// 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 #include #include #include using namespace std; #define BORD 5 /// Constructeur /// @param *img classe image /// @param *segm classe segmNN Group::Group(Img *img, SegmNN *segm) { // Sauvegarde des pointeurs Group::img = img; Group::segm = segm; oconfig = OConfig::GetInstance (); width = img->width; height = img->height; tabOut = NULL; zoneListBall = NULL; zoneListGoal = NULL; } /// Destructeur Group::~Group() { } /// Supprime la liste des groupes void Group::FreeGroups () { 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); } zoneListBall = NULL; zoneListGoal = NULL; } /// Construit la table des distances void Group::DoDeltaTable () { } /// Retourne le delta utilisé pour la dissociation de 2 balles proches int Group::GetDelta (int type, int y) { // return 50; if (type == BALL) return (int)(25 + y*0.1); else return 3*(int)(25 + y*0.1); } /// Test si la zone trouvé est valide bool Group::IsValidZone (int type, int xmin, int xmax, int ymin, int ymax) { // test si la zone trouve un trop petite -> parasite if ( (abs(xmin - xmax) < oconfig->minLengthZone) || (abs(ymin - ymax) < oconfig->minLengthZone) ) return 0; if (type == BALL) { } else if (type == GOAL) { // test si la zone trouve touche le haut de l'image if (ymin > 0) return 0; } return 1; } /// 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) { int xmax = x; int xmin = x; int ymax = y; int ymin = y; // TODO ajouter une inertie ? // Parcours de l'objet trouve de haut en bas while ((xmax < img->width-1)&& (segm->FindColorNN(img->tabData + ((++xmax)+y* img->width)*3, 1) == numColor)) {} while ((xmin > 0) && (segm->FindColorNN(img->tabData + ((--xmin)+y* img->width)*3, 1) == numColor)) {} while ((ymax < img->height-1) && (segm->FindColorNN(img->tabData + (x+(++ymax)* img->width)*3, 1) == numColor)) {} while ((ymin > 0) && (segm->FindColorNN(img->tabData + (x+(--ymin)* img->width)*3, 1) == numColor)) {} // test si la zone trouve est une zone valide if (!IsValidZone (type, xmin, xmax, ymin, ymax)) return; ZONE *pCur; if (type == BALL) pCur = zoneListBall; else if (type == GOAL) pCur = zoneListGoal; // Calcul du centre de l'image int centerx, centery; centerx = (xmax+xmin)/2; centery = (ymax+ymin)/2; ZONE *pLast=NULL; int imgY; while (pCur) { imgY = (pCur->centery + centery) / 2; // si on a deja ce groupe on actualise les donnees du groupe if ((numColor == pCur->idColor) && (abs(pCur->centerx - centerx) <= GetDelta(type, imgY)) && (abs(pCur->centery - centery) <= GetDelta(type, imgY))) { 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->ymax >= img->height - BORD) { pLast->bottom = 1; if ((pLast->xmin <= 0) || (pLast->xmax >= img->width) || (pLast->ymin <= 0)) pLast->partial = 1; else pLast->partial = 0; } else { pLast->bottom = 0; 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; } pCur = zoneListGoal; cout << "Groupes poteaux:" << 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 numColorBall, unsigned char numColorGoal) { FreeGroups (); // Initialisation de la couleur a chercher numColorBall = segm->index[numColorBall]; if (numColorGoal != 255) numColorGoal = segm->index[numColorGoal]; int curColor; // Parcours d'une partie des pixels de l'image for (int x=0; xwidth; x+=10) { for (int y=0; yheight; y+=10) { // if (tabSegm[y*img->width+x] == numColor) curColor = segm->FindColorNN(img->tabData + ((y*img->width+x) * 3)); if (curColor == numColorBall) Plague(BALL, numColorBall, x, y); else if (curColor == numColorGoal) Plague(GOAL, numColorGoal, x, y); } } ZONE *pCur; for (int k=0; k<2; k++) { if (k == 0) pCur = zoneListBall; else if (k == 1) pCur = zoneListGoal; while (pCur) { pCur->ymax = img->height - pCur->ymax; pCur = pCur->next; } } } /// 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; inbPixels; i++) tabOut[i] = 0; // Parcours de la liste des zones trouvees while (pCur) { // Remplissage de la zone avec une couleur for(int i=pCur->xmin; ixmax; i++) for (int j=pCur->ymin; jymax; j++) tabOut[j* img->width+i] = pCur->idColor+1; pCur = pCur->next; } }