summaryrefslogtreecommitdiff
path: root/2004/i/nono/src/vision
diff options
context:
space:
mode:
Diffstat (limited to '2004/i/nono/src/vision')
-rw-r--r--2004/i/nono/src/vision/Makefile.defs11
-rw-r--r--2004/i/nono/src/vision/image.cc344
-rw-r--r--2004/i/nono/src/vision/image.h48
-rw-r--r--2004/i/nono/src/vision/rgbyuv.h57
-rw-r--r--2004/i/nono/src/vision/test_image.cc34
-rw-r--r--2004/i/nono/src/vision/test_vision.cc48
-rw-r--r--2004/i/nono/src/vision/thresholds.cc55
-rw-r--r--2004/i/nono/src/vision/thresholds.h42
8 files changed, 639 insertions, 0 deletions
diff --git a/2004/i/nono/src/vision/Makefile.defs b/2004/i/nono/src/vision/Makefile.defs
new file mode 100644
index 0000000..e13c735
--- /dev/null
+++ b/2004/i/nono/src/vision/Makefile.defs
@@ -0,0 +1,11 @@
+TARGETS += test_image test_vision
+LIBS += vision.a
+test_vision_SOURCES = test_vision.cc vision.a camera.a config.a date.a erreur.a $(LIBPPM)
+test_image_SOURCES = test_image.cc vision.a camera.a config.a date.a erreur.a $(LIBPPM)
+vision_a_SOURCES = image.cc thresholds.cc
+
+test_image: $(test_image_SOURCES:%.cc=%.o)
+
+test_vision: $(test_vision_SOURCES:%.cc=%.o)
+
+vision.a: ${vision_a_SOURCES:%.cc=vision.a(%.o)}
diff --git a/2004/i/nono/src/vision/image.cc b/2004/i/nono/src/vision/image.cc
new file mode 100644
index 0000000..f91e9e6
--- /dev/null
+++ b/2004/i/nono/src/vision/image.cc
@@ -0,0 +1,344 @@
+// image.cc - Classe Image
+// buzz - Programme du robot Efrei Robotique I1-I2 2003
+// Copyright (C) 2003 Nicolas Schodet
+#include "image.h"
+
+extern "C" {
+#include <ppm.h>
+};
+
+// Attention, l'un des paramètres est evalué deux fois.
+#define min(a,b) ((a) < (b) ? (a) : (b))
+#define max(a,b) ((a) > (b) ? (a) : (b))
+
+// Constructeurs.
+Image::Image (const char *filename, const Thresholds *thresholds)
+{
+ pixel **img;
+ pixel *p;
+ pixval maxval;
+ int x, y, w, h;
+ FILE *fp;
+ unsigned char *pi;
+ // Open the file.
+ fp = fopen (filename, "r");
+ if (!fp) throw "Image::Image: fopen failled";
+ // Read it.
+ img = ppm_readppm (fp, &w, &h, &maxval);
+ // Close it.
+ fclose (fp);
+ if (!img) throw "Image::Image: ppm_readppm failled";
+ // Allocate memory...
+ m_image = new unsigned char [w*h*4];
+ m_width = w;
+ m_height = h;
+ // Extrait les info RGB ou YUV.
+ pi = m_image;
+ for (y = 0; y < h; y++)
+ {
+ p = img[y];
+ for (x = 0; x < w; x++)
+ {
+ *pi++ = (unsigned char) (PPM_GETB (*p) * 255 / maxval);
+ *pi++ = (unsigned char) (PPM_GETG (*p) * 255 / maxval);
+ *pi++ = (unsigned char) (PPM_GETR (*p) * 255 / maxval);
+ *pi++ = 0;
+ p++;
+ }
+ }
+ // Alloue de la memoire pour les zones.
+ m_zones = new unsigned char [m_width * m_height];
+ // Initalisation
+ m_groups = 0;
+ m_thresholds = thresholds;
+ m_camera = 0;
+}
+
+Image::Image (Camera *camera, const Thresholds *thresholds)
+{
+ // Copie la camera.
+ m_camera = camera;
+ // Allocate memory...
+ m_camera->getSize (m_width, m_height);
+ m_image = new unsigned char [m_width * m_height * 4];
+ // Alloue de la memoire pour les zones.
+ m_zones = new unsigned char [m_width * m_height];
+ // Initalisation
+ m_groups = 0;
+ m_thresholds = thresholds;
+}
+
+// Destructeur
+Image::~Image (void)
+{
+ ImageGroup *g, *g2;
+ if (m_image) delete [] m_image;
+ if (m_zones) delete [] m_zones;
+ for (g = m_groups; g; g = g2)
+ {
+ g2 = g->next;
+ delete g;
+ }
+}
+
+// Filtre l'image pour trouver les zones.
+void Image::filter (void)
+{
+ int i;
+ unsigned char *pz, *pi;
+ unsigned char r, g, b;
+ // Filtre.
+ pz = m_zones;
+ pi = m_image;
+ for (i = 0; i < m_width * m_height; i++)
+ {
+ b = *pi++;
+ g = *pi++;
+ r = *pi++;
+ pi++;
+ *pz++ = m_thresholds->findZone (r, g, b);
+ }
+}
+
+// Group les groupes de pixels.
+void Image::group (void)
+{
+ // c: group courant, n: group suivant (chercheur).
+ ImageGroup *c, **n, *n2;
+ // Supprime tous les groupes.
+ for (c = m_groups; c; c = n2)
+ {
+ n2 = c->next;
+ delete c;
+ }
+ // Fait des groupes de pixels.
+ groupLine ();
+ for (c = m_groups; c; c = c->next)
+ {
+ n = &c->next;
+ // Recherche des groups plus bas dans l'image qui sont colle au groupe
+ // courant.
+ while (*n && (*n)->y <= c->y + c->h)
+ {
+ // Si ils sont de la même zone et qu'ils se touchent (avec au
+ // moins 5 pixels), on les rassemble en 1 groupe.
+ if (c->zone == (*n)->zone
+ && (*n)->x < c->x + c->w - 5
+ && c->x < (*n)->x + (*n)->w - 5)
+ {
+ // Dechainage de n.
+ n2 = (*n);
+ *n = n2->next;
+ // Mise a jour de c.
+ c->h++;
+ c->w = max (c->x + c->w, n2->x + n2->w) - min (c->x, n2->x);
+ c->x = min (c->x, n2->x);
+ // Supression de n.
+ delete n2;
+ }
+ else
+ n = &(*n)->next;
+ }
+ }
+}
+
+// Fait des packets de pixels sur les lignes.
+void Image::groupLine (void)
+{
+ unsigned char zone;
+ int n, y, x, sx;
+ ImageGroup **p;
+ unsigned char *pz;
+ pz = m_zones;
+ p = &m_groups;
+ for (y = 0; y < m_height; y++)
+ {
+ // Pour chaque ligne.
+ n = 0;
+ zone = 0;
+ for (x = 0; x < m_width; x++)
+ {
+ if (n == 0)
+ {
+ // Nouvelle zone.
+ sx = x;
+ zone = *pz;
+ n = 1;
+ }
+ else
+ {
+ if (zone == *pz)
+ {
+ // Même zone.
+ n++;
+ }
+ else
+ {
+ // Zone differente.
+ if (zone && n > 5)
+ {
+ *p = new ImageGroup;
+ (*p)->x = sx;
+ (*p)->y = y;
+ (*p)->w = n;
+ (*p)->h = 1;
+ (*p)->zone = zone;
+ (*p)->type = 0;
+ p = &(*p)->next;
+ }
+ n = 0;
+ zone = *pz;
+ }
+ }
+ pz++;
+ }
+ // Dernier groupe, si assez grand.
+ if (zone && n > 5)
+ {
+ *p = new ImageGroup;
+ (*p)->x = sx;
+ (*p)->y = y;
+ (*p)->w = n;
+ (*p)->h = 1;
+ (*p)->zone = zone;
+ (*p)->type = 0;
+ p = &(*p)->next;
+ }
+ }
+ *p = 0;
+}
+
+// Affiche les groupes qui on été trouvés.
+void
+Image::dumpGroups (void)
+{
+ ImageGroup *g;
+ printf ("Groups\n");
+ for (g = m_groups; g; g = g->next)
+ {
+ printf ("x: %d, y: %d, w: %d, h: %d, z: %d, t: %d\n", g->x, g->y,
+ g->w, g->h, g->zone, g->type);
+ }
+}
+
+// Filtre les packets de pixels.
+void
+Image::groupFilter (void)
+{
+ ImageGroup **g, *g2;
+ g = &m_groups;
+ while (*g)
+ {
+ g2 = *g;
+ // Trouve le type de palet.
+ g2->type = 1; // TODO : trouver le type du palet.
+ // Vire les groupes qu'on ne voix pas en entier ou d'une taille bizare.
+ if (g2->type == 0
+ //|| g2->x <= 0 || g2->x + g2->w >= m_width
+ //|| g2->y <= 0 || g2->y + g2->h >= m_height)
+ )
+ {
+ *g = g2->next;
+ delete g2;
+ }
+ else
+ {
+ g = &g2->next;
+ }
+ }
+}
+
+// Enregistre les infos trouvées.
+void
+Image::dump (const char *filename)
+{
+ pixel *row;
+ pixel *pr;
+ int x, y;
+ FILE *fp;
+ unsigned char *p;
+ int r, g, b;
+ ImageGroup *pg;
+ // Open the file.
+ fp = fopen (filename, "w");
+ if (!fp) throw "Image::dump: fopen failled";
+ // Allocate memory...
+ row = ppm_allocrow (m_width);
+ // Sauve l'image.
+ ppm_writeppminit (fp, m_width, m_height * 3, 255, 0);
+ // image.
+ p = m_image;
+ for (y = 0; y < m_height; y++)
+ {
+ pr = row;
+ for (x = 0; x < m_width; x++)
+ {
+ b = *p++;
+ g = *p++;
+ r = *p++;
+ p++;
+ PPM_ASSIGN (*pr, r, g, b);
+ pr++;
+ }
+ ppm_writeppmrow (fp, row, m_width, 255, 0);
+ }
+ // Sauve les zones.
+ p = m_zones;
+ for (y = 0; y < m_height; y++)
+ {
+ pr = row;
+ for (x = 0; x < m_width; x++)
+ {
+ r = *p == 1 ? 255 : 0;
+ g = *p == 2 ? 255 : 0;
+ b = 0;
+ p++;
+ PPM_ASSIGN (*pr, r, g, b);
+ pr++;
+ }
+ ppm_writeppmrow (fp, row, m_width, 255, 0);
+ }
+ // Sauve les groupes.
+ for (y = 0; y < m_height; y++)
+ {
+ pr = row;
+ for (x = 0; x < m_width; x++)
+ {
+ r = g = b = 0;
+ for (pg = m_groups; pg; pg = pg->next)
+ {
+ if (x >= pg->x && x < pg->x + pg->w
+ && y >= pg->y && y < pg->y + pg->h)
+ {
+ if (pg->zone == 1)
+ r = 255;
+ else if (pg->zone == 2)
+ g = 255;
+ else
+ b = 255;
+ }
+ }
+ PPM_ASSIGN (*pr, r, g, b);
+ pr++;
+ }
+ ppm_writeppmrow (fp, row, m_width, 255, 0);
+ }
+ // Free memory.
+ ppm_freerow (row);
+ // Close it.
+ fclose (fp);
+}
+
+// Relit les données de la camera et fait les analyses.
+bool
+Image::reread (void)
+{
+ // Lit l'image.
+ if (m_camera->read (m_image) == 0)
+ return false;
+ filter ();
+ group ();
+ groupFilter ();
+ return true;
+}
+
diff --git a/2004/i/nono/src/vision/image.h b/2004/i/nono/src/vision/image.h
new file mode 100644
index 0000000..4177f81
--- /dev/null
+++ b/2004/i/nono/src/vision/image.h
@@ -0,0 +1,48 @@
+#ifndef image_h
+#define image_h
+// image.h - Image class
+// buzz - Programme du robot Efrei Robotique I1-I2 2003
+// Copyright (C) 2003 Nicolas Schodet
+
+#include "thresholds.h"
+#include "camera/camera.h"
+
+struct ImageGroup
+{
+ ImageGroup *next;
+ int x, y, w, h;
+ int zone, type;
+};
+
+class Image
+{
+ int m_width, m_height;
+ unsigned char *m_image;
+ unsigned char *m_zones;
+ ImageGroup *m_groups;
+ const Thresholds *m_thresholds;
+ Camera *m_camera;
+ public:
+ // Constructeurs.
+ Image (const char *filename, const Thresholds *thresholds);
+ Image (Camera *camera, const Thresholds *thresholds);
+ // Destructeur.
+ ~Image (void);
+ // Filtre l'image pour trouver les zones.
+ void filter (void);
+ // Fait des packets de pixels.
+ void group (void);
+ // Affiche les groupes qui on été trouvés.
+ void dumpGroups (void);
+ // Enregistre les infos trouvées.
+ void dump (const char *filename);
+ // Filtre les packets de pixels.
+ void groupFilter (void);
+ // Relit les données de la camera et fait les analyses.
+ bool reread (void);
+ protected:
+ // Fait des packets de pixels sur les lignes.
+ void groupLine (void);
+};
+
+#endif // image_h
diff --git a/2004/i/nono/src/vision/rgbyuv.h b/2004/i/nono/src/vision/rgbyuv.h
new file mode 100644
index 0000000..104c309
--- /dev/null
+++ b/2004/i/nono/src/vision/rgbyuv.h
@@ -0,0 +1,57 @@
+#ifndef rgbyuv_h
+#define rgbyuv_h
+// rgbyuv.h - Convertions RGB <-> YUV
+// buzz - Programme du robot Efrei Robotique I1-I2 2003
+// Copyright (C) 2003 Nicolas Schodet
+
+// TODO: Implementer une version plus rapide avec des tableaux ???
+// Pas pour le momment, on utilise pas YUV.
+
+class RgbYuv
+{
+ public:
+ // Convertie un pixel RGB en YUV.
+ static void rgbToYuv (unsigned char r, unsigned char g, unsigned char b,
+ unsigned char &y, unsigned char &u, unsigned char
+ &v);
+ // Convertie un pixel YUV en RGB.
+ static void yuvToRgb (unsigned char y, unsigned char u, unsigned char v,
+ unsigned char &r, unsigned char &g, unsigned char
+ &b);
+};
+
+// Convertie un pixel RGB en YUV.
+inline void RgbYuv::rgbToYuv (unsigned char r, unsigned char g, unsigned char
+ b, unsigned char &y, unsigned char &u, unsigned
+ char &v)
+{
+ y = (( 66 * r + 129 * g + 25 * b + 128) >> 8) + 16;
+ u = (( -38 * r - 74 * g + 112 * b + 128) >> 8) + 128;
+ v = (( 112 * r - 94 * g - 18 * b + 128) >> 8) + 128;
+}
+
+// Convertie un pixel YUV en RGB.
+inline void RgbYuv::yuvToRgb (unsigned char y, unsigned char u, unsigned char
+ v, unsigned char &r, unsigned char &g, unsigned
+ char &b)
+{
+ int c, d, e;
+ int _r, _g, _b;
+ c = (int) (y & 0xff) - 16;
+ d = (int) (u & 0xff) - 128;
+ e = (int) (v & 0xff) - 128;
+ _r = (298 * c + 409 * e + 128) >> 8;
+ _g = (298 * c - 100 * d - 208 * e + 128) >> 8;
+ _b = (298 * c + 516 * d + 128) >> 8;
+ if (_r > 255) _r = 255;
+ if (_g > 255) _g = 255;
+ if (_b > 255) _b = 255;
+ if (_r < 0) _r = 0;
+ if (_g < 0) _g = 0;
+ if (_b < 0) _b = 0;
+ r = _r;
+ g = _g;
+ b = _b;
+}
+
+#endif // rgbyuv_h
diff --git a/2004/i/nono/src/vision/test_image.cc b/2004/i/nono/src/vision/test_image.cc
new file mode 100644
index 0000000..006c764
--- /dev/null
+++ b/2004/i/nono/src/vision/test_image.cc
@@ -0,0 +1,34 @@
+// test_image.cc - Teste la classe Image.
+// buzz - Programme du robot Efrei Robotique I1-I2 2003
+// Copyright (C) 2003 Nicolas Schodet
+#include "image.h"
+
+extern "C" {
+#include <ppm.h>
+};
+
+int
+main (int argc, char **argv)
+{
+ Image *i;
+ Thresholds *t;
+ ppm_init (&argc, argv);
+ try
+ {
+ t = new Thresholds ("rc/vision/palets.rgb");
+ i = new Image (argc == 2 ? argv[1] : "test.ppm", t);
+ i->filter ();
+ i->group ();
+ i->groupFilter ();
+ i->dumpGroups ();
+ i->dump ("dump.ppm");
+ delete i;
+ delete t;
+ }
+ catch (const char *s)
+ {
+ fprintf (stderr, "test_image: %s\n", s);
+ return 1;
+ }
+ return 0;
+}
diff --git a/2004/i/nono/src/vision/test_vision.cc b/2004/i/nono/src/vision/test_vision.cc
new file mode 100644
index 0000000..9792910
--- /dev/null
+++ b/2004/i/nono/src/vision/test_vision.cc
@@ -0,0 +1,48 @@
+// test_vision.cc
+// buzz - Programme du robot Efrei Robotique I1-I2 2003
+// Copyright (C) 2003 Nicolas Schodet
+//
+#include "image.h"
+#include "date/date.h"
+
+#include <unistd.h>
+extern "C" {
+#include <ppm.h>
+};
+
+int
+main (int argc, char **argv)
+{
+ Date d;
+ Image *i;
+ Camera *c;
+ Thresholds *t;
+ ppm_init (&argc, argv);
+ try
+ {
+ t = new Thresholds ("rc/vision/palets.rgb");
+ c = new Camera ();
+ i = new Image (c, t);
+ for (int j = 0; j < 5; ++j)
+ {
+ if (i->reread ())
+ {
+ char s[256];
+ i->dumpGroups ();
+ sprintf (s, "dump%d.ppm", j);
+ i->dump (s);
+ }
+ sleep (1);
+ }
+ delete i;
+ delete c;
+ delete t;
+ }
+ catch (const char *s)
+ {
+ fprintf (stderr, "test_vision: %s\n", s);
+ return 1;
+ }
+ return 0;
+}
+
diff --git a/2004/i/nono/src/vision/thresholds.cc b/2004/i/nono/src/vision/thresholds.cc
new file mode 100644
index 0000000..23c37e5
--- /dev/null
+++ b/2004/i/nono/src/vision/thresholds.cc
@@ -0,0 +1,55 @@
+// Classe Thresholds - Chargement de seuils
+// buzz - Programme du robot Efrei Robotique I1-I2 2003
+// Copyright (C) 2003 Nicolas Schodet
+#include "thresholds.h"
+
+#include <stdio.h>
+
+// Constructeur.
+Thresholds::Thresholds (const char *filename)
+{
+ FILE *fp;
+ Threshold **pt;
+ int n;
+ int zone, ym, yM, um, uM, vm, vM;
+ // Ouvre le fichier.
+ fp = fopen (filename, "r");
+ if (!fp) throw "Thresholds::Thresholds: fopen failled";
+ // Charge chaque lignes.
+ pt = &m_thresholds;
+ while (!feof (fp))
+ {
+ n = fscanf (fp, "%d %d %d %d %d %d %d\n", &zone, &ym, &yM, &um,
+ &uM, &vm, &vM);
+ if (n != 7)
+ {
+ fclose (fp);
+ throw "Thresholds::Thresholds: Bad format.";
+ }
+ // Ajoute un nouveaux seuil a la collection.
+ *pt = new Threshold;
+ (*pt)->zone = zone;
+ (*pt)->ym = ym;
+ (*pt)->yM = yM;
+ (*pt)->um = um;
+ (*pt)->uM = uM;
+ (*pt)->vm = vm;
+ (*pt)->vM = vM;
+ pt = &(*pt)->next;
+ }
+ // Ferme la liste de seuils.
+ *pt = 0;
+ // Ferme le fichier.
+ fclose (fp);
+}
+
+// Destructeur.
+Thresholds::~Thresholds (void)
+{
+ Threshold *p, *p2;
+ for (p = m_thresholds; p; p = p2)
+ {
+ p2 = p->next;
+ delete p;
+ }
+}
diff --git a/2004/i/nono/src/vision/thresholds.h b/2004/i/nono/src/vision/thresholds.h
new file mode 100644
index 0000000..42d7313
--- /dev/null
+++ b/2004/i/nono/src/vision/thresholds.h
@@ -0,0 +1,42 @@
+#ifndef thresholds_h
+#define thresholds_h
+// thresholds.h - Chargement de seuils.
+// buzz - Programme du robot Efrei Robotique I1-I2 2003
+// Copyright (C) 2003 Nicolas Schodet
+
+struct Threshold
+{
+ Threshold *next;
+ unsigned char ym, yM, um, uM, vm, vM;
+ unsigned char zone;
+};
+
+class Thresholds
+{
+ Threshold *m_thresholds;
+ public:
+ Thresholds (const char *filename);
+ ~Thresholds (void);
+ // Trouve la zone qui correspond aux composantes.
+ unsigned char findZone (unsigned char y, unsigned char u, unsigned char v)
+ const;
+};
+
+// Trouve la zone qui correspond aux composantes.
+inline unsigned char
+Thresholds::findZone (unsigned char y, unsigned char u, unsigned char v) const
+{
+ Threshold *t;
+ for (t = m_thresholds; t; t = t->next)
+ {
+ if (y >= t->ym && y <= t->yM
+ && u >= t->um && u <= t->uM
+ && v >= t->vm && v <= t->vM)
+ {
+ return t->zone;
+ }
+ }
+ return 0;
+}
+
+#endif // thresholds_h