From 109db2b0cce1b89c75e32f3705a1c5975391b3c5 Mon Sep 17 00:00:00 2001 From: gaillaro Date: Sat, 1 May 2004 11:52:08 +0000 Subject: Ajout de ovision. --- 2004/i/nono/src/ovision/adjust.cc | 237 ++++++++++ 2004/i/nono/src/ovision/adjust.h | 45 ++ 2004/i/nono/src/ovision/comm.cc | 350 ++++++++++++++ 2004/i/nono/src/ovision/comm.h | 64 +++ 2004/i/nono/src/ovision/config.cc | 347 ++++++++++++++ 2004/i/nono/src/ovision/config.h | 138 ++++++ 2004/i/nono/src/ovision/group.cc | 235 ++++++++++ 2004/i/nono/src/ovision/group.h | 87 ++++ 2004/i/nono/src/ovision/img.cc | 83 ++++ 2004/i/nono/src/ovision/img.h | 61 +++ 2004/i/nono/src/ovision/imgFile.cc | 137 ++++++ 2004/i/nono/src/ovision/imgFile.h | 44 ++ 2004/i/nono/src/ovision/map.cc | 179 +++++++ 2004/i/nono/src/ovision/map.h | 107 +++++ 2004/i/nono/src/ovision/modele.h | 31 ++ 2004/i/nono/src/ovision/segmNN.cc | 260 +++++++++++ 2004/i/nono/src/ovision/segmNN.h | 75 +++ 2004/i/nono/src/ovision/segmTh.cc | 126 +++++ 2004/i/nono/src/ovision/segmTh.h | 37 ++ 2004/i/nono/src/ovision/space.cc | 341 ++++++++++++++ 2004/i/nono/src/ovision/space.h | 121 +++++ 2004/i/nono/src/ovision/test.cc | 32 ++ 2004/i/nono/src/ovision/testdist.cc | 14 + 2004/i/nono/src/ovision/testimg.cc | 65 +++ 2004/i/nono/src/ovision/testmap.cc | 29 ++ 2004/i/nono/src/ovision/testsegm.cc | 18 + 2004/i/nono/src/ovision/testui.cc | 46 ++ 2004/i/nono/src/ovision/testui.h | 4 + 2004/i/nono/src/ovision/ui.cc | 898 ++++++++++++++++++++++++++++++++++++ 2004/i/nono/src/ovision/ui.h | 92 ++++ 30 files changed, 4303 insertions(+) create mode 100644 2004/i/nono/src/ovision/adjust.cc create mode 100644 2004/i/nono/src/ovision/adjust.h create mode 100644 2004/i/nono/src/ovision/comm.cc create mode 100644 2004/i/nono/src/ovision/comm.h create mode 100644 2004/i/nono/src/ovision/config.cc create mode 100644 2004/i/nono/src/ovision/config.h create mode 100644 2004/i/nono/src/ovision/group.cc create mode 100644 2004/i/nono/src/ovision/group.h create mode 100644 2004/i/nono/src/ovision/img.cc create mode 100644 2004/i/nono/src/ovision/img.h create mode 100644 2004/i/nono/src/ovision/imgFile.cc create mode 100644 2004/i/nono/src/ovision/imgFile.h create mode 100644 2004/i/nono/src/ovision/map.cc create mode 100644 2004/i/nono/src/ovision/map.h create mode 100644 2004/i/nono/src/ovision/modele.h create mode 100644 2004/i/nono/src/ovision/segmNN.cc create mode 100644 2004/i/nono/src/ovision/segmNN.h create mode 100644 2004/i/nono/src/ovision/segmTh.cc create mode 100644 2004/i/nono/src/ovision/segmTh.h create mode 100644 2004/i/nono/src/ovision/space.cc create mode 100644 2004/i/nono/src/ovision/space.h create mode 100644 2004/i/nono/src/ovision/test.cc create mode 100644 2004/i/nono/src/ovision/testdist.cc create mode 100644 2004/i/nono/src/ovision/testimg.cc create mode 100644 2004/i/nono/src/ovision/testmap.cc create mode 100644 2004/i/nono/src/ovision/testsegm.cc create mode 100644 2004/i/nono/src/ovision/testui.cc create mode 100644 2004/i/nono/src/ovision/testui.h create mode 100644 2004/i/nono/src/ovision/ui.cc create mode 100644 2004/i/nono/src/ovision/ui.h (limited to '2004/i/nono/src') diff --git a/2004/i/nono/src/ovision/adjust.cc b/2004/i/nono/src/ovision/adjust.cc new file mode 100644 index 0000000..5bc6572 --- /dev/null +++ b/2004/i/nono/src/ovision/adjust.cc @@ -0,0 +1,237 @@ +#include // Header File For The GLUT Library +#include // Header File For The OpenGL32 Library +#include // Header File For The GLu32 Library +#include + +#include +#include +#include + +#include "adjust.h" +#include "comm.h" + +using namespace std; + +int window; +Comm *comm; + + +/// Sortie du programme +void +Leave (int numSignal) +{ + exit(0); +} + + +/// Sortie du programme anormal +void +TooLate(int numSignal) +{ + // Affichage d'un message d'erreur + cerr << "TooLate : Temps d'attente FIFO depasse\n"; + Leave(-1); +} + + +/// Lecture du fifo et execution de la commande +void +ExecuteUiCmds(int numSignal) +{ + // Reassignement du signal handler + signal(SIGUSR1, ExecuteUiCmds); + + char buffer[50]; + + // On test si le fifo a ete initialiser + if (numSignal == SIGUSR2) + { + // Permet l'envoie du message d'initialisation + strcpy(buffer, "i\n"); + } + else + { + // Timer + signal(ALARM, TooLate); + alarm(5); + + // Lecture du FIFO + if (!read (comm->fifo, buffer, 50)) + { + cerr << "ReadUicmds : Error FIFO is empty" << endl; + return; + } + + alarm(0); + } + + // Parse de la commande recue + comm->ExecuteUiCmds(buffer); + + // Envoyer un signal de réponse à UI + kill(comm->uiPid, SIGUSR1); +} + + +/// Chargement d'une texture a partir de donnees RGB +unsigned int +LoadImage(int width, int height, unsigned char *data, unsigned int lastTex) +{ + GLuint tex; + + if (glIsTexture(lastTex)) glDeleteTextures(1, &lastTex); + + + // Mode de chargement des donnees + glPixelStorei (GL_UNPACK_ALIGNMENT, 1); + + // Creer une id pour stocker l'image + glGenTextures(1, &tex); + glBindTexture(GL_TEXTURE_2D, tex); + + // Stocke l'image + //glTexImage2D(GL_TEXTURE_2D, 0, 3, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data); + gluBuild2DMipmaps(GL_TEXTURE_2D, 3, width, height, GL_RGB, GL_UNSIGNED_BYTE, data); + + // Config des parametres + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); + + // Retourne l'id de l'image + return tex; +} + + +/// Initialisation des fonctions OpenGL +void +InitGL(int width, int height) +{ + // Initialisation du mode d'affichage + glClearColor(0.0f, 0.0f, 0.0f, 0.0f); + + // Mode de chargement des donnees + glPixelStorei (GL_UNPACK_ALIGNMENT, 1); + glShadeModel(GL_FLAT); + glEnable(GL_TEXTURE_2D); + + + // Remise a zero de la matrice de projection + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + + // Plan de projection en 2D + glOrtho(0.0, WIDTH, 0.0, HEIGHT, -1.0, 1.0); + glMatrixMode(GL_MODELVIEW); +} + + + +/// Redimenssionement d'une fenetre +void +ReSizeGLScene(int width, int height) +{ + // Evite div par 0 + if (height==0) height=1; + + // Initialise le point de vue + glViewport(0, 0, width, height); + glMatrixMode(GL_PROJECTION); + + // Remise a zero et mode 2D + glLoadIdentity(); + glOrtho(0.0, WIDTH, 0.0, HEIGHT, -1.0, 1.0); + glMatrixMode(GL_MODELVIEW); +} + + +/// Affiche une image +/// @param texId numero de la texture a afficher +void +DrawImage(GLuint texId) +{ + int wMin, wMax; + int hMin, hMax; + + // Selection de l'image + glBindTexture(GL_TEXTURE_2D, comm->tex[texId]); + + // Calcul des coordonnees de l'image + wMin = BORDER+(texId%3)*(352+BORDER); + wMax = 352+BORDER+(texId%3)*(352+BORDER); + hMin = HEIGHT-288-BORDER-(int)(texId/3)*(288+BORDER); + hMax = HEIGHT-BORDER-(int)(texId/3)*(288+BORDER); + + // Dessine un carre contenant l'image + glBegin(GL_QUADS); + glNormal3f( 0.0f, 0.0f, 1.0f); + glColor3f(1.0f,1.0f,1.0f); + glTexCoord2f(0.0f, 0.0f); glVertex3f(wMax, hMax, -1.0f); + glTexCoord2f(1.0f, 0.0f); glVertex3f(wMin, hMax, -1.0f); + glTexCoord2f(1.0f, 1.0f); glVertex3f(wMin, hMin, -1.0f); + glTexCoord2f(0.0f, 1.0f); glVertex3f(wMax, hMin, -1.0f); + glEnd(); +} + + +/// Dessine les images a l'ecran +void +DrawGLScene() +{ + // Efface le buffer + glClear(GL_COLOR_BUFFER_BIT); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + + // Affiche toutes les images + for (int i=0; i +#include +#include +using namespace std; + +#include "comm.h" +#include "adjust.h" + + +/// Constructeur +/// @param *filename nom de l'image a utiliser +Comm::Comm(char *filename) +{ + // Initialisation de IL + ilInit(); + + // Ecriture du PID dans un fichier + long pid = getpid(); + FILE *file = fopen("adjust.PID", "w+"); + if (!file) + { + cerr << "InitComm : Error during file opening" << endl; + return; + } + fprintf(file, "%li\n", pid); + fclose(file); + + // Creation de config + config = new Config("vision.conf"); + + // Ouverture de l'image pilote et stockage + img.ReadRaw(filename); + tex[0] = LoadImage(img.width, img.height, img.tabData, tex[0]); + + // Conversion en RGB et stockage + img.RGBtoYUV(); + tex[3] = LoadImage(img.width, img.height, img.tabData, tex[3]); + + // NN configure en RGB ou YUV ? + if (config->colorMode == RGB) img.ReadRaw(filename); + + // Allocation memoire pour les images + for (int i=0; i<2; i++) + data[i] = new unsigned char[img.nbPixels*3]; + + // Initialisation de la segmentation + segm = new SegmNN(&img, config); + segm->BuildNN(config->nn_NbCouleurs, LOAD_FROM_FILE); + + group = new Group(&img, segm); + SegmAndGroup(); + + // Affichage de l'image pilote en RGB et YUV + tex[1] = LoadImage(img.width, img.height, data[0], tex[1]); + tex[4] = LoadImage(img.width, img.height, data[1], tex[4]); +} + + +/// Destructeur +Comm::~Comm() +{ + // Fermeture de DevIL + ilShutDown(); + + // Liberation de la memoire + delete config; + delete segm; + delete group; + delete [] data; + + close(fifo); +} + + +/// Segmente et group les couleurs +void +Comm::SegmAndGroup() +{ + segm->Segm(); + + // Creation de l'image segmentee + img.DoImg(segm->tabSegm , data[0]); + + // Creation des groupes + if (group) delete group; + group = new Group(&img, segm); + group->JumpPoints(config->groupColor); + group->TabOut(); + + img.DoImg(group->tabOut, data[1]); + + tex[2] = LoadImage(img.width, img.height, data[0], tex[2]); + tex[5] = LoadImage(img.width, img.height, data[1], tex[5]); +} + + +/// Synchronisation des poids locaux et de ceux du programme ui +void +Comm::SendNodes() +{ + char buf[10]; + for (int i=0; i < config->nn_NbCouleurs*3; i++) + { + sprintf(buf, "%u\n", segm->node[i]); + write(fifo, buf, 10); + } +} + +/// Execute une commande venant de l'interface ui +/// @param *buffer ligne de commande a analyser +void +Comm::ExecuteUiCmds(char *buffer) +{ + const int NBARG = 20; + + // Division du string + char *cut[NBARG]={NULL}; + cut[0] = strtok(buffer, " \t\n"); + int i = 0; + while ((cut[i] != NULL) && (i<(NBARG-1))) + { + i++; + cut[i] = strtok( NULL, " \t\n"); + } + + // Detection de la commande recue + switch (buffer[0]) + { + case 'i': // ouverture du fifo + cout << "Initialisation du fifo\n"; + // Ouverture du fifo + fifo = open("uicmds", O_RDWR); + if (!fifo) { + cerr << "InitComm : Error during opening FIFO" << endl; + exit(1); + } + + // On choppe le pid du prog ui situé dans le fichier uiPid.PID + FILE *file; + file = fopen("ui.PID", "r"); + if (!file) + { + cerr << "Comm::ExecuteUiCmds : PID file not found" << endl; + exit(1); + } + char buf[10]; + fgets(buf, 10, file); + uiPid = atol(buf); + fclose(file); + break; + + case 'c': // changement de couleur + int numColor; + numColor = atoi(cut[NUMCOLORTOCHANGE]); + + // Changement des valeurs sur les poids du NN + for (int i=0; i<3; i++) + segm->node[numColor*3+i] = atoi(cut[COLORTOCHANGE+i]); + + // On segmente l'image puis on la stocke + SegmAndGroup(); + + printf("Couleur %i changé aux valeurs : %u %u %u\n", numColor, segm->node[numColor*3], segm->node[numColor*3+1], segm->node[numColor*3+2]); + break; + + case 'm': // mélanger couleurs + int nbColorToMerge, numIndexColor; + + // Si on recoit une commande de remise a zero de l'index + if (atoi(cut[NBCOLORTOMERGE]) == -1) + { + for (int i=0; inn_NbCouleurs; i++) + segm->index[i] = i; + } + // Sinon on mix les couleurs + else + { + nbColorToMerge = atoi(cut[NBCOLORTOMERGE]); + numIndexColor = segm->index[atoi(cut[NUMCOLORTOMERGE])]; + + // On inscrit les changements dans l'index + for (int i=1; iindex[atoi(cut[NUMCOLORTOMERGE+i])] = numIndexColor; + } + + // On segmente l'image puis on la stocke + SegmAndGroup(); + + cout << nbColorToMerge << " colors merged to " << numIndexColor << endl; + break; + + + case 's': // isole une couleur + int numColorToShow; + numColorToShow = atoi(cut[NUMCOLORTOSHOW]); + + // Cas ou toutes les couleurs doivent etre affiche + if (numColorToShow == -1) + SegmAndGroup(); + + // Afficher seulement une couleur + else + { + segm->Segm(numColorToShow); + + // Creation de l'image segmentee + img.DoImg(segm->tabSegm , data[0]); + + // Creation des groupes + group = new Group(&img, segm); + group->JumpPoints(config->groupColor); + group->TabOut(); + + img.DoImg(group->tabOut, data[1]); + + tex[2] = LoadImage(img.width, img.height, data[0], tex[2]); + tex[5] = LoadImage(img.width, img.height, data[1], tex[5]); + } + break; + + + case 'd': // supprimer couleur + int numColorToDel; + numColorToDel = atoi(cut[NUMCOLORTODEL]); + + // Decalage de toutes les couleurs pour supprimer une couleur + unsigned char *pCur; + pCur = &config->node[numColorToDel*3]; + for(int i=numColorToDel*3; inn_NbCouleurs*3; i++) + { + *(pCur) = *(pCur+3); + pCur++; + } + + config->nn_NbCouleurs--; + + // On refait le NN vu qu'il y a une couleur de moins + segm->BuildNN(config->nn_NbCouleurs, LOAD_FROM_FILE); + + segm->ShowNodes(); + + // On segmente l'image puis on la stocke + SegmAndGroup(); + break; + + case 'r': // Reload l'image + int nbNNOutput; + nbNNOutput = atoi(cut[NBNNOUTPUT]); + + // Reattribution du nombre de sorties d'origine + if (nbNNOutput != -1) config->nn_NbCouleurs = nbNNOutput; + + // Recharge du fichier des poids + config->LoadNNFile(); + + // On refait le NN vu qu'il y a une couleur de moins + segm->BuildNN(config->nn_NbCouleurs, LOAD_FROM_FILE); + + // On segmente l'image puis on la stocke + SegmAndGroup(); + + // Si l'image a ete sauve on change l'image pivot + if (nbNNOutput == -1) + { + tex[1] = LoadImage(img.width, img.height, data[0], tex[1]); + tex[4] = LoadImage(img.width, img.height, data[1], tex[4]); + } + break; + + case 'g': // Selection du groupe + config->groupColor = atoi(cut[NUMGROUP]); + + // On segmente l'image puis on la stocke + SegmAndGroup(); + break; + + case 'n': // Image suivante + char *filename; + filename = cut[FILENAME]; + cout << filename << endl; + + // Ouverture de l'image pilote et stockage + img.ReadRaw(filename); + + // Allocation memoire pour les images + for (int i=0; i<2; i++) + { + if (data[i]) delete data[i]; + data[i] = new unsigned char[img.nbPixels*3]; + } + + tex[0] = LoadImage(img.width, img.height, img.tabData, tex[0]); + + // Conversion en YUV et stockage + img.RGBtoYUV(); + tex[3] = LoadImage(img.width, img.height, img.tabData, tex[3]); + + // NN configure en RGB ou YUV ? + if (!config->colorMode == RGB) img.ReadRaw(filename); + + SegmAndGroup(); + + // Affichage de l'image pilote en RGB et YUV + tex[1] = LoadImage(img.width, img.height, data[0], tex[1]); + tex[4] = LoadImage(img.width, img.height, data[1], tex[4]); + break; + + case 't': // Entraine le reseau + segm->TrainNN(); + + // On segmente l'image puis on la stocke + SegmAndGroup(); + + // Synchronisation des poids avec ui + SendNodes(); + + break; + + case 'p': // Regenere les poids du reseau + int nbColor; + nbColor = atoi(cut[NBCOLORNN]); + + // Assignation du nombre de couleurs a isoler par le reseau + config->nn_NbCouleurs = nbColor; + + // Genere aleatoire les poids + segm->BuildNN(config->nn_NbCouleurs, GENERATE); + + // Apprentissage + segm->TrainNN(); + + // On segmente l'image puis on la stocke + SegmAndGroup(); + + // Synchronisation des poids avec ui + SendNodes(); + + break; + } + + DrawGLScene(); +} + diff --git a/2004/i/nono/src/ovision/comm.h b/2004/i/nono/src/ovision/comm.h new file mode 100644 index 0000000..e97e580 --- /dev/null +++ b/2004/i/nono/src/ovision/comm.h @@ -0,0 +1,64 @@ +#ifndef comm_h +#define comm_h +// comm.h - classe Comm +// nono - Programme du robot Efrei Robotique I1-I2 2004 +// Copyright (C) 2004 Olivier Gaillard + + + +#include "adjust.h" + +#include "img.h" +#include "segmNN.h" +#include "config.h" +#include "group.h" + + + +/// Interprete les commandes envoyes par l'interface UI et les executent +class Comm { + + public: + /// tableau des numeros de textures utilises par openGL + unsigned int tex[NBIMG]; + + /// tableau de donnees RGB stockant les images + unsigned char* data[2]; + + /// classe image + ImgFile img; + + /// classe config + Config *config; + + /// classe segmentation + SegmNN *segm; + + /// classe group + Group *group; + + /// id utilise pour l'ouverture du fifo + int fifo; + + /// PID du programme ui + long uiPid; + + /// Constructeur + Comm (char *filename); + + /// Destructeur + ~Comm (void); + + /// Execute une commande venant de l'interface + void ExecuteUiCmds(char *buffer); + + protected: + /// Segmentation et groupement des couleurs + void SegmAndGroup(); + + /// Synchronisation des poids locaux et de ceux du programme ui + void SendNodes(); +}; + + +#endif // comm_h diff --git a/2004/i/nono/src/ovision/config.cc b/2004/i/nono/src/ovision/config.cc new file mode 100644 index 0000000..03ca5f7 --- /dev/null +++ b/2004/i/nono/src/ovision/config.cc @@ -0,0 +1,347 @@ +// config.cc - Classe Config +// nono - Programme du robot Efrei Robotique I1-I2 2004 +// Copyright (C) 2004 Olivier Gaillard + +/// @file config.cc Charge le fichier config et distribue les variables + +#include "config.h" +#include +#include +#include +using namespace std; + + +/// Parse une ligne du fichier de config +/// @param *var nom de la variable a fixer +/// @param *arg valeur de la variable +void Config::Parse(char *var, char *arg) { + + char argu[20]; + + if (!arg) cerr << "Config::Parse : Error during config file parsing" << endl; + + strcpy(argu, arg); + + // Verifie si l'argument est un nombre ou un nom de fichier + if (((argu[0]>'9') || (argu[0] < '0')) + && strcmp(var, "Source") && strcmp(var, "imgPath")) { + FILE *file; + + file=fopen(arg, "r"); + if (!file) cerr << "Config::Parse : Bad pathfile for " << arg << endl; + + fgets(argu, 20,file); + + fclose(file); + } + + // Affecte la valeur de argu a la variable var + if (!strcmp(var, "Hauteur_Image")) height = atoi(argu); + else if(!strcmp(var,"Largeur_Image")) width = atoi(argu); + else if(!strcmp(var,"NN_Step_Learning")) nn_sl = atof(argu); + else if(!strcmp(var,"NN_Neighborhood_Learning")) nn_nl = atof(argu); + else if(!strcmp(var,"NN_Number_Iteration_Learning")) nn_nil = atol(argu); + else if(!strcmp(var,"NN_Nombre_Couleurs")) nn_NbCouleurs = atoi(argu); + else if(!strcmp(var,"NN_Influence_Luminosite")) nn_influ_lum = atof(argu); + else if(!strcmp(var,"imgPath")) strcpy(imgPath, argu); + else if(!strcmp(var,"NN_Lazy_Threshold")) nn_lazy_threshold = atoi(argu); + else if(!strcmp(var,"Map_Error")) map_error = atoi(argu); + else if(!strcmp(var,"Map_Error_Part")) map_error_part = atoi(argu); + else if(!strcmp(var,"Angle_Ball")) angle_ball_weight= atoi(argu); + else if(!strcmp(var,"Distance_Ball_Robot")) distance_ball_robot_weight = atoi(argu); + else if(!strcmp(var,"Distance_Ball_Goal")) distance_ball_goal_weight = atoi(argu); + else if(!strcmp(var,"Ball_Density")) ball_density_weight = atoi(argu); + else if(!strcmp(var,"Ennemy_Presence")) ennemy_presence_weight = atoi(argu); + else if(!strcmp(var,"Ball_Precision")) ball_precision_weight = atoi(argu); + else if(!strcmp(var,"Skepticism")) skepticism_weight = atoi(argu); + else if(!strcmp(var,"Skepticism_Max")) skepticism_max = atoi(argu); + else if(!strcmp(var,"Source")) + { + if (!strcmp(argu, "file")) source = SOURCE_FILE; + else if (!strcmp(argu, "usbcam")) source = SOURCE_USB_CAM; + else if (!strcmp(argu, "cam")) source = SOURCE_CAM; + } + +} + + +/// Constructor +/// @param *filename nom du fichier de config +Config::Config(char *filename) { + + const int NBARG = 3; + char *cut[NBARG] = {NULL}; + FILE *file; + char ligne[50]; + int i; + + // Ouverture du fichier de conf + file = fopen(filename, "r"); + if (!file) cerr << "Config::Config : Error during config file opening" << endl; + else cout << "Lecture du ficher de configuration" << endl; + + + // Parcours des lignes et analyse + while(fgets(ligne, 50, file)) { + if (ligne[0] == '#') continue; + + // Division du string + cut[0] = strtok(ligne, " \n"); + if (!cut[0]) continue; + i=0; + while ((cut[i] != NULL) && (i<(NBARG-1))) { + i++; + cut[i] = strtok( NULL, " \t\n"); + + } + + Parse(cut[0], cut[2]); + } + + colorMode = 0; + color = NULL; + node = NULL; + index = NULL; + LoadThFile(); + LoadNNFile(); +} + + +/// Chargement des poids d'un reseau de neurones +/// @param *filePath nom du fichier de poids a charger +void Config::LoadNNFile(char *filePath) { + const int NBARG = 4; + char *cut[NBARG] = {NULL}; + FILE *file; + char ligne[50]; + int i; + unsigned char *pNode; + + // Ouverture du fichier de conf + file = fopen(filePath, "r"); + if (!file) { + cerr << "Config::LoadNNFile : Error during poids file opening" << endl; + index = new int[nn_NbCouleurs]; + for (int i=0; i +#include +#include +using namespace std; + +#define BALL 1 +#define GOAL 2 + + +/// Constructeur + +/// @param *img classe image +/// @param *segm classe segmNN +Group::Group(Img *img, SegmNN *segm) { + // Sauvegarde des pointeurs + Group::img = img; + Group::segm = segm; + + width = img->width; + height = img->height; + + tabOut = NULL; + zoneListBall = NULL; + zoneListGoal = NULL; +} + + +/// Destructeur +Group::~Group() { + ZONE *pCur = zoneListBall; + ZONE *pPrev; + + while (pCur) + { + pPrev = pCur; + pCur = pCur->next; + + free(pPrev); + } + + pCur = zoneListGoal; + while (pCur) + { + pPrev = pCur; + pCur = pCur->next; + + free(pPrev); + } +} + + +/// Cherche l'objet complet a partir d'un pixel donne + +/// @param numColor numero de la couleur a chercher +/// @param x,y coordonnees de depart pour la recherche +void Group::Plague(int type, unsigned char numColor, int x, int y) { + unsigned int xmax = x; + unsigned int xmin = x; + unsigned int ymax = y; + unsigned int ymin = y; + + // TODO ajouter une inertie ? + + // Parcours de l'objet trouve de haut en bas + while ((xmax < width-1)&& (tabSegm[(++xmax)+y*width] == numColor)) {} + while ((xmin > 0) && (tabSegm[(--xmin)+y*width] == numColor)) {} + while ((ymax < height-1) && (tabSegm[x+(++ymax)*width] == numColor)) {} + while ((ymin > 0) && (tabSegm[x+(--ymin)*width] == numColor)) {} + + // Verification la validite des entrees +/* if ((xmin < 0) || (xmin > width)) + xmin = 0; + if ((xmax > img->width) || (xmax < 0)) + xmax = img->width; + if ((ymin < 0) || (ymin > height)) + ymin = 0; + if ((ymax > img->height) || (ymax < 0)) + ymax = img->height; +*/ + // Calcul du centre de l'image + int centerx, centery; + centerx = (xmax+xmin)/2; + centery = (ymax+ymin)/2; + + ZONE *pCur; + + if (type == BALL) + pCur = zoneListBall; + else if (type == GOAL) + { + if (!((pLast->ymin <= 0) && (pLast->ymax >= config->width))) + return; + pCur = zoneListGoal; + } + + ZONE *pLast=NULL; + while (pCur) { + // si on a deja ce groupe on actualise les donnees du groupe + if ((numColor == pCur->idColor) && (abs(pCur->centerx - centerx) <= DELTA) && (abs(pCur->centery - centery) <= DELTA)) { + if (xmin < pCur->xmin) pCur->xmin = xmin; + if (xmax > pCur->xmax) pCur->xmax = xmax; + if (ymin < pCur->ymin) pCur->ymin = ymin; + if (ymax > pCur->ymax) pCur->ymax = ymax; + + pCur->centerx = (pCur->xmax+pCur->xmin)/2; + pCur->centery = (pCur->ymax+pCur->ymin)/2; + + return; + } + + pLast = pCur; + pCur = pCur->next; + } + + + // Si il n'est pas presente on l'ajoute + if (!pCur) { + if (!pLast) + { + if (type == BALL) + { + zoneListBall = new ZONE; + pLast = zoneListBall; + } + else if (type == GOAL) + { + zoneListGoal = new ZONE; + pLast = zoneListGoal; + } + } + else + { + pLast->next = new ZONE; + pLast = pLast->next; + } + + pLast->xmin = xmin; + pLast->xmax = xmax; + pLast->ymin = ymin; + pLast->ymax = ymax; + + pLast->centerx = centerx; + pLast->centery = centery; + pLast->idColor = numColor; + + // test si la balle est vu partiellement ou completement + if ((pLast->xmin <= 0) || (pLast->ymin <= 0) || (pLast->xmax >= config->width) || (pLast->ymax >= config->height)) + pLast->partial = 1; + else pLast->partial = 0; + + + + + pLast->next = NULL; + } +} + + +/// Affiche les zones trouvees +void Group::ShowZones() { + + ZONE *pCur = zoneListBall; + cout << "Groupes balles:" << endl; + while(pCur) { + printf("%u %i %i %i %i\n", pCur->idColor, pCur->xmin, pCur->xmax, pCur->ymin, pCur->ymax); + pCur = pCur->next; + } + + ZONE *pCur = zoneListGoal; + cout << "Groupes balles:" << endl; + while(pCur) { + printf("%u %i %i %i %i\n", pCur->idColor, pCur->xmin, pCur->xmax, pCur->ymin, pCur->ymax); + pCur = pCur->next; + } +} + + +/// Selectionne les points a tester dans l'image +/// @param numColor numero de la couleur a trouver +void Group::JumpPoints(unsigned char numColor) { + + tabSegm = segm->tabSegm; + + // Initialisation de la couleur a chercher + numColor = segm->index[numColor]; + + // Parcours d'une partie des pixels de l'image + for (unsigned int x=0; xnbPixels]; + + // On initialise le tableau pour une image noire + for (unsigned int i=0; inbPixels; i++) + tabOut[i] = 0; + + // Parcours de la liste des zones trouvees + while (pCur) { + // Remplissage de la zone avec une couleur + for(unsigned int i=pCur->xmin; ixmax; i++) + for (unsigned int j=pCur->ymin; jymax; j++) + tabOut[j*img->width+i] = pCur->idColor+1; + + pCur = pCur->next; + } +} + + diff --git a/2004/i/nono/src/ovision/group.h b/2004/i/nono/src/ovision/group.h new file mode 100644 index 0000000..f154bd0 --- /dev/null +++ b/2004/i/nono/src/ovision/group.h @@ -0,0 +1,87 @@ +#ifndef group_h +#define group_h +// group.h - classe Group +// nono - Programme du robot Efrei Robotique I1-I2 2004 +// Copyright (C) 2004 Olivier Gaillard + +#include "img.h" +#include "segmNN.h" +#include "segmTh.h" + +// TODO delta devrait diminuer avec la profondeur +#define DELTA 20 // taille du jumppoint + + +/// Liste chainee des zones trouvees par la classe group +struct ZONE { + /// bornes de la zone pour x + unsigned int xmin, xmax; + + /// bornes de la zone pour y + unsigned int ymin, ymax; + + /// centre de la zone trouvee + int centerx, centery; + + /// couleur de la zone + unsigned char idColor; + + /// l'objet est vue partiellement ou completement + bool partial; + + /// maillon suivant + ZONE *next; +}; + + +/// Cree une liste chainee de zones correspondant aux balles +class Group { + + // classe segmentation + SegmNN *segm; + + // classe image + Img *img; + + // largeur de l'image a analyser + unsigned int width; + + // longueur de l'image a analyser + unsigned int height; + + public: + // pointeur vers l'image segmentee + unsigned char *tabSegm; + + // pointeur vers l'image RGB pour affichage + unsigned char *tabOut; + + // liste chainee pour sauver les zones des balles + ZONE *zoneListBall; + + // liste chainee pour sauver les zones des poteaux + ZONE *zoneListGoal; + + /// Constructeur + Group (Img *img, SegmNN *segm); + + /// Destructeur + ~Group (void); + + /// Selectionne les points a tester + void JumpPoints(unsigned char numColor); + + /// Creation du tableau de RGB pour faire une image + void TabOut(); + + /// Affiche les zones trouvees + void ShowZones(); + + protected: + /// Cherche l'objet complet a partir d'un pixel + void Plague(int type, unsigned char numColor, int x, int y); + +}; + + +#endif // group_h diff --git a/2004/i/nono/src/ovision/img.cc b/2004/i/nono/src/ovision/img.cc new file mode 100644 index 0000000..6288404 --- /dev/null +++ b/2004/i/nono/src/ovision/img.cc @@ -0,0 +1,83 @@ +// img.cc - Classe Image +// nono - Programme du robot Efrei Robotique I1-I2 2004 +// Copyright (C) 2004 Olivier Gaillard + +/// @file img.cc Chargement des images, conversion en YUV, HSI, detection des contours, transformation d'une image segmentee en RGB, ecriture de l'image sur le disque + +#include "img.h" +#include +#include +#include +using namespace std; +/// Renvoie le minimum entre 2 nombres +inline unsigned char min(unsigned char a, unsigned char b) { + if (a +#include +#include +using namespace std; + +/// tableau de couleur utlisation pour la creation de l'image segmentee +unsigned char tabCol[9][3] = + {{0, 0, 0}, {255, 255, 255}, {0, 0, 255}, + {0,255,0}, {255, 0, 0}, {0, 150, 60}, + {150,60,0}, {0, 150, 60}, {20, 50, 120}}; + + + +/// Constructor ImgFile +ImgFile::ImgFile(void) +{ + // Initialisation de DevIL. + ilInit(); +} + + +/// Destructor ImgFile +ImgFile::~ImgFile(void) +{ + /// Fermeture de DevIl + ilShutDown(); +} + + +/// Ouvre un fichier +int ImgFile::ReadRaw (char *filename) +{ + ILuint ImgFileId; + + // Supprime l'id d'une image dans DevIL + if (tabData) { + ilDeleteImages(1, &ImgFileId); + } + + // Generation de l'id + ilGenImages(1, &ImgFileId); + + // Selection de l'image courante + ilBindImage(ImgFileId); + + // Chargement de l'image avec DevIL + if (!ilLoadImage(filename)) { + cerr << "Could not open file...exiting." << endl; + return 0; + } + + // Caracteristiques d'une image + height = ilGetInteger(IL_IMAGE_HEIGHT); + width = ilGetInteger(IL_IMAGE_WIDTH); + nbPixels = height*width; + + cout << "Width: " << width << " Height: " << height + << " Depth: " << ilGetInteger(IL_IMAGE_DEPTH) << " Bpp: " << ilGetInteger(IL_IMAGE_BITS_PER_PIXEL) << endl; + + // Recuperation des donnees RGB + if (tabData) delete [] tabData; + tabData = new unsigned char[nbPixels*3]; + ilCopyPixels(0,0,0,width,height,1,IL_RGB,IL_UNSIGNED_BYTE,(ILvoid*)tabData); + + return 1; +} + +/// Cree un tableau en RGB pour l'affichage a partir d'une image segmentee + +/// @param *tabIn pointeur vers un tableau de donnees segmentees +/// @param *tabOut pointeur vers un tableau de donnees RGB +void ImgFile::DoImg(unsigned char *tabIn, unsigned char *tabOut) { + if (tabIn) { + // Change les couleurs segmentees en valeurs RGB pour l'affichage + for (int i=0; i<(int)(nbPixels);i++) { + tabOut[i*3] = tabCol[tabIn[i]][0]; + tabOut[i*3+1] = tabCol[tabIn[i]][1]; + tabOut[i*3+2] = tabCol[tabIn[i]][2]; + } + } + else { + // Si la table donnee est vide on renvoie des couleurs noires + for (int i=0; i<(int)(nbPixels);i++) { + tabOut[i*3] = 0; + tabOut[i*3+1] = 0; + tabOut[i*3+2] = 0; + } + } +} + + +/// Cree une image et l'ecrit sur le disque + +/// @param *filename nom du fichier cree +/// @param *tabSegm tableau de donnees segmentees a transformer en image +void ImgFile::WriteSegm (char *filename, unsigned char *tabSegm) { + + ILuint ImgFileIdSegm; + unsigned char *tabOut; + + // Verification du pointeur passe en argument + if (!tabSegm) { + cerr << "ImgFile::Write : Rien a ecrire dans le fichier\n"; + return; + } + + // Preparation des donnees + tabOut = new unsigned char[nbPixels*3]; + + DoImg(tabSegm, tabOut); + + // Generation de l'id + ilGenImages(1, &ImgFileIdSegm); + + // Selection de l'image courante + ilBindImage(ImgFileIdSegm); + + // Creation de l'image test + ilTexImage(width, height*2, 1, 3, IL_RGB, IL_UNSIGNED_BYTE, NULL); + ilSetPixels(0,height,0,width,height,1,IL_RGB, IL_UNSIGNED_BYTE, (ILvoid*)tabOut); + ilSetPixels(0,0,0,width,height,1,IL_RGB, IL_UNSIGNED_BYTE, (ILvoid*)tabData); + iluRotate(180); + + // Sauvegarde de l'image + ilEnable(IL_FILE_OVERWRITE); + ilSaveImage(filename); + + // Libere la memoire + delete [] tabOut; +} diff --git a/2004/i/nono/src/ovision/imgFile.h b/2004/i/nono/src/ovision/imgFile.h new file mode 100644 index 0000000..d8ff33e --- /dev/null +++ b/2004/i/nono/src/ovision/imgFile.h @@ -0,0 +1,44 @@ +#ifndef imgFile_h +#define imgFile_h +// imgFile.h - classe Image +// nono - Programme du robot Efrei Robotique I1-I2 2004 +// Copyright (C) 2004 Olivier Gaillard + + +// Chargement des librairies DevIL +#include +#include + +#include "img.h" + +/// Chargement des images, conversion en YUV, HSI, detection des contours, +/// transformation d'une image segmentee en RGB, ecriture de l'image sur le disque +class ImgFile : public Img +{ + + public: + ImgFile(); + + /// Destructeur + virtual ~ImgFile (void); + + /// Lis une image en utilisant le peripherique adequate (fichier, cam usb, cam) + virtual int ReadRaw(char *sourcePath); + + /// Transformation d'un tableau de valeurs segmentees en RGB + void DoImg(unsigned char *tabIn, unsigned char *tabOut); + + /// Ecriture de l'image sur le disque + virtual void WriteSegm(char *filename, unsigned char *tabSegm); + + /// Ecriture de l'image sur le disque + virtual void WriteSegm(char *filename); + + + protected: +}; + + +inline void ImgFile::WriteSegm(char *filename) {WriteSegm(filename, tabSegm);} + +#endif // imgFile_h diff --git a/2004/i/nono/src/ovision/map.cc b/2004/i/nono/src/ovision/map.cc new file mode 100644 index 0000000..8787c6d --- /dev/null +++ b/2004/i/nono/src/ovision/map.cc @@ -0,0 +1,179 @@ +// map.cc - Classe Map +// nono - Programme du robot Efrei Robotique I1-I2 2004 +// Copyright (C) 2004 Olivier Gaillard + +/// @file map.cc Fourni la liste des balles presentes sur le terrain et permet le choix rapide et efficace de la prochaine balle a aller chercher + +#include "map.h" +#include +#include +#include +using namespace std; + + + +/// Constructeurs. +Map::Map (Config *config) +{ + lock = 0; + + Map::config = config; + + posGoal[0] = 105; + posGoal[1] = 0; +} + +/// Destructeur. +Map::~Map (void) +{ +} + +/// Ajoute une balle a la map +void +Map::AddBall(int *pos, ZONE *pZone) +{ + BALL ballTmp; + + ballTmp.position[0] = pos[0]; + ballTmp.position[1] = pos[1]; + + // definit la position de la balle + ballTmp.zone = pos[0]%300 + (pos[1]%300)*7; + + ballTmp.partial = pZone->partial; + ballTmp.skepticism = 0; + + // calcul du score partie + ballTmp.preScore = + config->distance_ball_goal_weight * Dist(pos, posGoal); + + ball.push_back(ballTmp); +} + +/// Supprime une balle de la map +void +Map::DelBall(list::iterator &iter) +{ + ball.erase(iter); +} + +/// Test si une balle trouvee correspond a une balle de la map +int +Map::TestSimilarBall(ZONE *pBall, list::iterator &iter) +{ + //TODO tester d'abord les zones et ensuite les pos + for(iter = ball.begin(); iter != ball.end(); iter++) + { + if (Dist(iter->position, pos) < (iter->partial || pBall->partial)?config->map_error_part:config->map_error) + return 1; + } + + return 0; +} + +/// Calcul de distance +int +Map::Dist(int *pos1, int *pos2) +{ + int x = pos2[0]-pos1[0]; + int y = pos2[1]-pos1[1]; + return (int)sqrt((double)(x * x + y * y)); +} + +/// Retourne si une balle est locke +int +Map::IsLock() +{ + return lock; +} + +/// Lock une balle pour savoir quel balle le robot suit +void +Map::SetLock(int value) +{ + lock = value; +} + +/// Met a jour la map avec une nouvelle liste de balle +void +Map::AddBallsToMap(Group *group) +{ + ZONE *pCur = group->zoneListBall; + int pos[2]; + + + while (pCur) + { + // TODO passer par la classe space + pos[0] = pCur->centerx; + pos[1] = pCur->centery; + + // Cherche si la balle est deja dans la liste + list::iterator iCur; + + + // Si la balle n'est pas dans la liste on l'ajoute + if (!TestSimilarBall(pCur, iCur)) + { + AddBall(pos, pCur); + } + // Si elle l'est on incremente son marqueur de viabilite + else + { + if (iCur->skepticism < config->skepticism_max) + iCur->skepticism++; + + } + pCur = pCur->next; + } + + // TODO decremente d'autre marqueur + + + // Detection de poteau ou de goal + pCur = group->zoneListGoal; + if (pCur) + {} +} + +/// Met a jour les scores +void +Map::UpdateMap() +{ + // On met a jour tous les scores + list::iterator iter; + for(iter = ball.begin(); iter != ball.end(); iter++) + { + // iter->score = preScore + // + config->distance_ball_robot_weight * distancerobot + // + config->angle_ball_weight * + // + config->ball_density_weight * + // + config->ennemy_presence_weight * + // + config->skepticism_weight * iter->skepticism + // + config->ball_precision_weight * + // + ... iter->partial; + + if ((iter->score > curBall->score) && (!IsLock())) curBall = iter; + } + + +} + + +/// Affiche les balles de la map +void +Map::ShowBalls() +{ + list::iterator iter; + int i=0; + cout << "balles:\n"; + + /// Parcours de la liste + for(iter = ball.begin(); iter != ball.end(); iter++) + { + /// Affichage des infos de la balle + cout << i << ": " << iter->position[0] << "\t" << iter->position[1] << endl; + i++; + } + cout << endl; +} diff --git a/2004/i/nono/src/ovision/map.h b/2004/i/nono/src/ovision/map.h new file mode 100644 index 0000000..7e507f1 --- /dev/null +++ b/2004/i/nono/src/ovision/map.h @@ -0,0 +1,107 @@ +#ifndef map_h +#define map_h +// map.h - classe Map +// nono - Programme du robot Efrei Robotique I1-I2 2004 +// Copyright (C) 2004 Olivier Gaillard + +#include +#include "group.h" +#include "config.h" + +#define LOCKED 1 +#define UNLOCKED 0 + + + +/// TODO calcul de plusieurs scores si on veut rapidite ou efficacite + + +/// Structure stockant les balles +struct BALL { + /// position de la balle + int position[2]; + + /// score balle pour le choix de la prochaine balle a aller chercher + int score; + + /// score precalcule sans distance pour eviter les calculs redondants + int preScore; + + // zone balle, facilite le calcul de la distance robot-balle + int zone; + + /// probabilite que la balle sot a la zone indique par la map + int skepticism; + + /// balle vu seulement partiellement par la camera + int partial; +}; + + +/// Classe Map +class Map +{ + /// Variables configurables + Config *config; + + /// position des goals + int posGoal[2]; + + /// Liste de balles trouvees + std::list ball; + + /// Balle ayant le plus haut score + std::list::iterator curBall; + + /// Stocke le numero de la balle locke + int lock; + + /// Ajoute une balle a la map + void AddBall(int *pos, ZONE *pZone); + + /// Supprime une balle de la map + void DelBall(std::list::iterator &iter); + + /// Test si une balle trouvà correspond a une balle de la map + int TestSimilarBall(ZONE *pBall , std::list::iterator &iter); + + /// Distance robot-balle + int Dist(int *pos1, int *pos2); + + + + public: + + /// Balle ayant la plus grand score + int goodBall; + + /// Zone ou est situe le robot + int zoneRobot; + + /// Constructeurs. + Map (Config *config); + + /// Destructeur. + ~Map (void); + + /// Retourne si une balle est locke + int IsLock(); + + /// Lock une balle pour savoir quel balle le robot suit + void SetLock(int value); + + /// Ajoute des balles a la liste + void AddBallsToMap(Group *group); + + /// Met a jour les scores des balles + void UpdateMap(); + + //Affiche les balles de la map + void ShowBalls(); + + + protected: +}; + + +#endif // map_h diff --git a/2004/i/nono/src/ovision/modele.h b/2004/i/nono/src/ovision/modele.h new file mode 100644 index 0000000..b07f522 --- /dev/null +++ b/2004/i/nono/src/ovision/modele.h @@ -0,0 +1,31 @@ +#ifndef config_h +#define config_h +// config.h - classe Config +// nono - Programme du robot Efrei Robotique I1-I2 2004 +// Copyright (C) 2004 Olivier Gaillard + + +#include +#include + +#define IMG_HEIGHT 352 +#define IMG_WIDTH 288 + + +class Config { + + + public: + // Constructeurs. + Config (void); + + + // Destructeur. + ~Config (void); + + + protected: +}; + + +#endif // config_h diff --git a/2004/i/nono/src/ovision/segmNN.cc b/2004/i/nono/src/ovision/segmNN.cc new file mode 100644 index 0000000..d765f80 --- /dev/null +++ b/2004/i/nono/src/ovision/segmNN.cc @@ -0,0 +1,260 @@ +// segmNN.cc - Classe Segmentation +// nono - Programme du robot Efrei Robotique I1-I2 2004 +// Copyright (C) 2004 Olivier Gaillard + +/// @file segmNN.cc Segmente l'image et cree un tableau contenant des valeurs segmentees, creation du reseau de neurones et apprentissage + +#include "segmNN.h" +#include +#include +#include +#include +using namespace std; + +/// Constructor SegmNN + +/// @param img classe img permettant d'acceder au donnees de l'image a traiter +/// @param config classe config permettant d'acceder aux variables de configuration +SegmNN::SegmNN(ImgFile *img, Config *config) { + // Sauvegarde les pointeurs + SegmNN::img = img; + SegmNN::config = config; + nbOutput = config->nn_NbCouleurs; + + node = NULL; + index = NULL; + tabSegm = NULL; +} + +/// Destructor SegmNN +SegmNN::~SegmNN() +{ +} + + +/// Affiche les poids du reseau de neurones (neural network : NN) +void SegmNN::ShowNodes() { + + // Affichage des poids du NN + cout << "Poids:"; + for(int i=0; inbNodeMax < nbOutput) { + cerr << "SegmNN::BuildNN : Nombre de nodes insuffisants dans le fichier poids\n"; + } + else { + // Charge les poids du NN et l'index des couleurs + node = config->node; + index = config->index; + } + return; + } + + //initialition de random + srand((unsigned)time(0)); + + // Initialisation des noeuds du NN + if (node) delete [] node; + node = new unsigned char[nbOutput*3]; + if (index) delete [] index; + index = new int[nbOutput]; + if (freq) delete [] freq; + freq = new unsigned int[nbOutput]; + + + for(int i=0; i 220) node[i*3+j] = 220; + } + } +} + + +/// Entraine un reseau de neurones +void SegmNN::TrainNN() { + + unsigned long pixelNum; + unsigned char *tabData; + int output[nbOutput]; + int numOutputMax=0; + + tabData = img->tabData; + config->colorMode = img->hsi*2 + img->yuv; + config->groupColor = 0; + + for(long i=0; inn_nil; i++) { + // On choisit un pixel au hasard + pixelNum = (unsigned long)(img->nbPixels*(rand()/(RAND_MAX+1.0))); + + // Calcul des valeurs de sorties pour ce pixel + for(int j=0; jyuv && k==0) || (img->hsi && k==2)) + output[j] += abs((int)(config->nn_influ_lum*node[j*3+k]-tabData[pixelNum*3+k])*abs(node[j*3+k]-tabData[pixelNum*3+k])); + else + output[j] += abs(node[j*3+k]-tabData[pixelNum*3+k])*abs(node[j*3+k]-tabData[pixelNum*3+k]); + } + + // On cherche la sortie ayant le plus haut niveau + if (output[j] < output[numOutputMax]) { + numOutputMax = j; + } + } + + // Mis a jour des poids + for(int k=0; k<3; k++) { + node[numOutputMax*3+k] = + (unsigned char)((node[numOutputMax*3+k] + config->nn_sl*tabData[pixelNum*3+k])/(1+config->nn_sl)); + + // Recompense pour la sortie qui travaille + freq[numOutputMax]++; + + // Verification des noeuds inutiles + if ((i%300) == 299) + { + for (int k=0; k < nbOutput; k++) + { + if (freq[numOutputMax] < config->nn_lazy_threshold) + { + // Regeneration de nouveaux poids + for(int m=0; m<3; m++) { + // Attribution aléatoire des poids + node[numOutputMax*3+m] = (unsigned char) (255.0*rand()/(RAND_MAX+1.0)); + if (node[numOutputMax*3+m] < 30) node[numOutputMax*3+m] = 30; + else if (node[numOutputMax*3+m] > 220) node[numOutputMax*3+m] = 220; + } + } + + // On remet le compteur a zero + freq[k] = 0; + } + + } + + } + + } +} + + +/// Renvoie le code de la couleur segmentee +/// @param *x pointeur vers un tableau contenant une valeur RGB +unsigned char SegmNN::FindColorNN(unsigned char *x) { + + int numOutputMax=0; + int output[nbOutput]; + int j; + + // Calcul des valeurs de sorties pour ce pixel + for(j=0; jyuv && k==0) || (img->hsi && k==2)) + output[j] += abs((int)(config->nn_influ_lum*node[j*3+k]-x[k])*abs(node[j*3+k]-x[k])); + else + output[j] += abs(node[j*3+k]-x[k])*abs(node[j*3+k]-x[k]); + } + + // On selectionne la sortie ayant la plus grande valeur comme couleur + if (output[numOutputMax] > output[j]) { + numOutputMax = j; + } + } + + return numOutputMax; +} + + +/// Segmente l'image avec le reseau de neurones +void SegmNN::Segm() { + + unsigned char* tabData = img->tabData; + + if (tabSegm) delete [] tabSegm; + tabSegm = new unsigned char[img->nbPixels]; + + // Parcours de l'image pour la segmentation + // On recupere l'index et non le numero de sortie du NN + for (unsigned long i=0; inbPixels; i++) { + tabSegm[i] = index[FindColorNN(tabData+i*3)]; + } +} + +/// Segmente l'image pour une seule couleur uniquement et permet donc d'isoler un ficher +/// @param numColor numero de la couleur a isoler +void SegmNN::Segm(int numColor) { + unsigned char* tabData = img->tabData; + + if (tabSegm) delete [] tabSegm; + tabSegm = new unsigned char[img->nbPixels]; + + // Parcours de l'image pour la segmentation + for (unsigned long i=0; inbPixels; i++) { + if (FindColorNN(tabData+i*3) == numColor) tabSegm[i] = 1; + else tabSegm[i] = 0; + } +} + + +/// Entraine plusieurs reseaux de neurones avec des parametres differents et crees les images associees +void SegmNN::TestNN() { + + double sl[] = {0.01, 0.1, 1}; + unsigned long nil[] = {100, 1000, 10000, 100000, 1000000}; + int nc[] = {3,4,5,6,7,8}; + + char filename[30]; + + // Parcours de toutes les valeurs de nombres de couleurs + for (int i_nc = 0; i_nc<6; i_nc++) { + BuildNN(nc[i_nc], 0); + + // Parcours de toutes les valeurs de nombres d'itérations + for (int i_nil = 0; i_nil<5; i_nil++) { + + config->nn_nil = nil[i_nil]; + + // Parcours de toutes les valeurs de Step Learning + for (int i_sl = 0; i_sl<4; i_sl++) { + config->nn_sl = sl[i_sl]; + + // Apprentissage du NN + TrainNN(); + + // Segmentation + Segm(); + + // Ecriture des résultats dans une image + sprintf(filename, "NN/%i-%lf-%luNN.jpg", nc[i_nc], sl[i_sl], nil[i_nil]); + img->WriteSegm(filename, tabSegm); + sprintf(filename, "NN/%i-%lf-%luNN", nc[i_nc], sl[i_sl], nil[i_nil]); + config->node = node; + config->CreateNNFile(filename, config->colorMode, nbOutput); + } + } + } +} diff --git a/2004/i/nono/src/ovision/segmNN.h b/2004/i/nono/src/ovision/segmNN.h new file mode 100644 index 0000000..e870392 --- /dev/null +++ b/2004/i/nono/src/ovision/segmNN.h @@ -0,0 +1,75 @@ +#ifndef segmNN_h +#define segmNN_h +// segmNN.h - classe Segmentation +// nono - Programme du robot Efrei Robotique I1-I2 2004 +// Copyright (C) 2004 Olivier Gaillard + + +#include "imgFile.h" +#include "config.h" + +// Constantes +#define MIN 0 +#define MAX 1 + + +/// Constantes pour la creation du NN +#define LOAD_FROM_FILE 1 +#define GENERATE 0 + +/// Segmente l'image et cree un tableau contenant des valeurs segmentees, creation du reseau de neurones et apprentissage +class SegmNN +{ + // Classe image + ImgFile *img; + + // Classe config + Config *config; + + public: + // tableau avec couleurs segmentees + unsigned char *tabSegm; + + // tableau de poids du NN + unsigned char *node; + + // index des couleurs pour melanger (merge) les couleurs + int *index; + + // memorise la popularite des noeuds pour enlever les sorties inefficaces + unsigned int *freq; + + // nb de couleurs a differencier + int nbOutput; + + /// Constructeur + SegmNN (ImgFile *img, Config *config); + + /// Destructeur + ~SegmNN (void); + + /// Affiche la valeur des poids du NN + void ShowNodes(); + + /// Cree le NN + void BuildNN(int nbOutput, int loadFromFile); + + /// Apprentissage du NN + void TrainNN(); + + /// Segmentation de l'image + void Segm(); + + /// Segmentation de l'image permettant d'isoler une couleur + void Segm(int numColor); + + /// Entraine plusieurs reseaux de neurones avec des parametres differents + void TestNN(); + + protected: + /// Renvoie le code la couleur segmentee + unsigned char FindColorNN(unsigned char *x); + +}; + +#endif // segmNN_h diff --git a/2004/i/nono/src/ovision/segmTh.cc b/2004/i/nono/src/ovision/segmTh.cc new file mode 100644 index 0000000..78481b6 --- /dev/null +++ b/2004/i/nono/src/ovision/segmTh.cc @@ -0,0 +1,126 @@ +// segmTh.cc - Classe Segmentation +// nono - Programme du robot Efrei Robotique I1-I2 2004 +// Copyright (C) 2004 Olivier Gaillard +#include "segmTh.h" +#include +#include +using namespace std; + +SegmTh::SegmTh(Img *img, Config *config) { + SegmTh::img = img; + SegmTh::config = config; + nbOutput = config->nn_NbCouleurs; + + tabSegm = NULL; +} + + +SegmTh::~SegmTh() +{ +} + + +void SegmTh::CreateThresholds(char *filename, unsigned char *node) { + + int weight[nbOutput][3]; + int seuil[nbOutput][3][2]; + int tmp; + + if (!node) { + cerr << "SegmTh::CreateThresholds : NN non initialisé\n"; + return; + } + + // Classement des seuils par ordre croissant + for (int comp=0; comp<3; comp++) { + + // Tri par insertion pour les 3 composantes avec un tableau d'index + for(int i=0; i0) && (node[weight[j][comp]*3+comp] < node[weight[j-1][comp]*3+comp])) { + tmp = weight[j-1][comp]; + weight[j-1][comp]=weight[j][comp]; + weight[j][comp]=tmp; + j--; + + } + } + } + + // Formation des seuils + for (int comp=0; comp<3 ; comp++) { + for (int i=0; icolor[i*6]; + + // On test pour savoir si la couleur correspond au seuils + if (x[0] >= pColor[0] && x[0] <= pColor[1] && + x[1] >= pColor[2] && x[1] <= pColor[3] && + x[2] >= pColor[4] && x[2] <= pColor[5]) + return i; + } + + // Si aucune couleur ne correspond + return nbOutput; +} + + +void SegmTh::Segm () { + if (tabSegm) delete [] tabSegm; + tabSegm = new unsigned char[img->nbPixels]; + if (config->nbCouleurMax < nbOutput) { + cerr << "SegmTh::Segm : Nb de couleurs dans le fichier threshold insuffisante\n"; + return; + } + + + // Parcours de l'image et détermination de la couleur + for (int i=0; i<(int)(img->nbPixels); i++) { + tabSegm[i] = FindzoneTh(img->tabData+i*3); + } +} + diff --git a/2004/i/nono/src/ovision/segmTh.h b/2004/i/nono/src/ovision/segmTh.h new file mode 100644 index 0000000..b430340 --- /dev/null +++ b/2004/i/nono/src/ovision/segmTh.h @@ -0,0 +1,37 @@ +#ifndef segmTh_h +#define segmTh_h +// segmTh.h - classe Segmentation +// nono - Programme du robot Efrei Robotique I1-I2 2004 +// Copyright (C) 2004 Olivier Gaillard + + +#include "img.h" +#include "config.h" + +#define MIN 0 +#define MAX 1 + +class SegmTh +{ + Img *img; + Config *config; + + int nbOutput; // nb de couleurs a différencier + + public: + unsigned char *tabSegm; // tableau avec couleurs segmentées + + // Constructeurs. + SegmTh (Img *img, Config *config); + + // Destructeur. + ~SegmTh (void); + + void Segm(); + void CreateThresholds(char *filename, unsigned char *node); // Crée un fichier avec les seuils + + protected: + unsigned char FindzoneTh (unsigned char *x); +}; + +#endif // segmTh_h diff --git a/2004/i/nono/src/ovision/space.cc b/2004/i/nono/src/ovision/space.cc new file mode 100644 index 0000000..770a2d9 --- /dev/null +++ b/2004/i/nono/src/ovision/space.cc @@ -0,0 +1,341 @@ +// space.cc - Classe Space +// nono - Programme du robot Efrei Robotique I1-I2 2004 +// Copyright (C) 2004 Olivier Gaillard + +/// @file space.cc Etalonnage des distances et localisation de la balle + +#include "space.h" +#include + +#include "imgFile.h" +#include "segmNN.h" +#include "group.h" + +using namespace std; +/*namespace std +{ +struct less { + bool operator()(TABLOC *loc1, TABLOC *loc2) + { + return loc1->locImageY < loc2->locImageY; + } +} +*/ + +/// Constructeur +/// @param imgHeight hauteur de l'image +/// @param imgWidth largeur de l'image +Space::Space (uint imgHeight, uint imgWidth) +{ + Space::imgHeight = imgHeight; + Space::imgWidth = imgWidth; + + indexTabY = NULL; + indexTabX = NULL; +} + + +/// Destructeur +Space::~Space () +{ +} + + +/// Affiche la liste des distance etalonneess +void Space::ShowTab() +{ + cout << "\nTabLocY (" << tabLocY.size() << "):" << endl; + cout << "num\tlocImageY\tdistance\tsurface" << endl; + + // Parcours de la liste et affichage ces elements pour y + for (uint i=0; i < tabLocY.size(); i++) + { + cout << i << "\t" << tabLocY[i].locImageY << "\t\t" << tabLocY[i].distance << "\t\t" << tabLocY[i].surface << endl; + } + + cout << "\nTabLocX (" << tabLocX.size() << "):" << endl; + cout << "num\tlocImageX\tlocImageY\tangle\tdistance" << endl; + + // Parcours de la liste et affichage ces elements pour y + for (uint i=0; i < tabLocX.size(); i++) + { + cout << i << "\t" << tabLocX[i].locImageX << "\t\t" << tabLocX[i].locImageY << "\t\t" << tabLocX[i].angle << "\t" << tabLocX[i].distance << endl; + } +} + + + +/// Permet d'ajouter une distance pour l'etalonnage +/// @param zone zone de l'image ou la balle se situe +/// @param distance distance de la balle au robot +void Space::SetDist(ZONE zone, unsigned int distance) +{ + TABLOC loc; + + // Initialisation des valeurs a ajouter a la liste + loc.locImageY = zone.centery; + loc.distance = distance; + loc.surface = (zone.xmax - zone.xmin) * (zone.ymax - zone.ymin); + + // On range cette loc dans le tableau + // Si c'est le premier element + if (!tabLocY.size()) + { + tabLocY.push_back(loc); + } + // Si ce n'est pas le premier element + else + { + // Trie par ordre croissant des distances + vector::iterator it; + it = tabLocY.begin(); + // Parcours de la liste pour ajouter au bon endroit + while (it != tabLocY.end()) + { + if (it->distance < distance) + it++; + else + { + tabLocY.insert(it, loc); + it = tabLocY.end(); + } + } + } + +} + + +/// Cree la liste des distances etalonnees a partir d'image +void Space::DoDistTab() +{ + ImgFile img; + Config config("vision.conf"); + SegmNN segm(&img, &config); + TABLOC loc; + + Date &d = Date::GetInstance(); + + Motor m; + Movement *mov = new MovementGoto(-0.1, 400); + m.setMovement(mov); + + double x, y, angle; + double lastY = 0; + int lastGroupY = 0; + + m.go(); + + + // On cherche la composante de profondeur + for (int i=0; i < 10; i++) + { + m.waitOK(); + m.tracker_.getPos(&x, &y, &angle); + + if (y > lastY+10) + { + img.ReadRaw(); + if (config.colorMode == YUV) img.RGBtoYUV(); + + segm.Segm(); + + Group group(&img, &segm); + group.JumpPoints(config.groupColor); + + if (group.zoneListBall) + { + ZONE *pBall = group.zoneListBall; + + // on teste s'il y a eu un changement dans l'image + if (pBall->centery < lastGroupY) + { + //group.ShowZones(); + loc.distance = y; + loc.surface = (pBall->xmax - pBall->xmin) * (pBall->ymax - pBall->ymin); + loc.locImageY = pBall->centery; + + tabLocY.push_back(loc); + + lastGroupY = pBall->centery; + } + } + lastY = y; + } + + d.wait(10); + } + + m.ungo(); + + + return 0; +} + + + + + + + + + + +/* const int nbFile = 6; + char file[nbFile][40] = {{"../thumbrobot/9.jpg"}, {"../thumbrobot/7.jpg"}, {"../thumbrobot/8.jpg"}, + {"../thumbrobot/6.jpg"}, {"../thumbrobot/10.jpg"}, {"../thumbrobot/11.jpg"}}; + + segm.BuildNN(config.nn_NbCouleurs, LOAD_FROM_FILE); + + // On cherche la composante de profondeur + for (int i=0; i < nbFile; i++) + { + img.ReadRaw(file[i]); + if (config.colorMode == YUV) img.RGBtoYUV(); + + segm.Segm(); + + Group group(&img, &segm); + group.JumpPoints(config.groupColor); + + if (group.zoneListBall) + { + ZONE *pBall = group.zoneListBall; + //group.ShowZones(); + loc.distance = i; + loc.surface = (pBall->xmax - pBall->xmin) * (pBall->ymax - pBall->ymin); + loc.locImageY = pBall->centery; + + tabLocY.push_back(loc); + } + } + + // On cherche la composante honrizontale +/* for (int i=0; i < nbFile; i++) + { + img.ReadRaw(file[i]); + if (config.colorMode == YUV) img.RGBtoYUV(); + + segm.Segm(); + + Group group(&img, &segm); + group.JumpPoints(config.groupColor); + + if (group.zoneListBall) + { + ZONE *pBall = group.zoneListBall; + loc.locImageY = pBall->centery; + loc.locImageX = pBall->centerx; + loc.distance = (int)sqrt((double)((pBall->centery*pBall->centery)+(pBall->centerx*pBall->centerx))); + loc.angle = i; + + // get angle + + tabLocX.push_back(loc); + } + } +*/ +// tabLocY.sort(tabLoc.begin(), tabLoc.end(), less); + + /* + // Exemple de remplissage de la table au lieu d'utiliser les images + for(int i=0; i<10; i++) { + loc.locImageY = i*11; + loc.distance = i; + loc.surface = 100; + + tabLocY.push_back(loc); + } + */ +} + + +/// Cree le tableau d'index a partir de la liste +void Space::DoIndexTab() +{ + uint start, stop; + + // Allocation de la memoire + if (indexTabY) delete [] indexTabY; + indexTabY = new uint[imgHeight]; + if (indexTabX) delete [] indexTabX; + indexTabX = new uint[imgHeight*imgWidth]; + + // Parcours de la liste des distances ajoutées avec SetDist + // et creation d'un tableau + for(uint y=0; y < tabLocY.size(); y++) + { + // Recherche des bornes entre 2 distances de la liste + if (y == 0) + { + start = 0; + stop = tabLocY[1].locImageY / 2; + } + else if (y == tabLocY.size()-1) + { + start = stop; + stop = imgHeight; + } + else + { + start = stop; + stop = (tabLocY[y+1].locImageY - tabLocY[y].locImageY) / 2 + tabLocY[y].locImageY; + } + + // Remplissage du tableau d'index + for(uint j=start; j < stop; j++) + indexTabY[j] = y; + } + + for(uint y=0; y < imgHeight; y++) + { + for(uint x=0; x < imgWidth; x++) + { + indexTabX[y*imgWidth+x] = 0;//distance * cos(angle) * locImageX / POS_ROBOT_ETALONNOGE_X ; + } + } + + + +} + + +/// Renvoie la distance en fonction du pixel donne +/// @param locImageY pixel de l'image ou la balle a ete trouvee +uint Space::GetDistY(unsigned int locImageY) +{ + // Retourne la distance inscrit dans la table tabLocY + return tabLocY[indexTab[locImageY]].distance; +} + +uint Space::GetDistX(unsigned int locImageX, unsigned int locImageY) +{ + // Retourne la distance inscrit dans la table tabLocY + return 1; +} + + +/// Position d'un objet dans le referentiel du robot +/*void Space::GetLoc(uint locImgX, uint locImgY, uint *locX, uint *locY) +{ + locX = 0; +// locY = tabLocY[indexTab[locImgY]].distance; +} + +*/ + +/// Donne la position reelle sur la table de la balle +/// @param *vOrig position du robot sur la table +/// @param *vDir position de la balle par rapport au robot +/// @param angle rotation du robot par rapport a sa position d'origine +void Space::GetPos(Vec *vOrig, Vec *vDir, float angle) +{ + Vec vPos; + float sinus = sin(angle); + float cosinus = cos(angle); + + // Calcul des coordonnes avec le changement de repere + vPos.x = vOrig->x + vDir->x*cosinus - vDir->y*sinus; + vPos.y = vOrig->y + vDir->x*sinus + vDir->y*cosinus; + + printf("Position: %f %f\n", vPos.x, vPos.y); +} diff --git a/2004/i/nono/src/ovision/space.h b/2004/i/nono/src/ovision/space.h new file mode 100644 index 0000000..30f69b6 --- /dev/null +++ b/2004/i/nono/src/ovision/space.h @@ -0,0 +1,121 @@ +#ifndef space_h +#define space_h +// space.h - Space class +// nono - Programme du robot Efrei Robotique I1-I2 2004 +// Copyright (C) 2004 Olivier Gaillard + +#include +#include +#include "date/date.h" +#include "motor/motor.h" + +#define TAILLE_MAX 1000 + +#define POS_ROBOT_ETALONNOGE_X 300 + +#include "group.h" + +struct TABLOC { + unsigned int height; + unsigned int surface; + unsigned int locImageX; + unsigned int locImageY; + unsigned int distance; + unsigned int angle; +}; + +/// Classe Vec simplifiant l'utilisation de vecteur 2D +class Vec +{ + public: + /// Coordonnees du vecteur + float x; + float y; + + /// Constructeurs + Vec(void); + Vec(float x1, float y1, float x2, float y2); + Vec(float x, float y); + + /// Operateur + + inline Vec operator+(Vec v) + {return Vec(x + v.x, y + v.y);} + +}; + +/// Constructeur +inline Vec::Vec(void) +{ +} + +/// Constructeur avec initialisation des coordonnees +/// @param vx coordonnees du vecteur +/// @param vy coordonnees du vecteur +inline Vec::Vec(float vx, float vy) +{ + x = vx; + y = vy; +} + + +/// Constructeur avec calcul des coordonnees suivant des points +/// @param x1 Premier point du vecteur +/// @param y1 Premier point du vecteur +/// @param x2 Deuxieme point du vecteur +/// @param y2 Deuxieme point du vecteur +inline Vec::Vec(float x1, float y1, float x2, float y2) +{ + x = x2 - x1; + y = y2 - y1; +} + + +/// Etalonnage des distances et localisation de la balle +class Space +{ + /// tableau d'index des distances + uint *indexTabX; + uint *indexTabY; + + /// liste des distances etalonnees + std::vector tabLocX; + std::vector tabLocY; + + /// hauteur de l'image + uint imgHeight; + + /// largeur de l'image + uint imgWidth; + + + public: + + /// Permet d'ajouter une distance pour l'etalonnage + void SetDist(ZONE zone, unsigned int distance); + + /// Renvoie la distane en fonction du pixel donne + unsigned int GetDistX(unsigned int locImageX, unsigned int locImageY); + unsigned int GetDistY(unsigned int locImageY); + + /// Affiche la liste des distance etalonnees + void ShowTab(); + + /// Cree la liste des distances etalonnees a partir d'image + void DoDistTab(); + + /// Cree le tableau d'index a partir de la liste + void DoIndexTab(); + + /// Donne la position reelle sur la table de la balle + void GetPos(Vec *vOrig, Vec *vDir, float angle); + + // Constructeur + Space (uint imgWidth, uint imgHeight); + + // Destructeur + ~Space (); + + protected: +}; + +#endif // space_h diff --git a/2004/i/nono/src/ovision/test.cc b/2004/i/nono/src/ovision/test.cc new file mode 100644 index 0000000..26b0500 --- /dev/null +++ b/2004/i/nono/src/ovision/test.cc @@ -0,0 +1,32 @@ +// test.cc - Programme de test du NN +// nono - Programme du robot Efrei Robotique I1-I2 2004 +// Copyright (C) 2004 Olivier Gaillard + +#include "img.h" +#include "segmNN.h" +#include "segmTh.h" +#include "config.h" +#include "group.h" +#include "space.h" +#include +using namespace std; + + + + +int main(int argc, char **argv) { + Img img; + + Config config("vision.conf"); + + system("rm -Rf NN && mkdir NN"); + + if (argv[1]) img.ReadRaw(argv[1]); + else img.ReadRaw("palet.jpg"); + img.RGBtoYUV(); + + SegmNN segmNN(&img, &config); + + segmNN.TestNN(); +} + diff --git a/2004/i/nono/src/ovision/testdist.cc b/2004/i/nono/src/ovision/testdist.cc new file mode 100644 index 0000000..8936607 --- /dev/null +++ b/2004/i/nono/src/ovision/testdist.cc @@ -0,0 +1,14 @@ +#include "space.h" +#include +using namespace std; + +int main() +{ + Space space(356, 288); + + space.DoDistTab(); + space.ShowTab(); + space.DoIndexTab(); + + + diff --git a/2004/i/nono/src/ovision/testimg.cc b/2004/i/nono/src/ovision/testimg.cc new file mode 100644 index 0000000..4b797ca --- /dev/null +++ b/2004/i/nono/src/ovision/testimg.cc @@ -0,0 +1,65 @@ +// img.cc - Classe Image +// nono - Programme du robot Efrei Robotique I1-I2 2004 +// Copyright (C) 2004 Olivier Gaillard + +#include "imgFile.h" +#include "segmNN.h" +#include "config.h" +#include "group.h" +#include +using namespace std; + + + + +int main(int argc, char **argv) { + ImgFile img; + + Config config("vision.conf"); + + + if (argv[1]) img.ReadRaw(argv[1]); + else img.ReadRaw("palet.jpg"); + // img.EdgeDetect(); + // img.RGBtoHSI(); + // img.RGBtoYUV(); + + SegmNN segmNN(&img, &config); + segmNN.BuildNN(config.nn_NbCouleurs, LOAD_FROM_FILE); + + // segmNN.TrainNN(); + // segmNN.ShowNodes(); + segmNN.Segm(); + // config.node = segmNN.node; + // config.CreateNNFile("poids", config.colorMode, segmNN.nbOutput); + // img.WriteSegm("NN.jpg", segmNN.tabSegm); + + + // segmNN.CreateThresholds("threshold"); + // config.LoadThFile(); + // SegmTh segmTh(&img, &config); + // segmTh.Segm(); + // img.WriteSegm("Th.jpg", segmTh.tabSegm); + // segmNN.TestNN(); + + + // Group group(&img, &segmNN); + // group.JumpPoints(config.groupColor); + + /* Space space(img.width, img.height); + //if (group.zoneList) space.SetDist(group.zoneList[0], 10); + space.DoDistTab(); + space.ShowTab(); + space.DoIndexTab(); + // cout << space.GetDist(54) << endl; + // cout << space.GetDist(155) << endl; + */ + //Vec vOrig(10, 5); + //Vec vDir(1,2); + // space.GetPos(&vOrig, &vDir, -0.785); + + // img.WriteSegm("group.jpg",group.tabOut); + + +} + diff --git a/2004/i/nono/src/ovision/testmap.cc b/2004/i/nono/src/ovision/testmap.cc new file mode 100644 index 0000000..2626617 --- /dev/null +++ b/2004/i/nono/src/ovision/testmap.cc @@ -0,0 +1,29 @@ + + +#include "map.h" +#include "config.h" +//#include "group.h" + +int +main() +{ + Config config("vision.conf"); + Map map(&config); + + ImgFile img; + img.ReadRaw("palet.jpg"); + + SegmNN segmNN(&img, &config); + segmNN.BuildNN(config.nn_NbCouleurs, LOAD_FROM_FILE); + + segmNN.Segm(); + + Group group(&img, &segmNN); + group.JumpPoints(config.groupColor); + group.ShowZones(); + + map.ShowBalls(); + map.AddBallsToMap(&group); + map.ShowBalls(); + + } diff --git a/2004/i/nono/src/ovision/testsegm.cc b/2004/i/nono/src/ovision/testsegm.cc new file mode 100644 index 0000000..f77dcfa --- /dev/null +++ b/2004/i/nono/src/ovision/testsegm.cc @@ -0,0 +1,18 @@ +// img.cc - Classe Image +// nono - Programme du robot Efrei Robotique I1-I2 2004 +// Copyright (C) 2004 Olivier Gaillard +#include "img.h" +#include + + + +int main(int argc, char **argv) { + Img img; + + if (img.ReadRaw(argv[1])) + printf("Ouverture de l'image effectué\n"); + img.SegmImg(); + img.WriteSegm("segm"); + +} + diff --git a/2004/i/nono/src/ovision/testui.cc b/2004/i/nono/src/ovision/testui.cc new file mode 100644 index 0000000..32ce7a1 --- /dev/null +++ b/2004/i/nono/src/ovision/testui.cc @@ -0,0 +1,46 @@ +#include "ui.h" + +#include + +#include +#include +#include + +using namespace std; + +UI *ui; +int ready; + +int +GetReady() +{ + return ready; +} + +void +SetReady(int i) +{ + ready = i; +} + + +// Lecture du fifo et execution de la commande +void +endSleep(int numSignal) +{ + // Reassignement du signal handler + signal(SIGUSR1, endSleep); + ready = 1; +} + + +int +main() +{ + signal(SIGUSR1, endSleep); + + ui = new UI; + ui->Menu(); + + delete ui; +} diff --git a/2004/i/nono/src/ovision/testui.h b/2004/i/nono/src/ovision/testui.h new file mode 100644 index 0000000..2d550cb --- /dev/null +++ b/2004/i/nono/src/ovision/testui.h @@ -0,0 +1,4 @@ + +int GetReady(); +void SetReady(int i); + diff --git a/2004/i/nono/src/ovision/ui.cc b/2004/i/nono/src/ovision/ui.cc new file mode 100644 index 0000000..93ed499 --- /dev/null +++ b/2004/i/nono/src/ovision/ui.cc @@ -0,0 +1,898 @@ +// ui.cc - Classe User Interface +// nono - Programme du robot Efrei Robotique I1-I2 2004 +// Copyright (C) 2004 Olivier Gaillard + +/// @file ui.cc Interface ncurses permettant de piloter adjust + +#include +#include +#include +#include +#include +#include +#include + +#include "config.h" +#include "ui.h" +#include "testui.h" + +using namespace std; + +#define BALL 1 +#define GOAL 2 + + +/// Nombre d'items du menu +#define NBITEMS 11 + +Config config("vision.conf"); + +/// Items du menu principal +char *itemsName[NBITEMS][2] = {{"Move color", "Permet d'ajuster les niveaux d'une couleur"}, + {"Del color", "Enleve une couleur du reseau"}, + {"Merge colors", "Groupe plusieurs couleurs ensembles"}, + {"Select color ball", "Selectionne l'index de la couleur des balles"}, + {"Select color goal", "Selectionne l'index de la couleur des poteaux"}, + {"Training", "Entraine le reseau de neurones"}, + {"New network", "Regenere de nouveaux poids pour le reseau"}, + {"Cancel changes", "Recharge le fichier de config"}, + {"Save changes", "Sauvegarde les changements dans le fichier"}, + {"Quit", "Quitte le programme"}, + {NULL, NULL}}; + +/// Constructor +UI::UI() +{ + // TODO verifier que le terminal est assez grand sinon écran noir + + + // Suppression de l'ancien fifo + system("rm -f uicmds"); + + // Creation du fifo + if (mknod("uicmds", S_IFIFO | 0666, 0) != 0 && errno != EEXIST) + { + cerr << "UI::UI : Error during fifo creation"; + return; + } + + // Ouverture du fifo + fifo = open("uicmds", O_RDWR); + if (fifo < 0) + { + cerr << "UI::UI : Error during fifo opening"; + return; + } + + // On choppe le pid du prog adjust situé dans le fichier adjust.PID + FILE *file; + file = fopen("adjust.PID", "r"); + if (!file) + { + cerr << "UI:UI : PID file not found" << endl; + exit(1); + } + char buf[10]; + fgets(buf, 10, file); + pid = atol(buf); + fclose(file); + + curImage = 0; + ParseFileList(); + + config.LoadNNFile(); + savedNNColorNumber = config.nn_NbCouleurs; + + // Ecriture du PID dans un fichier + long uiPid = getpid(); + file = fopen("ui.PID", "w+"); + if (!file) + { + cerr << "UI::UI : Error during file opening" << endl; + return; + } + fprintf(file, "%li\n", uiPid); + fclose(file); + + // Ouverture du fifo + kill(pid, SIGUSR2); + + // Init ncurses + initscr(); + start_color(); + keypad(stdscr, TRUE); + cbreak(); + noecho(); + curs_set(0); + + // Init couleurs + init_pair(1, COLOR_BLUE, COLOR_BLACK); + init_pair(2, COLOR_RED, COLOR_BLACK); + init_pair(3, COLOR_GREEN, COLOR_BLACK); + init_pair(4, COLOR_CYAN, COLOR_BLACK); + +} + + +/// Destructeur +UI::~UI() +{ + // Libere memoire + unpost_menu(menu); + free_menu(menu); + for(int i = 0; i < NBITEMS; ++i) + free_item(item[i]); + endwin(); + + close(fifo); + + // Ferme adjust SIGQUIT + kill(pid, SIGQUIT); + + system("rm -f adjust.PID ui.PID"); + + if (fileList) delete fileList; +} + + +/// Synchronisation des poids locaux avec ceux du programme adjust +void +UI::UpdateNodes() +{ + char buf[10]; + + // On parcours toutes les couleurs + for (int i=0; i < config.nn_NbCouleurs*3; i++) + { + // On lis le fifo et on le copie dans le tableau node + read(fifo, buf, 10); + config.node[i] = atoi(buf); + } +} + + + +/// Cree la liste d'images a ouvrir +void +UI::ParseFileList() +{ + // On enleve l'ancienne liste et on en cree une nouvelle + char buf[100]; + sprintf(buf, "rm -Rf imagelist ; ls %s | grep -e .jpg -e .JPG -e .png -e .PNG > imagelist", config.imgPath); + system(buf); + + FILE *file; + file = fopen("imagelist", "r"); + if (!file) + { + cerr << "UI:ParseFileList : file not found" << endl; + cerr << "UI:ParseFileList : use 'ls pictures_dir > imagelist" << endl; + exit(1); + } + + lengthFileList = 0; + + while(fgets(buf, 30, file)) + lengthFileList++; + rewind(file); + + fileList = new char*[lengthFileList]; + int fileCount = 0; + char *p; + + while (fgets(buf, 30, file)) + { + fileList[fileCount] = new char[30]; + p = strtok(buf, "\t\n"); + if (p) + { + strcpy(fileList[fileCount], p); + fileCount++; + } + else lengthFileList--; + } +} + + +/// Envoie une donnee au prog adjust +/// @param *cmd commande a envoyer +void +UI::SendSignal(char *cmd) +{ + // Ecrit dans le fifo + write(fifo, cmd, 50); + + // Envoie un signal USR1 au prog adjust + kill(pid, SIGUSR1); + + // Attente de la reponse de adjust + SetReady(0); + while (!GetReady()) + { + usleep(1); + } +} + +/// Affiche un msg dans la barre d'etat +/// @param *str message a afficher dans la barre d'etat +void +UI::PrintStatus(char *str) +{ + // Creation de la fenetre + WINDOW *statusWindow = newwin(3, 60, 20, 5); + wattron(statusWindow, A_BOLD | COLOR_PAIR(4)); + + // Affichage du texte + wprintw(statusWindow, "%s\n", str); + wrefresh(statusWindow); + + // Liberation de la memoire + delwin(statusWindow); +} + + +/// Menu de selection de couleur +/// @param type choix du texte des items +/// @param current item selectionne au depart +int +UI::ChooseColor(int type, int current) +{ + // Choix de la couleur + char **colorName; + + // Nombre d'item a afficher + if (type == NB_COULEUR) + config.nn_NbCouleurs = 10; + + // Creation des items + ITEM **colorItem = new ITEM*[config.nn_NbCouleurs+2]; + colorName = new char*[config.nn_NbCouleurs+1]; + for (int i=0; i "); + post_menu(colorMenu); + wrefresh(colorWindow); + + // Affichage d'info + PrintStatus("Utiliser ENTREE pour selectionner la couleur\n"); + + char buf[50]; + int car; + int col=0; + + if (type == NUM_COULEUR) + { + // Cree une image de la couleur selectionnee + sprintf(buf, "s %i\n", current); + SendSignal(buf); + } + + set_current_item(colorMenu, colorItem[current]); + col = current; + + wrefresh(colorWindow); + + while((car = wgetch(colorWindow)) != 10) + { + switch (car) + { + case KEY_DOWN: // Touche BAS + // Deplacement dans le menu + if (col < (int)config.nn_NbCouleurs) + { + menu_driver(colorMenu, REQ_DOWN_ITEM); + col++; + } + break; + + case KEY_UP: // Touche HAUT + // Deplacement dans le menu + if (col > 0) + { + menu_driver(colorMenu, REQ_UP_ITEM); + col--; + } + break; + } + + if ( (type == NUM_COULEUR) && (col < config.nn_NbCouleurs)) + { + // Cree une image de la couleur selectionnee + sprintf(buf, "s %i\n", col); + SendSignal(buf); + } + + wrefresh(colorWindow); + } + + // Cas d'annulation + if (col == config.nn_NbCouleurs) + { + col = -1; + + // On reaffiche l'image normale + SendSignal("r -1\n"); + } + + // Liberation memoire + for(int i=0; i "); + menu_opts_off(mergeMenu, O_ONEVALUE); + post_menu(mergeMenu); + + wrefresh(mergeWindow); + + // Initialisation de variables + int c; + int end = 0; + int col = 0; + char buf[40]; + char cmd[50]; + char tmp[3]; + int nbColorToMerge = 0; + + // Cree une image de la couleur selectionnee + SendSignal("s 0\n"); + + // Affichage d'info + PrintStatus("ESPACE pour choisir les valeurs, ENTREE pour valider\n"); + + // Boucle du menu de selection des couleurs + int indexColor = -1; + while(!end) + { + c = wgetch(mergeWindow); + switch (c) + { + case ' ': // Touche ESPACE + // Selection d'un element + menu_driver(mergeMenu, REQ_TOGGLE_ITEM); + break; + + case KEY_DOWN: // Touche BAS + // Deplacement dans le menu + if (col < config.nn_NbCouleurs) + { + menu_driver(mergeMenu, REQ_DOWN_ITEM); + col++; + } + break; + + case KEY_UP: // Touche HAUT + // Deplacement dans le menu + if (col > 0) + { + menu_driver(mergeMenu, REQ_UP_ITEM); + col--; + } + break; + + case 10: // Touche ENTREE + // Validation des elements + items = menu_items(mergeMenu); + + + // Si l'option unmerge est choisie + if ( item_index(current_item(mergeMenu)) == item_count(mergeMenu)-1) + { + // On remet a zero la table d'index + for (int i=0; i\n"); + wprintw(colorWindow, "<---------------------------------------------------->\n"); + wprintw(colorWindow, "<---------------------------------------------------->\n"); + + // Affichage du curseur sur les lignes + // ainsi que des valeurs des composantes de la couleur + wattron(colorWindow, A_BOLD | COLOR_PAIR(1)); + mvwprintw(colorWindow, 1, 56, "%3u", c[0]); + mvwprintw(colorWindow, 1, c[0]/5+1, "*"); + wattroff(colorWindow, A_BOLD | COLOR_PAIR(1)); + mvwprintw(colorWindow, 2, 56, "%3u", c[1]); + mvwprintw(colorWindow, 3, 56, "%3u", c[2]); + mvwprintw(colorWindow, 2, c[1]/5+1, "*"); + mvwprintw(colorWindow, 3, c[2]/5+1, "*"); + + wrefresh(colorWindow); + + // Boucle pour la selection des valeurs + int car; + while ((car = wgetch(colorWindow)) != 10) + { + switch(car) + { + case KEY_UP: // Touche HAUT + if (ligne != 0) + { + // Mise a jour affichage + mvwprintw(colorWindow, ligne+1, 56, "%3u", c[ligne]); + mvwprintw(colorWindow, ligne+1, c[ligne]/5+1, "*"); + ligne--; + } + break; + + case KEY_DOWN: // Touche BAS + if (ligne != 2) + { + // Mise a jour affichage + mvwprintw(colorWindow, ligne+1, 56, "%3u", c[ligne]); + mvwprintw(colorWindow, ligne+1, c[ligne]/5+1, "*"); + ligne++; + } + break; + + case KEY_LEFT: // Touche gauche + if (c[ligne] > 0) + { + // Mise a jour affichage + mvwprintw(colorWindow, ligne+1, c[ligne]/5+1, "-"); + c[ligne]--; + } + break; + + case KEY_RIGHT: // Touche droite + if (c[ligne] < 255) + { + // Mise a jour affichage + mvwprintw(colorWindow, ligne+1, c[ligne]/5+1, "-"); + c[ligne]++; + } + break; + + case KEY_NPAGE : // Touche gauche + if (c[ligne] > 9) + { + // Mise a jour affichage + mvwprintw(colorWindow, ligne+1, c[ligne]/5+1, "-"); + c[ligne]-=10; + } + break; + + case KEY_PPAGE: // Touche droite + if (c[ligne] < 246) + { + // Mise a jour affichage + mvwprintw(colorWindow, ligne+1, c[ligne]/5+1, "-"); + c[ligne]+=10; + } + break; + } + + // Mise a jour de l'affichage des valeurs + wattron(colorWindow, A_BOLD | COLOR_PAIR(1)); + mvwprintw(colorWindow, ligne+1, 56, "%3u", c[ligne]); + mvwprintw(colorWindow, ligne+1, c[ligne]/5+1, "*"); + wattroff(colorWindow, A_BOLD | COLOR_PAIR(1)); + + wrefresh(colorWindow); + + // Communication avec adjust + sprintf(cmd, "c %i %u %u %u\n", col, c[0], c[1], c[2]); + SendSignal(cmd); + + // Affichage d'info + sprintf(cmd, "Couleur %i change en %u %u %u\n", col, c[0], c[1], c[2]); + PrintStatus(cmd); + } + + // Affectation des nouvelles valeurs + for (int i=0; i<3; i++) + config.node[col*3+i] = c[i]; + + // Communication avec adjust + sprintf(cmd, "c %i %u %u %u\n", col, c[0], c[1], c[2]); + SendSignal(cmd); + + // Suppression de la fenetre ecran et affichage + delwin(colorWindow); + colorWindow = newwin(4, 60, 12, 25); + wrefresh(colorWindow); + delwin(colorWindow); +} + + +/// Affiche le menu principale +void +UI::Menu() +{ + // Init items + item = new ITEM*[NBITEMS]; + for (int i=0; i "); + set_menu_win(menu, mainWindow); + set_menu_sub(menu, derwin(mainWindow, 10, 65, 3, 1)); + set_menu_format(menu, NBITEMS, 1); + post_menu(menu); + + // Actualisation de la fenetre + wrefresh(mainWindow); + + int c; + int select=0; + int end=0; + + // Affichage de l'aide de l'item + wattron(mainWindow,COLOR_PAIR(3)); + mvwprintw(mainWindow, 3+select, 25, itemsName[select][1]); + + char buf[50]; + + // Boucle du menu principal + while(!end) + { + c = wgetch(mainWindow); + switch(c) + { + case KEY_DOWN: // Touche flèche BAS + // On se déplace vers le bas + menu_driver(menu, REQ_DOWN_ITEM); + if (select!=NBITEMS-2) + { + // Efface la ligne d'aide de l'item courant + mvwprintw(mainWindow,3+select, 25, "\t\t\t\t\t\t\t"); + select++; + } + break; + + case KEY_UP: // Touche flèche HAUT + // On se déplace vers le haut + menu_driver(menu, REQ_UP_ITEM); + if (select!=0) + { + // Efface la ligne d'aide de l'item courant + mvwprintw(mainWindow,3+select, 25, "\t\t\t\t\t\t\t"); + select--; + } + break; + + case 10: // Touche ENTER + switch(select) + { + case NBITEMS-2: // Quitte le programme + end=1; + break; + + case 0: // Change les valeurs des poids du NN pour une couleur + GoChangeColor(); + break; + + case 1: // Supprime une couleur + GoDelColor(); + break; + + case 2: // Melange 2 couleurs + GoMergeWindow(); + break; + + case 3: // Selectionne la couleur a grouper + GoSelectGroup(BALL); + break; + + case 4: // Selectionne la couleur des poteaux + GoSelectGroup(GOAL); + break; + + case 5: // Entraine le NN + sprintf(buf, "t\n"); + SendSignal(buf); + + // Synchronisation des poids avec adjust + UpdateNodes(); + + PrintStatus("Reseau de neurones entraine\n"); + break; + + case 6: // Regeneration de poids + int nbColor; + nbColor = ChooseColor(NB_COULEUR, config.nn_NbCouleurs); + if (nbColor != -1) + { + sprintf(buf, "p %i\n", nbColor); + SendSignal(buf); + + if (config.node) delete [] config.node; + config.node = new unsigned char[nbColor*3]; + + config.nn_NbCouleurs = nbColor; + + // Synchronisation des poids avec adjust + UpdateNodes(); + + PrintStatus("Nouveau reseau de neurones charge\n"); + } + break; + + case 7: // Annuler les changements + // Reload du fichier de poids initial + config.LoadNNFile(); + + // Envoie du nombre de couleur initial du NN et reload de l'image + sprintf(buf, "r %i", savedNNColorNumber); + SendSignal(buf); + config.nn_NbCouleurs = savedNNColorNumber; + + PrintStatus("Les changements ont ete annules\n"); + break; + + case 8: // Sauver les changements + // Sauvegarde des poids dans le fichier poids + config.CreateNNFile("poids", config.colorMode, config.nn_NbCouleurs); + + // Reload du NN et de l'image a partir des nouveaux poids + sprintf(buf, "r -1"); + SendSignal(buf); + + PrintStatus("Les changements ont ete sauves\n"); + break; + } // END switch touche ENTER + + break; + + // Sortie du programme + case 27: // ECHAP + end=1; + break; + + // Changement d'image + case ' ': + // Image suivante + curImage++; + if (curImage >= lengthFileList) curImage = 0; + + // Envoie de la commande pour le chargement de la nouvelle image + sprintf(buf, "n %s%s\n", config.imgPath, fileList[curImage]); + SendSignal(buf); + break; + } + + // On affiche le texte d'aide de l'item correspondant + mvwprintw(mainWindow, 3+select, 25, itemsName[select][1]); + wrefresh(mainWindow); + } + + delwin(mainWindow); +} + + diff --git a/2004/i/nono/src/ovision/ui.h b/2004/i/nono/src/ovision/ui.h new file mode 100644 index 0000000..4b29cb7 --- /dev/null +++ b/2004/i/nono/src/ovision/ui.h @@ -0,0 +1,92 @@ +#ifndef UI_h +#define UI_h +// UI.h - classe User Interface +// nono - Programme du robot Efrei Robotique I1-I2 2004 +// Copyright (C) 2004 Olivier Gaillard + + +// Realise a l'aide du "NCURSES Programming HOWTO" + + +#include "menu.h" + + +#define NUM_COULEUR 1 +#define NB_COULEUR 2 + + +/// Interface ncurses permettant de piloter adjust +class UI { + + /// Variable utilisees pour ncurses + ITEM **item; + MENU *menu; + WINDOW *mainWindow; + + /// Id du fifo + int fifo; + + /// PID du prog + long pid; + + /// Sauvegarde la valeur de sorties du NN + int savedNNColorNumber; + + /// liste des images + char **fileList; + + /// id de l'image actuel + int curImage; + + /// taille de la liste + int lengthFileList; + + + public: + /// Constructeurs. + UI (void); + + /// Destructeur. + ~UI (void); + + /// Affiche le menu principale + void Menu(); + + /// reponse du programme adjust + int uiReady; + + protected: + /// Cree la liste d'images a ouvrir + void ParseFileList(); + + /// Envoie une donnee au prog adjust + void SendSignal(char *buf); + + /// Menu de selection de couleur + inline int ChooseColor(int type) + {return ChooseColor(type, 0);} + + /// Menu de selection de couleur + int ChooseColor(int type, int current); + + /// Affiche un msg dans la barre d'etat + void PrintStatus(char *str); + + /// Menu de suppression de couleur + void GoDelColor(); + + /// Menu de selection du group a former + void GoSelectGroup(int type); + + /// Menu de melange de couleurs + void GoMergeWindow(); + + /// Menu de changements des composantes d'un poid du NN + void GoChangeColor(); + + /// Synchronisation des poids locaux et de ceux du programme adjust + void UpdateNodes(); +}; + + +#endif // UI_h -- cgit v1.2.3