From 30ea7faee31ad69f3f0886dae8bb58e1fe31a74f Mon Sep 17 00:00:00 2001 From: schodet Date: Thu, 1 May 2003 17:10:58 +0000 Subject: Ajout du module vision. --- 2003/i/buzz/src/busp/GNUmakefile | 2 +- 2003/i/buzz/src/busp/busp.h | 2 +- 2003/i/buzz/src/vision/GNUmakefile | 26 +++ 2003/i/buzz/src/vision/image.cc | 354 ++++++++++++++++++++++++++++++ 2003/i/buzz/src/vision/image.h | 44 ++++ 2003/i/buzz/src/vision/rgbyuv.h | 57 +++++ 2003/i/buzz/src/vision/size_thresholds.cc | 53 +++++ 2003/i/buzz/src/vision/size_thresholds.h | 40 ++++ 2003/i/buzz/src/vision/test_image.cc | 37 ++++ 2003/i/buzz/src/vision/thresholds.cc | 55 +++++ 2003/i/buzz/src/vision/thresholds.h | 42 ++++ 11 files changed, 710 insertions(+), 2 deletions(-) create mode 100644 2003/i/buzz/src/vision/GNUmakefile create mode 100644 2003/i/buzz/src/vision/image.cc create mode 100644 2003/i/buzz/src/vision/image.h create mode 100644 2003/i/buzz/src/vision/rgbyuv.h create mode 100644 2003/i/buzz/src/vision/size_thresholds.cc create mode 100644 2003/i/buzz/src/vision/size_thresholds.h create mode 100644 2003/i/buzz/src/vision/test_image.cc create mode 100644 2003/i/buzz/src/vision/thresholds.cc create mode 100644 2003/i/buzz/src/vision/thresholds.h (limited to '2003/i') diff --git a/2003/i/buzz/src/busp/GNUmakefile b/2003/i/buzz/src/busp/GNUmakefile index 3fe815e..28efc6f 100644 --- a/2003/i/buzz/src/busp/GNUmakefile +++ b/2003/i/buzz/src/busp/GNUmakefile @@ -8,7 +8,7 @@ test_busp_SOURCES = busp.cc test_busp.cc $(SRCDIR)/erreur/erreur.a all: $(TARGETS) test_busp: $(test_busp_SOURCES:%.cc=%.o) - $(CXX) $(CXXFLAGS) $(LDFLAGS) -o $@ $^ $(LDLIBS) + $(CXX) $(CXXFLAGS) $(LDFLAGS) -o $@ $^ $(LDADD) clean: rm -f $(TARGETS) *.o diff --git a/2003/i/buzz/src/busp/busp.h b/2003/i/buzz/src/busp/busp.h index 767ac27..b7aa328 100644 --- a/2003/i/buzz/src/busp/busp.h +++ b/2003/i/buzz/src/busp/busp.h @@ -1,6 +1,6 @@ #ifndef busp_h #define busp_h -// busp.h +// busp.h - Contrôle bas niveau du bus parallèle. // buzz - Programme du robot Efrei Robotique I1-I2 2003 // Copyright (C) 2003 Nicolas Schodet diff --git a/2003/i/buzz/src/vision/GNUmakefile b/2003/i/buzz/src/vision/GNUmakefile new file mode 100644 index 0000000..b72985b --- /dev/null +++ b/2003/i/buzz/src/vision/GNUmakefile @@ -0,0 +1,26 @@ +SRCDIR = .. +CXXFLAGS = -Wall -g +CPPFLAGS = -I$(SRCDIR) + +LDADD = -lppm +test_image_SOURCES = test_image.cc image.cc thresholds.cc size_thresholds.cc + +TARGETS = test_image + +all: $(TARGETS) + +test_image: $(test_image_SOURCES:%.cc=%.o) + $(CXX) $(CXXFLAGS) $(LDFLAGS) -o $@ $^ $(LDADD) + +.dep/%.d: %.cc .dep + @set -e; $(CC) -M $(CPPFLAGS) $< \ + | sed 's/\($*\)\.o[ :]*/\1.o .dep\/$*.d : /g' > $@; \ + [ -s $@ ] || rm -f $@ + +include $(test_image_SOURCES:%.cc=.dep/%.d) + +.dep: + @mkdir .dep + +clean: + rm -f $(TARGETS) *.o 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 +}; + +// 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); +} diff --git a/2003/i/buzz/src/vision/image.h b/2003/i/buzz/src/vision/image.h new file mode 100644 index 0000000..eae1d20 --- /dev/null +++ b/2003/i/buzz/src/vision/image.h @@ -0,0 +1,44 @@ +#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 "size_thresholds.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; + Thresholds *m_thresholds; + SizeThresholds *m_sizeThresholds; + public: + // Constructeur. + Image (const char *filename, Thresholds *thresholds, + SizeThresholds *sizeThresholds); + // Destructeur. + ~Image (void); + 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); + protected: + // Fait des packets de pixels sur les lignes. + void groupLine (void); +}; + +#endif // image_h diff --git a/2003/i/buzz/src/vision/rgbyuv.h b/2003/i/buzz/src/vision/rgbyuv.h new file mode 100644 index 0000000..104c309 --- /dev/null +++ b/2003/i/buzz/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/2003/i/buzz/src/vision/size_thresholds.cc b/2003/i/buzz/src/vision/size_thresholds.cc new file mode 100644 index 0000000..3a65d4c --- /dev/null +++ b/2003/i/buzz/src/vision/size_thresholds.cc @@ -0,0 +1,53 @@ +// size_thresholds.cc - Chargement de seuils de taille de palets. +// buzz - Programme du robot Efrei Robotique I1-I2 2003 +// Copyright (C) 2003 Nicolas Schodet +#include "size_thresholds.h" + +#include + +// Constructeur. +SizeThresholds::SizeThresholds (const char *filename) +{ + FILE *fp; + SizeThreshold **pt; + int n; + int type, wm, wM, hm, hM; + // Ouvre le fichier. + fp = fopen (filename, "r"); + if (!fp) throw "SizeThresholds::SizeThresholds: fopen failled"; + // Charge chaque lignes. + pt = &m_thresholds; + while (!feof (fp)) + { + n = fscanf (fp, "%d %d %d %d %d\n", &type, &wm, &wM, + &hm, &hM); + if (n != 5) + { + fclose (fp); + throw "SizeThresholds::SizeThresholds: Bad format."; + } + // Ajoute un nouveaux seuil a la collection. + *pt = new SizeThreshold; + (*pt)->type = type; + (*pt)->wm = wm; + (*pt)->wM = wM; + (*pt)->hm = hm; + (*pt)->hM = hM; + pt = &(*pt)->next; + } + // Ferme la liste de seuils. + *pt = 0; + // Ferme le fichier. + fclose (fp); +} + +// Destructeur. +SizeThresholds::~SizeThresholds (void) +{ + SizeThreshold *p, *p2; + for (p = m_thresholds; p; p = p2) + { + p2 = p->next; + delete p; + } +} diff --git a/2003/i/buzz/src/vision/size_thresholds.h b/2003/i/buzz/src/vision/size_thresholds.h new file mode 100644 index 0000000..f30ac4d --- /dev/null +++ b/2003/i/buzz/src/vision/size_thresholds.h @@ -0,0 +1,40 @@ +#ifndef __size_thresholds_h__ +#define __size_thresholds_h__ +// size_thresholds.h - Chargement de seuils pour les tailles de palets. +// buzz - Programme du robot Efrei Robotique I1-I2 2003 +// Copyright (C) 2003 Nicolas Schodet + +struct SizeThreshold +{ + SizeThreshold *next; + int wm, wM, hm, hM; + int type; +}; + +class SizeThresholds +{ + SizeThreshold *m_thresholds; + public: + SizeThresholds (const char *filename); + ~SizeThresholds (void); + // Trouve le type qui correspond a la taille. + int findType (int w, int h); +}; + +// Trouve la zone qui correspond aux composantes. +inline int +SizeThresholds::findType (int w, int h) +{ + SizeThreshold *t; + for (t = m_thresholds; t; t = t->next) + { + if (w >= t->wm && w <= t->wM + && h >= t->hm && h <= t->hM) + { + return t->type; + } + } + return 0; +} + +#endif // size_thresholds_h diff --git a/2003/i/buzz/src/vision/test_image.cc b/2003/i/buzz/src/vision/test_image.cc new file mode 100644 index 0000000..cbdbd1e --- /dev/null +++ b/2003/i/buzz/src/vision/test_image.cc @@ -0,0 +1,37 @@ +// 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 +}; + +int +main (int argc, char **argv) +{ + Image *i; + Thresholds *t; + SizeThresholds *st; + ppm_init (&argc, argv); + try + { + t = new Thresholds ("palets.rgb"); + st = new SizeThresholds ("palets.size"); + i = new Image (argc == 2 ? argv[1] : "test.ppm", t, 0); + i->filter (); + i->group (); + i->groupFilter (); + i->dumpGroups (); + i->dump ("dump.ppm"); + delete i; + delete t; + delete st; + } + catch (const char *s) + { + fprintf (stderr, "test_image: %s\n", s); + return 1; + } + return 0; +} diff --git a/2003/i/buzz/src/vision/thresholds.cc b/2003/i/buzz/src/vision/thresholds.cc new file mode 100644 index 0000000..23c37e5 --- /dev/null +++ b/2003/i/buzz/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 + +// 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/2003/i/buzz/src/vision/thresholds.h b/2003/i/buzz/src/vision/thresholds.h new file mode 100644 index 0000000..b11c387 --- /dev/null +++ b/2003/i/buzz/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); +}; + +// Trouve la zone qui correspond aux composantes. +inline unsigned char +Thresholds::findZone (unsigned char y, unsigned char u, unsigned char v) +{ + 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 -- cgit v1.2.3