summaryrefslogtreecommitdiff
path: root/2003/i/buzz/src/vision/image.cc
diff options
context:
space:
mode:
Diffstat (limited to '2003/i/buzz/src/vision/image.cc')
-rw-r--r--2003/i/buzz/src/vision/image.cc354
1 files changed, 354 insertions, 0 deletions
diff --git a/2003/i/buzz/src/vision/image.cc b/2003/i/buzz/src/vision/image.cc
new file mode 100644
index 0000000..f868587
--- /dev/null
+++ b/2003/i/buzz/src/vision/image.cc
@@ -0,0 +1,354 @@
+// image.cc - Classe Image
+// buzz - Programme du robot Efrei Robotique I1-I2 2003
+// Copyright (C) 2003 Nicolas Schodet
+#include "image.h"
+#include "rgbyuv.h"
+
+// A definir si on code en YUV.
+//#define USE_YUV
+
+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))
+
+// Constructeur.
+Image::Image (const char *filename, Thresholds *thresholds,
+ SizeThresholds *sizeThresholds)
+{
+ pixel **img;
+ pixel *p;
+ pixval maxval;
+ int x, y, w, h;
+#ifdef USE_YUV
+ int r, g, b, Y, U, V;
+#endif // USE_YUV
+ 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*3];
+ 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++)
+ {
+#ifdef USE_YUV
+ r = PPM_GETR (*p) * 255 / maxval;
+ g = PPM_GETG (*p) * 255 / maxval;
+ b = PPM_GETB (*p) * 255 / maxval;
+ RgbYuv::rgbToYuv (r, g, b, Y, U, V);
+ *pi++ = (unsigned char) Y;
+ *pi++ = (unsigned char) U;
+ *pi++ = (unsigned char) V;
+#else // ! USE_YUV
+ *pi++ = (unsigned char) (PPM_GETR (*p) * 255 / maxval);
+ *pi++ = (unsigned char) (PPM_GETG (*p) * 255 / maxval);
+ *pi++ = (unsigned char) (PPM_GETB (*p) * 255 / maxval);
+#endif // ! USE_YUV
+ 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_sizeThresholds = sizeThresholds;
+}
+
+// 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; // ou y, u, v, c'est le même traitement.
+ // Filtre.
+ pz = m_zones;
+ pi = m_image;
+ for (i = 0; i < m_width * m_height; i++)
+ {
+ r = *pi++;
+ g = *pi++;
+ b = *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 = m_sizeThresholds->findType (g2->w, g2->h);
+ // 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.
+#ifdef USE_YUV
+ ppm_writeppminit (fp, m_width, m_height * 4, 255, 0);
+#else // ! USE_YUV
+ ppm_writeppminit (fp, m_width, m_height * 3, 255, 0);
+#endif // ! USE_YUV
+ // image.
+ p = m_image;
+ for (y = 0; y < m_height; y++)
+ {
+ pr = row;
+ for (x = 0; x < m_width; x++)
+ {
+ r = *p++;
+ g = *p++;
+ b = *p++;
+ PPM_ASSIGN (*pr, r, g, b);
+ pr++;
+ }
+ ppm_writeppmrow (fp, row, m_width, 255, 0);
+ }
+#ifdef USE_YUV
+ // Image en couleurs RGB
+ p = m_image;
+ for (y = 0; y < m_height; y++)
+ {
+ pr = row;
+ for (x = 0; x < m_width; x++)
+ {
+ // Lit les YUV.
+ r = *p++;
+ g = *p++;
+ b = *p++;
+ // Convertit.
+ RgbYuv::yuvToRgb (r, g, b, r, g, b);
+ PPM_ASSIGN (*pr, r, g, b);
+ pr++;
+ }
+ ppm_writeppmrow (fp, row, m_width, 255, 0);
+ }
+#endif // USE_YUV
+ // 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);
+}