// 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 }; // 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); }