// 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 (); tabOut = NULL; zoneListBall = NULL; zoneListGoal = NULL; } /// Destructeur Group::~Group () { FreeGroups (); } /// 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; } /// Ajoute une balle ou un poteau à la liste de groupes /// @param type type du group à rechercher GOAL ou BALL /// @param numColor numéro de la couleur du group /// @param xmin,xmax,ymin,ymax borne du group /// @param centerx, centery centre du group /// @param dernier élément de la liste où empiler void Group::AddGroup (int type, int numColor, int xmin, int xmax, int ymin, int ymax, int centerx, int centery, ZONE *pLast) { 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 = true; if ((pLast->xmin <= 0) || (pLast->xmax >= img->width) || (pLast->ymin <= 0)) pLast->partial = true; else pLast->partial = false; } else { pLast->bottom = false; pLast->partial = false; } pLast->next = NULL; } /// Construit la table des distances void Group::DoDeltaTable () { } /// Retourne le delta utilisé pour la dissociation de 2 balles proches /// @param type type du group à rechercher GOAL ou BALL /// @param y coordonnees de la hauteur de la balle int Group::GetDelta (int type, int y) { if (type == BALL) return (int)(25 + y*0.1); else return 3*(int)(25 + y*0.1); } /// Test si la zone trouvé est valide /// @param type type du group à rechercher GOAL ou BALL /// @param xmin,xmax,ymin,ymax borne du group à valider bool Group::IsValidZone (int type, int xmin, int xmax, int ymin, int ymax) { if (type == BALL) { // test si la zone trouve un trop petite -> parasite if ( (abs(xmin - xmax) < oconfig->minLengthZone) || (abs(ymin - ymax) < oconfig->minLengthZone) ) return 0; } else if (type == GOAL) { // test si la zone trouve un trop petite -> parasite if ( (abs(xmin - xmax) * (abs(ymin - ymax) < oconfig->minLengthZone*oconfig->minLengthZone/10))) return 0; // 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 type type du group à rechercher GOAL ou BALL /// @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 et de gauche à droite while ((xmax < img->width-1)&& (segm->GiveColor(img->tabData + ((++xmax)+y* img->width)*3, true, true) == numColor)) {} while ((xmin > 0) && (segm->GiveColor(img->tabData + ((--xmin)+y* img->width)*3, true, true) == numColor)) {} while ((ymax < img->height-1) && (segm->GiveColor(img->tabData + (x+(++ymax)* img->width)*3, true, true) == numColor)) {} while ((ymin > 0) && (segm->GiveColor(img->tabData + (x+(--ymin)* img->width)*3, true, true) == 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; int delta; while (pCur) { imgY = (pCur->centery + centery) / 2; delta = GetDelta(type, imgY); // si on a deja ce groupe on actualise les donnees du groupe if ((numColor == pCur->idColor) && (abs(pCur->centerx - centerx) <= delta) && (abs(pCur->centery - centery) <= delta)) { 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) AddGroup (type, numColor, xmin, xmax, ymin, ymax, centerx, centery, pLast); } /// 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 != IS_SET) numColorGoal = segm->index[numColorGoal]; int curColor; // Parcours d'une partie des pixels de l'image for (int x=0; xwidth; x+=oconfig->jumpPointDist) for (int y=0; yheight; y+=oconfig->jumpPointDist) { curColor = segm->GiveColor (img->tabData + ((y*img->width+x) * 3), true, true); if (curColor == numColorBall) Plague(BALL, numColorBall, x, y); else if (curColor == numColorGoal) Plague(GOAL, numColorGoal, x, y); } } /// Creation du tableau de RGB pour faire une image void Group::TabOut (int type, bool init) { ZONE *pCur; if (type == BALL) pCur = zoneListBall; else pCur = zoneListGoal; // On verifie que des groupes ont ete trouve if (!pCur) { cerr << "Group::TabOut : No group defined" << endl; if (tabOut) delete [] tabOut; return; } if (init) { // 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; } else { // Allocation de la memoire if (!tabOut) tabOut = new unsigned char[img->nbPixels]; } // 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; } cout << endl; }