summaryrefslogtreecommitdiff
path: root/2004
diff options
context:
space:
mode:
authorgaillaro2004-05-01 11:52:08 +0000
committergaillaro2004-05-01 11:52:08 +0000
commit109db2b0cce1b89c75e32f3705a1c5975391b3c5 (patch)
tree28da709aee1cbab296b99378e42a1e737403addf /2004
parentf95f1fb2bc439178a9e7ca6102b57c02c791f3f0 (diff)
Ajout de ovision.
Diffstat (limited to '2004')
-rw-r--r--2004/i/nono/src/ovision/adjust.cc237
-rw-r--r--2004/i/nono/src/ovision/adjust.h45
-rw-r--r--2004/i/nono/src/ovision/comm.cc350
-rw-r--r--2004/i/nono/src/ovision/comm.h64
-rw-r--r--2004/i/nono/src/ovision/config.cc347
-rw-r--r--2004/i/nono/src/ovision/config.h138
-rw-r--r--2004/i/nono/src/ovision/group.cc235
-rw-r--r--2004/i/nono/src/ovision/group.h87
-rw-r--r--2004/i/nono/src/ovision/img.cc83
-rw-r--r--2004/i/nono/src/ovision/img.h61
-rw-r--r--2004/i/nono/src/ovision/imgFile.cc137
-rw-r--r--2004/i/nono/src/ovision/imgFile.h44
-rw-r--r--2004/i/nono/src/ovision/map.cc179
-rw-r--r--2004/i/nono/src/ovision/map.h107
-rw-r--r--2004/i/nono/src/ovision/modele.h31
-rw-r--r--2004/i/nono/src/ovision/segmNN.cc260
-rw-r--r--2004/i/nono/src/ovision/segmNN.h75
-rw-r--r--2004/i/nono/src/ovision/segmTh.cc126
-rw-r--r--2004/i/nono/src/ovision/segmTh.h37
-rw-r--r--2004/i/nono/src/ovision/space.cc341
-rw-r--r--2004/i/nono/src/ovision/space.h121
-rw-r--r--2004/i/nono/src/ovision/test.cc32
-rw-r--r--2004/i/nono/src/ovision/testdist.cc14
-rw-r--r--2004/i/nono/src/ovision/testimg.cc65
-rw-r--r--2004/i/nono/src/ovision/testmap.cc29
-rw-r--r--2004/i/nono/src/ovision/testsegm.cc18
-rw-r--r--2004/i/nono/src/ovision/testui.cc46
-rw-r--r--2004/i/nono/src/ovision/testui.h4
-rw-r--r--2004/i/nono/src/ovision/ui.cc898
-rw-r--r--2004/i/nono/src/ovision/ui.h92
30 files changed, 4303 insertions, 0 deletions
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 <GL/glut.h> // Header File For The GLUT Library
+#include <GL/gl.h> // Header File For The OpenGL32 Library
+#include <GL/glu.h> // Header File For The GLu32 Library
+#include <iostream>
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <signal.h>
+
+#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<NBIMG; i++)
+ DrawImage(i);
+
+ glFlush();
+
+ // Affiche le buffer suivant
+ glutSwapBuffers();
+}
+
+
+/// Interruptions du clavier
+void
+KeyPressed(unsigned char key, int x, int y)
+{
+ // Touche Echap
+ if (key == 27)
+ {
+ glutDestroyWindow(window);
+ Leave(0);
+ }
+}
+
+
+/// Fonction principale
+int
+main(int argc, char **argv)
+{
+ // Initialisation de l'OpenGL
+ glutInit(&argc, argv);
+ glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
+ glutInitWindowSize(538, 395);
+ glutInitWindowPosition(0, 0);
+ window = glutCreateWindow("Adjust - Efrei Robotique");
+ glutDisplayFunc(&DrawGLScene);
+ glutReshapeFunc(&ReSizeGLScene);
+ glutKeyboardFunc(&KeyPressed);
+ InitGL(WIDTH, HEIGHT);
+
+ // Init de comm
+ comm = new Comm("palet.jpg");
+
+ //Initialisation des signal handlers
+ signal(SIGUSR1, ExecuteUiCmds);
+ signal(SIGUSR2, ExecuteUiCmds);
+ signal(SIGQUIT, Leave);
+
+ // Boucle principale
+ glutMainLoop();
+
+ return 1;
+}
diff --git a/2004/i/nono/src/ovision/adjust.h b/2004/i/nono/src/ovision/adjust.h
new file mode 100644
index 0000000..8cd53e8
--- /dev/null
+++ b/2004/i/nono/src/ovision/adjust.h
@@ -0,0 +1,45 @@
+#ifndef adjust_h
+#define adjust_h
+// adjust.h
+// nono - Programme du robot Efrei Robotique I1-I2 2004
+// Copyright (C) 2004 Olivier Gaillard
+
+
+/// Constantes d'interruptions
+#define QUIT 3
+#define USR1 10
+#define ALARM 14
+
+
+/// Proprietes de la fenetre
+#define WIDTH 1076
+#define HEIGHT 591
+#define BORDER 5
+#define NBIMG 6
+
+/// Constantes liees au chargement des commandes
+#define NUMCOLORTOCHANGE 1
+#define COLORTOCHANGE 2
+
+#define NBCOLORTOMERGE 1
+#define NUMCOLORTOMERGE 2
+
+#define NUMCOLORTODEL 1
+
+#define NBNNOUTPUT 1
+
+#define NUMGROUP 1
+
+#define NUMCOLORTOSHOW 1
+
+#define FILENAME 1
+
+#define NBCOLORNN 1
+
+/// Affiche les images a l'ecran
+void DrawGLScene();
+
+/// Chargement des textures a partir de donnees RGB
+unsigned int LoadImage(int width, int height, unsigned char *data, unsigned int lastTex);
+
+#endif // adjust_h
diff --git a/2004/i/nono/src/ovision/comm.cc b/2004/i/nono/src/ovision/comm.cc
new file mode 100644
index 0000000..4ff2566
--- /dev/null
+++ b/2004/i/nono/src/ovision/comm.cc
@@ -0,0 +1,350 @@
+// comm.cc - Classe Comm
+// nono - Programme du robot Efrei Robotique I1-I2 2004
+// Copyright (C) 2004 Olivier Gaillard
+
+
+/// @file comm.cc Interprete les commandes envoyes par l'interface UI et les executent
+
+#include <iostream>
+#include <fcntl.h>
+#include <unistd.h>
+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; i<config->nn_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; i<nbColorToMerge; i++)
+ segm->index[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; i<config->nn_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 <iostream>
+#include <stdlib.h>
+#include <string>
+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<nn_NbCouleurs; i++)
+ index[i] = i;
+ return;
+ }
+
+ // Nombre de couleurs contenu dans le fichier
+ int numNode=-3;
+ while(fgets(ligne, 50,file))
+ numNode++;
+
+ if (numNode <= 0) {
+ cerr << "Config::LoadNNFile : Corrupt poids file" << endl;
+ index = new int[nn_NbCouleurs];
+ for (int i=0; i<nn_NbCouleurs; i++)
+ index[i] = i;
+ return;
+ }
+
+
+ if (node) delete [] node;
+ node = new unsigned char[numNode*3];
+ if (index) delete [] index;
+ index = new int[numNode];
+
+ // Parcours des lignes et analyse
+ numNode=0;
+
+ // Recherche mode de couleur
+ rewind(file);
+
+ if (fgets(ligne, 50, file)) {
+ switch (ligne[0]) {
+ case 'Y': colorMode = YUV;
+ break;
+
+ case 'R': colorMode = RGB;
+ break;
+
+ case 'H': colorMode = HSI;
+ break;
+ }
+ }
+
+ // Recherche couleur des balles
+ if (fgets(ligne, 50, file)) {
+ cut[0] = strtok(ligne, " \t\n");
+ groupColor = atoi(cut[0]);
+ }
+
+ // Recherche couleur des poteaux
+ if (fgets(ligne, 50, file)) {
+ cut[0] = strtok(ligne, " \t\n");
+ goalColor = atoi(cut[0]);
+ }
+
+ while(fgets(ligne, 50, file)) {
+ if (ligne[0] == '#') continue;
+
+ // Division du string
+ cut[0] = strtok(ligne, " \t\n");
+ if (!cut[0]) continue;
+ i=0;
+ pNode = &node[numNode*3];
+ index[numNode] = atoi(cut[0]);
+ while ((cut[i] != NULL) && (i<(NBARG-1))) {
+ i++;
+ cut[i] = strtok( NULL, " \t\n");
+ pNode[i-1] = (unsigned char)atoi(cut[i]);
+ }
+ numNode++;
+ }
+
+ nbNodeMax = numNode;
+
+ fclose(file);
+
+}
+
+/// Creation d'un fichier de poids pour le reseau de neurones
+/// @param *filename nom du fichier a creer
+/// @param mode mode de l'espace de couleur
+/// @param nbOutput nombre de couleurs a detecter du reseau de neurones
+void Config::CreateNNFile(const char *filename, int mode, int nbOutput) {
+
+ if (!node) {
+ cerr << "Config::CreateNNFile : NN non initialisé\n";
+ return;
+ }
+
+ // Ecriture dans un fichier
+ FILE *file;
+ file = fopen(filename, "w+");
+
+ // Espace de couleur (RGB, YUV, HSI)
+ char buf[50];
+ if (colorMode == RGB) strcpy(buf, "RGB\n");
+ else if (colorMode == YUV) strcpy(buf, "YUV\n");
+ else if (colorMode == HSI) strcpy(buf, "HSI\n");
+
+ fprintf(file, buf);
+
+ // Couleur des balles
+ sprintf(buf, "%i // Index de la couleur des balles\n", groupColor);
+ fprintf(file, buf);
+
+ // Couleur des poteaux
+ sprintf(buf, "%i // Index de la couleur des poteaux\n", goalColor);
+ fprintf(file, buf);
+
+ fprintf(file, "#index\t#x1\tx2\tx3\n");
+ for (int i=0; i<nbOutput; i++) {
+ fprintf(file, "%i\t", index[i]);
+ for (int j=0; j<3; j++)
+ fprintf(file, "%u\t", node[i*3+j]);
+ fprintf(file, "\n");
+ }
+
+ fclose(file);
+}
+
+
+
+/// Chargement d'un fichier de seuils
+void Config::LoadThFile() {
+ const int NBARG = 6;
+ char *cut[NBARG] = {NULL};
+ FILE *file;
+ char ligne[50];
+ int i;
+ unsigned char *pColor;
+
+ // Ouverture du fichier de conf
+ file = fopen("threshold", "r");
+ if (!file) {
+ cerr << "Config::LoadThFile : Error during config file opening\n" << endl;
+ return;
+ }
+
+ // Nombre de couleurs contenu dans le fichier
+ int numColor=0;
+ while(fgets(ligne, 50,file))
+ numColor++;
+
+ if (color) delete [] color;
+ color = new unsigned char[numColor*3*2];
+
+ // Parcours des lignes et analyse
+ numColor=0;
+ rewind(file);
+ while(fgets(ligne, 50, file)) {
+ if (ligne[0] == '#') continue;
+
+ // Division du string
+ cut[0] = strtok(ligne, " \t\n");
+ if (!cut[0]) continue;
+ i=0;
+ pColor = &color[numColor*6];
+ pColor[0] = (unsigned char)atoi(cut[0]);
+ while ((cut[i] != NULL) && (i<(NBARG-1))) {
+ i++;
+ cut[i] = strtok( NULL, " \t\n");
+ pColor[i] = (unsigned char)atoi(cut[i]);
+ }
+ numColor++;
+ }
+
+ nbCouleurMax = numColor;
+
+ fclose(file);
+}
+
+
+
+/// Chargement de la table des distances
+void Config::LoadDistFile(char *filename, int **tab, int &height, int &width) {
+
+ FILE *file;
+
+ // Ouverture du fichier de distance
+ file = fopen(filename, "rb");
+ if (!file) {
+ cerr << "Config::LoadDistFile : Error during poids file opening" << endl;
+ return;
+ }
+
+ fwrite(&height, 1, sizeof(int), file);
+ fwrite(&width, 1, sizeof(int), file);
+
+ if (*tab) delete[] *tab;
+ *tab = new int[height*width];
+
+ fwrite(*tab, height*width, sizeof(int), file);
+ fclose(file);
+
+}
+
+/// Creation d'un fichier pour la table des distances
+void Config::CreateDistFile(char *filename, int *tab, int height, int width) {
+
+ if (!tab) {
+ cerr << "Config::CreateDistFile : tab vide\n";
+ return;
+ }
+
+ // Ecriture dans un fichier
+ FILE *file;
+ file = fopen(filename, "wb+");
+
+ fwrite(&height, 1, sizeof(int), file);
+ fwrite(&width, 1, sizeof(int), file);
+ fwrite(tab, height*width, sizeof(int), file);
+ fclose(file);
+}
+
+
+
+/// Destructor
+Config::~Config()
+{
+}
+
+
+
diff --git a/2004/i/nono/src/ovision/config.h b/2004/i/nono/src/ovision/config.h
new file mode 100644
index 0000000..d9b090b
--- /dev/null
+++ b/2004/i/nono/src/ovision/config.h
@@ -0,0 +1,138 @@
+#ifndef config_h
+#define config_h
+// config.h - classe Config
+// nono - Programme du robot Efrei Robotique I1-I2 2004
+// Copyright (C) 2004 Olivier Gaillard
+
+
+/// Constantes pour les modes d'espace de couleur
+#define RGB 0
+#define YUV 1
+#define HSI 2
+
+
+/// Constantes pour les sources d'acquisition
+#define SOURCE_FILE 0
+#define SOURCE_USB_CAM 1
+#define SOURCE_CAM 2
+
+
+
+/// Charge le fichier config et distribue les variables
+class Config {
+
+ public:
+ /// hauteur de l'image
+ unsigned int height;
+
+ /// largeur de l'image
+ unsigned int width;
+
+ /// source d'aquisition
+ int source;
+
+ /// nombre d'iteration pour l'apprentissage(number iteration learning)
+ long nn_nil;
+
+ /// vitesse d'apprentissage (step learning)
+ float nn_sl;
+
+ /// influence sur les voisins pour l'apprentissage (neighborhood learning)
+ float nn_nl;
+
+ /// seuil pour la verification des noeuds de sorties inutiles du reseau
+ unsigned int nn_lazy_threshold;
+
+ /// nombre de couleurs a detecter
+ int nn_NbCouleurs;
+
+ /// nombre de couleurs dans le fichier des seuils
+ int nbCouleurMax;
+
+ /// nombre de couleurs dans le fichier des poids
+ int nbNodeMax;
+
+ /// influence de la luminosite dans l'integration de l'image
+ float nn_influ_lum;
+
+ /// erreur accepte pour la construction de la map
+ int map_error;
+ int map_error_part;
+
+ /// Position de la balle (devant, derriere, cote, ...)
+ int angle_ball_weight;
+
+ /// Distance Balle-Robot
+ int distance_ball_robot_weight;
+
+ /// Distance Balle_goal
+ int distance_ball_goal_weight;
+
+ /// Densite de balles dans la zone
+ int ball_density_weight;
+
+ /// Presence du robot adverse dans la zone
+ int ennemy_presence_weight;
+
+ /// Precision de la position de la balle
+ int ball_precision_weight;
+
+ /// Viabilite de l'information
+ int skepticism_weight;
+
+ /// Max de la valeur
+ int skepticism_max;
+
+ /// mode de couleur (RGB, YUV, HSI)
+ int colorMode;
+
+ /// numero de la couleur des balles a chercher
+ int groupColor;
+
+ /// numero de la couleur des poteaux a chercher
+ int goalColor;
+
+ /// tableau de correspondances des couleurs RGB
+ unsigned char *color;
+
+ /// tableau des poids du reseau de neurones
+ unsigned char *node;
+
+ /// tableau d'index des couleurs a melanger (merge)
+ int *index;
+
+ /// Chemin d'acces des images
+ char imgPath[30];
+
+ /// Constructeur
+ Config (char *filename);
+
+ /// Destructeur
+ ~Config (void);
+
+ /// Chargement d'un fichier de seuils
+ void LoadThFile();
+
+ /// Chargement de poids pour le reseau de neurone
+ void LoadNNFile(char *filePath);
+
+ /// Chargement de poids pour le reseau de neurone
+ void LoadNNFile() {LoadNNFile("poids");}
+
+ /// Creation d'un fichier de poids pour le reseau de neurones
+ void CreateNNFile(const char *file, int mode, int nbOutput);
+
+ /// Creatio du fichier de la table de distance
+ void CreateDistFile(char *filename, int *tab, int height, int width);
+
+ /// Chargement du fichier de la table de distance
+ void LoadDistFile(char *filename, int **tab, int &height, int &width);
+
+ protected:
+ /// Parse une ligne du fichier de config
+ void Parse(char *var, char *arg);
+
+};
+
+
+#endif // config_h
diff --git a/2004/i/nono/src/ovision/group.cc b/2004/i/nono/src/ovision/group.cc
new file mode 100644
index 0000000..603dd70
--- /dev/null
+++ b/2004/i/nono/src/ovision/group.cc
@@ -0,0 +1,235 @@
+// group.cc - Classe Group
+// nono - Programme du robot Efrei Robotique I1-I2 2004
+// Copyright (C) 2004 Olivier Gaillard
+
+/// @file group.cc Cree une liste chainee de zones correspondant aux balles
+
+#include "group.h"
+#include <iostream>
+#include <stdlib.h>
+#include <math.h>
+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; x<width; x+=10) {
+ for (unsigned int y=0; y<height; y+=10) {
+ if (tabSegm[y*width+x] == numColor)
+ Plague(BALL, numColor, x, y);
+ }
+ }
+
+}
+
+
+/// Creation du tableau de RGB pour faire une image
+void Group::TabOut() {
+ ZONE *pCur = zoneListBall;
+
+ // On verifie que des groupes ont ete trouve
+ if (!pCur) {
+ cerr << "Group::TabOut : No group defined" << endl;
+ if (tabOut) delete [] tabOut;
+ return;
+ }
+
+ // Allocation de la memoire
+ if (tabOut) delete [] tabOut;
+ tabOut = new unsigned char[img->nbPixels];
+
+ // On initialise le tableau pour une image noire
+ for (unsigned int i=0; i<img->nbPixels; 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; i<pCur->xmax; i++)
+ for (unsigned int j=pCur->ymin; j<pCur->ymax; 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 <iostream>
+#include <stdlib.h>
+#include <math.h>
+using namespace std;
+/// Renvoie le minimum entre 2 nombres
+inline unsigned char min(unsigned char a, unsigned char b) {
+ if (a<b) return a;
+ else return b;
+}
+
+/// Constructeur
+Img::Img (void) {
+ // Initialisation des variables
+ tabData = NULL;
+ tabSegm = NULL;
+
+ yuv = hsi = 0;
+
+}
+
+/// Destructeur
+Img::~Img (void) {
+ //free tabData
+ if (tabData) delete [] tabData;
+
+}
+
+
+
+/// Convertit un tableau de donnees RGB en YUV
+void Img::RGBtoYUV() {
+ unsigned char r,g,b;
+
+ yuv = 1;
+
+ // Parcours du tableau et conversion des valeurs RBG en YUV
+ for (unsigned long i=0; i<nbPixels; i++) {
+ r = tabData[i*3];
+ g = tabData[i*3+1];
+ b = tabData[i*3+2];
+
+ tabData[i*3] = (unsigned char)(0.299*r + 0.587*g + 0.114*b); // Y
+ tabData[i*3+1] = (unsigned char)(0-0.147*r - 0.289*g + 0.437*b + 0.5); // U
+ tabData[i*3+2] = (unsigned char)(00.615*r - 0.515*g - 0.100*b + 0.5); // V
+ }
+}
+
+/// Convertit un tableau de donnees RGB en YUV
+void Img::RGBtoHSI() {
+ unsigned char r,g,b;
+
+ hsi = 1;
+
+ // Parcours du tableau et conversion des valeurs RBG en HSI
+ for (unsigned long i=0; i<nbPixels; i++) {
+ r = tabData[i*3];
+ g = tabData[i*3+1];
+ b = tabData[i*3+2];
+
+ tabData[i*3] = (unsigned char)(acos((r-0.5f*g-0.5f*b)/(sqrt(1.0f*(r-g)*(r-g)+(r-b)*(g-b))))); // H
+ tabData[i*3+1] = (unsigned char)(1-min(min(r,g),b)); // S
+ tabData[i*3+2] = (unsigned char)(0.33f*(r+g+b)); // I
+ }
+}
+
+/// Ecrit les valeurs RGB dans un fichier
+void Img::WriteRGB(char *filename) {
+
+ FILE *file;
+ file = fopen(filename, "w+");
+
+ fwrite(tabData, 3, width*height, file);
+
+ fclose(file);
+}
+
diff --git a/2004/i/nono/src/ovision/img.h b/2004/i/nono/src/ovision/img.h
new file mode 100644
index 0000000..877f7b7
--- /dev/null
+++ b/2004/i/nono/src/ovision/img.h
@@ -0,0 +1,61 @@
+#ifndef img_h
+#define img_h
+// img.h - classe Image
+// nono - Programme du robot Efrei Robotique I1-I2 2004
+// Copyright (C) 2004 Olivier Gaillard
+
+
+// Chargement des librairies DevIL
+#include "config.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 Img
+{
+ /// numero IL de l'image
+ unsigned int ImgId;
+
+ public:
+ /// tableau avec couleurs segmentees
+ unsigned char *tabSegm;
+
+ /// dimension de l'image
+ unsigned int height, width;
+
+ /// nombres de pixels de l'image
+ unsigned long nbPixels;
+
+ /// tableau des couleurs RGB bruts
+ unsigned char *tabData;
+
+ /// mode de l'espace de couleurs
+ char yuv,hsi;
+
+ /// Constructeur
+ Img (void);
+
+ /// Destructeur
+ virtual ~Img (void);
+
+ /// Lis une image en utilisant le peripherique adequate (fichier, cam usb, cam)
+ virtual int ReadRaw(char *sourcePath) = 0;
+
+ /// Ecriture de l'image sur le disque
+ virtual void WriteSegm(char *filename, unsigned char *tabSegm) = 0;
+ virtual void WriteSegm(char *filename) = 0;
+
+ /// Conversion en YUV
+ void RGBtoYUV();
+
+ /// Conversion en HSI
+ void RGBtoHSI();
+
+ /// Ecrite des valeurs RGB dans un fichier
+ void WriteRGB(char *filename);
+
+ protected:
+};
+
+
+
+#endif // img_h
diff --git a/2004/i/nono/src/ovision/imgFile.cc b/2004/i/nono/src/ovision/imgFile.cc
new file mode 100644
index 0000000..1ee5df6
--- /dev/null
+++ b/2004/i/nono/src/ovision/imgFile.cc
@@ -0,0 +1,137 @@
+// imgFile.cc - Classe Image
+// nono - Programme du robot Efrei Robotique I1-I2 2004
+// Copyright (C) 2004 Olivier Gaillard
+
+/// @file imgFile.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 "imgFile.h"
+#include <iostream>
+#include <stdlib.h>
+#include <math.h>
+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 <IL/il.h>
+#include <IL/ilu.h>
+
+#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 <iostream>
+#include <math.h>
+#include <list>
+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<BALL>::iterator &iter)
+{
+ ball.erase(iter);
+}
+
+/// Test si une balle trouvee correspond a une balle de la map
+int
+Map::TestSimilarBall(ZONE *pBall, list<BALL>::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<BALL>::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<BALL>::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<BALL>::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 <list>
+#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> ball;
+
+ /// Balle ayant le plus haut score
+ std::list<BALL>::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<BALL>::iterator &iter);
+
+ /// Test si une balle trouvà correspond a une balle de la map
+ int TestSimilarBall(ZONE *pBall , std::list<BALL>::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 <IL/il.h>
+#include <IL/ilu.h>
+
+#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 <iostream>
+#include <stdlib.h>
+#include <math.h>
+#include <time.h>
+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; i<nbOutput; i++)
+ printf("\t%u %u %u\n", node[i*3], node[i*3+1], node[i*3+2]);
+ cout << endl;
+}
+
+
+/// Construit un reseau de neurones
+
+/// @param nbOutput nombre de noeuds de la couche de sortie du NN
+/// @param loadFromFile (GENERATE ou LOADFROMFILE) indique si les poids sont charges d'un fichier ou generes aleatoirement
+void SegmNN::BuildNN(int nbOutput, int loadFromFile) {
+
+ SegmNN::nbOutput = nbOutput;
+
+ // Permet de charger les poids du NN depuis un fichier ou en les initialisant aleatoirement
+ if (loadFromFile) {
+ // Verifie si le nombre de poids donne dans le fichier est suffisant
+ if (config->nbNodeMax < 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<nbOutput; i++) {
+ index[i] = i;
+ freq[i] = 0;
+
+ for(int j=0; j<3; j++) {
+ // Attribution aléatoire des poids
+ node[i*3+j] = (unsigned char) (255.0*rand()/(RAND_MAX+1.0));
+ if (node[i*3+j] < 30) node[i*3+j] = 30;
+ else if (node[i*3+j] > 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; i<config->nn_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; j<nbOutput; j++) {
+ output[j] = 0;
+
+ for(int k=0; k<3; k++) {
+ if ((img->yuv && 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; j<nbOutput; j++) {
+ output[j] = 0;
+
+ for(int k=0; k<3; k++) {
+ if ((img->yuv && 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; i<img->nbPixels; 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; i<img->nbPixels; 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 <iostream>
+#include <stdlib.h>
+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; i<nbOutput; i++) {
+ weight[i][comp] = i;
+
+ int j=i;
+ while ((j>0) && (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; i<nbOutput; i++) {
+ if (i==0) {
+ seuil[weight[i][comp]][comp][MIN] = 0;
+ seuil[weight[i][comp]][comp][MAX] =
+ node[weight[i][comp]*3+comp]-(node[weight[i][comp]*3+comp]-node[weight[i+1][comp]*3+comp])/2;
+
+ }
+ else if (i==nbOutput-1) {
+ seuil[weight[i][comp]][comp][MIN] =
+ node[weight[i][comp]*3+comp]-(node[weight[i][comp]*3+comp]-node[weight[i-1][comp]*3+comp])/2;
+ seuil[weight[i][comp]][comp][MAX] = 255;
+ }
+ else {
+ seuil[weight[i][comp]][comp][MIN] =
+ node[weight[i][comp]*3+comp]-(node[weight[i][comp]*3+comp]-node[weight[i-1][comp]*3+comp])/2;
+ seuil[weight[i][comp]][comp][MAX] =
+ node[weight[i][comp]*3+comp]-(node[weight[i][comp]*3+comp]-node[weight[i+1][comp]*3+comp])/2;
+ }
+ }
+ }
+
+
+
+ // Ecriture dans un fichier
+ FILE *file;
+ file = fopen(filename, "w+");
+
+ fprintf(file, "#x1Min\tx1Max\tx2Min\tx2Max\tx3Min\tx3Max\n");
+ for (int i=0; i<nbOutput; i++) {
+ for (int j=0; j<3; j++)
+ fprintf(file, "%u\t%u\t", seuil[i][j][MIN], seuil[i][j][MAX]);
+ fprintf(file, "\n");
+
+ }
+
+ fclose(file);
+}
+
+
+unsigned char SegmTh::FindzoneTh (unsigned char *x) {
+ unsigned char *pColor;
+
+ // Parcours de toutes les couleurs possibles
+ for (int i=0; i<nbOutput; i++) {
+ pColor = &config->color[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 <math.h>
+
+#include "imgFile.h"
+#include "segmNN.h"
+#include "group.h"
+
+using namespace std;
+/*namespace std
+{
+struct less<TABLOC*> {
+ 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<TABLOC>::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<BALL>);
+
+ /*
+ // 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 <vector>
+#include <iostream>
+#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<TABLOC> tabLocX;
+ std::vector<TABLOC> 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 <iostream>
+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 <iostream>
+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 <iostream>
+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 <stdio.h>
+
+
+
+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 <iostream>
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <signal.h>
+
+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 <iostream>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <signal.h>
+
+#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<config.nn_NbCouleurs; i++)
+ {
+ colorName[i] = new char[20];
+ if (type == NUM_COULEUR)
+ sprintf(colorName[i], "Couleur %i", i);
+ else if (type == NB_COULEUR)
+ sprintf(colorName[i], "%i", i);
+ colorItem[i] = new_item(colorName[i] , NULL);
+ }
+ colorName[config.nn_NbCouleurs] = new char[20];
+ sprintf(colorName[config.nn_NbCouleurs], "Annuler");
+ colorItem[config.nn_NbCouleurs] = new_item(colorName[config.nn_NbCouleurs] , NULL);
+ colorItem[config.nn_NbCouleurs+1] = NULL;
+
+ // Creation de la fenetre
+ WINDOW *colorWindow = newwin(11, 15, 9, 35);
+ keypad(colorWindow, TRUE);
+
+ // Creation du menu
+ MENU *colorMenu = new_menu(colorItem);
+ set_menu_win(colorMenu, colorWindow);
+ set_menu_mark(colorMenu, " -> ");
+ 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<config.nn_NbCouleurs; i++)
+ free_item(colorItem[i]);
+ free_menu(colorMenu);
+ delwin(colorWindow);
+ colorWindow = newwin(11, 15, 9, 35);
+ wrefresh(colorWindow);
+ delwin(colorWindow);
+ delete [] colorName;
+
+ // Retourne la valeur choisie par l'utilisateur
+ return col;
+}
+
+
+
+/// Menu de melange de couleurs
+void
+UI::GoMergeWindow()
+{
+ ITEM **items;
+ char **mergeName;
+
+ // Creation des items
+ ITEM **mergeItem = new ITEM*[config.nn_NbCouleurs+2];
+ mergeName = new char*[config.nn_NbCouleurs+1];
+ for (int i=0; i<config.nn_NbCouleurs; i++)
+ {
+ mergeName[i] = new char[20];
+ sprintf(mergeName[i], "Couleur %i (%i)", i, config.index[i]);
+ mergeItem[i] = new_item(mergeName[i] , NULL);
+ }
+
+ // Ajout du choix unmerge a la fin du menu
+ mergeName[config.nn_NbCouleurs] = new char[20];
+ strcpy(mergeName[config.nn_NbCouleurs], "Unmerge all");
+ mergeItem[config.nn_NbCouleurs] = new_item(mergeName[config.nn_NbCouleurs], NULL);
+ mergeItem[config.nn_NbCouleurs+1] = NULL;
+
+ // Creation de la fenetre
+ WINDOW *mergeWindow = newwin(10, 20, 9, 35);
+ keypad(mergeWindow, TRUE);
+
+ // Creation du menu
+ MENU *mergeMenu = new_menu(mergeItem);
+ set_menu_win(mergeMenu, mergeWindow);
+ set_menu_mark(mergeMenu, " -> ");
+ 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<config.nn_NbCouleurs; i++)
+ config.index[i] = i;
+
+ // Fin de la boucle
+ end = 1;
+ nbColorToMerge++;
+ }
+ else
+ {
+ // Parcours des items du menu
+ for (int i=0; i< item_count(mergeMenu)-1; i++)
+ // Si il on ete valide on les ajoute a la string
+ if (item_value(items[i]) == TRUE)
+ {
+ // Memorisation du premier index trouve pour
+ // le copier dans les autres couleurs choisies
+ if (indexColor == -1) indexColor = config.index[i];
+ sprintf(tmp, " %i", i);
+ strcat(buf, tmp);
+ nbColorToMerge++;
+ config.index[i]= indexColor;
+ }
+
+ // Flag de fin de boucle
+ end = 1;
+ }
+ break;
+ }
+
+ if (col != config.nn_NbCouleurs)
+ {
+ // Cree une image de la couleur selectionnee
+ sprintf(cmd, "s %i\n", col);
+ SendSignal(cmd);
+ }
+ }
+
+ if (nbColorToMerge)
+ {
+ // Cas ou unmerge a ete selectionne
+ if (indexColor == -1)
+ {
+ // Envoie un signal
+ sprintf(cmd, "m %i\n", -1);
+ SendSignal(cmd);
+
+ // Affichage d'info
+ sprintf(cmd, "Les index des couleurs ont ete remises a zero");
+ PrintStatus(cmd);
+ }
+ else
+ {
+ // Finition de la chaine a envoye
+ strcat(buf, "\n");
+ sprintf(cmd, "m %i", nbColorToMerge);
+ strcat(cmd, buf);
+
+ // Envoie du signal
+ SendSignal(cmd);
+
+ // Affichage d'info
+ sprintf(cmd, "Les couleurs melangees sont %s", buf+1);
+ PrintStatus(cmd);
+ }
+ }
+ else PrintStatus("Pas de couleur selectionnee\n");
+ wrefresh(mergeWindow);
+
+
+ // Liberation memoire
+ for(int i=0; i<config.nn_NbCouleurs; i++)
+ free_item(mergeItem[i]);
+ free_menu(mergeMenu);
+ delwin(mergeWindow);
+ mergeWindow = newwin(10, 20, 9, 35);
+ wrefresh(mergeWindow);
+ delwin(mergeWindow);
+ delete [] mergeName;
+}
+
+
+
+/// Menu de suppression de couleur
+void
+UI::GoDelColor()
+{
+ // Menu de sélection de couleur
+ int numColor = ChooseColor(NUM_COULEUR);
+
+ // Annulation
+ if (numColor < 0) return;
+
+ // Envoie du signal
+ char buf[50];
+ sprintf(buf, "d %i\n", numColor);
+ SendSignal(buf);
+
+ // On supprime la couleur en local
+ unsigned char *pCur;
+ pCur = &config.node[numColor*3];
+ for(int i=numColor*3; i<config.nn_NbCouleurs*3; i++)
+ {
+ *(pCur) = *(pCur+3);
+ pCur++;
+ }
+
+ config.nn_NbCouleurs--;
+
+ // Affichage d'info
+ sprintf(buf, "Couleur %i supprimee\n", numColor);
+ PrintStatus(buf);
+}
+
+
+
+/// Menu de selection du group a former
+void
+UI::GoSelectGroup(int type)
+{
+ // Menu de selection de couleur
+ int tmp = ChooseColor(NUM_COULEUR, config.groupColor);
+
+ if (tmp != -1)
+ {
+ if (type == BALL)
+ {
+
+ config.groupColor = tmp;
+
+ // Envoie d'un signal avec la valeur choisie
+ char buf[50];
+ sprintf(buf, "g %i\n", tmp);
+ SendSignal(buf);
+ }
+ else if (type == GOAL)
+ {
+ config.goalColor = tmp;
+ }
+ }
+}
+
+
+
+/// Menu de suppression de couleur
+void
+UI::GoChangeColor()
+{
+ unsigned char c[3];
+ int ligne=0;
+ char cmd[50];
+
+ // Menu de sélection de couleur
+ int col = ChooseColor(NUM_COULEUR);
+
+ // Annulation
+ if (col < 0) return;
+
+ // Affectation des composantes actuelles
+ for (int i=0; i<3; i++)
+ c[i] = config.node[col*3+i];
+
+ // Création de la fenetre
+ WINDOW *colorWindow = newwin(4, 60, 12, 25);
+ keypad(colorWindow, TRUE);
+
+ // Initialisation de l'affichage
+ wprintw(colorWindow, "Couleur %i:\n", col);
+ wprintw(colorWindow, "<---------------------------------------------------->\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<NBITEMS; i++)
+ item[i] = new_item(itemsName[i][0], NULL);
+
+ // Init window
+ mainWindow = newwin(20, 75, 2, 2);
+ keypad(mainWindow, TRUE);
+
+ // Init titre
+ wattron(mainWindow, COLOR_PAIR(2));
+ wprintw(mainWindow, "Adjust - Efrei Robotique");
+ wattroff(mainWindow, COLOR_PAIR(2));
+ mvwhline(mainWindow,1,0,ACS_HLINE, 25);
+
+ // Init menus
+ menu = new_menu(item);
+ set_menu_mark(menu, " -> ");
+ 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