// magnifier.cc - Classe Magnifier // robert - Programme du robot APBteam // Copyright (C) 2005 Olivier Gaillard /// @file magnifier.cc Filtre la liste d'objets trouvées #include #include "magnifier.hh" #include "skittle.hh" /// Constructeur Magnifier::Magnifier (Img *img, Segm *segm, Eraser *eraser, Group::ZoneType aim) : segm_ (segm), img_ (img), eraser_ (eraser), aim_ (aim) { oconfig_ = OConfig::getInstance (); itemList_ = new std::vector[Group::nbZoneType]; } /// Destructeur Magnifier::~Magnifier (void) { delete [] itemList_; } // XXX getdelta XXX /// 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); } */ /// Analyse une liste de zones /// @param zoneList liste des zones extraites par la classe group bool Magnifier::analyse (std::vector &zoneList) { std::cout << zoneList.size () << std::endl; // remise à zéro de toutes les listes for (int i=0; i::iterator iter = zoneList.begin (); iter != zoneList.end (); ++iter) { // Vérifie qu'il n'y a pas de doublon if (!checkIsUnique (*iter, itemList_)) continue; add (*iter, itemList_); } // parcours des zones jusqu'à ce qu'il n'y ai plus de changement à faire while (scan ()); // analyse des objets trouvés if (itemList_[aim_].size () != 0) { bool find = false; for (std::vector::iterator iter = itemList_[aim_].begin (); iter != itemList_[aim_].end (); ++iter) { Skittle *s = isSkittle (*iter); if (s) { iter->alone = !eraser_->isTooBig (*iter); iter->small = eraser_->isTooSmall (*iter); if (iter->partial) getPosOut (*iter); //showZone (*iter); //s->show (); delete s; find = true; } } return find; } return false; } /// Renvoie la position d'une quille void Magnifier::getPosOut (Zone &zone) { static const int widthDiv3 = img_->width_ / 3; static const int width2Div3 = widthDiv3 * 2; static const int heightDiv3 = img_->height_ / 3; static const int height2Div3 = heightDiv3 * 2; if (zone.centery < heightDiv3) { if (zone.centerx < widthDiv3) zone.posOut = Zone::northwest; else if (zone.centerx < width2Div3) zone.posOut = Zone::north; else zone.posOut = Zone::northeast; } else if (zone.centery < height2Div3) { if (zone.centerx < widthDiv3) zone.posOut = Zone::west; else if (zone.centerx < width2Div3) zone.posOut = Zone::center; else zone.posOut = Zone::east; } else { if (zone.centerx < widthDiv3) zone.posOut = Zone::southwest; else if (zone.centerx < width2Div3) zone.posOut = Zone::south; else zone.posOut = Zone::southeast; } } bool Magnifier::scan () { bool hasChanged = false; std::vector *newList = new std::vector[Group::nbZoneType]; int dist; bool find; for (int i=0; i ::iterator iter = itemList_[i].begin (); iter != itemList_[i].end (); ++iter) { if (!checkIsUnique (*iter, newList)) { hasChanged = true; continue; } // on regarde s'il une zone noire est situé en dessous pour virer le cercle supérieur des quilles find = false; dist = iter->ymax - iter->ymin; for (std::vector::iterator jter = iter+1; jter != itemList_[i].end (); ++jter) { if ((iter->ymax + dist > jter->ymin) && (abs(iter->xmin - jter->xmin) < 40) && (abs(iter->xmax - jter->xmax) < 40)) { jter->circleUp = true; find = true; break; } } if (!find) add (*iter, newList); } } delete [] itemList_; itemList_ = newList; return hasChanged; } void Magnifier::add (Zone &zone, std::vector *list) { switch (zone.id) { case Group::redSkittle: if (isRedSkittle (zone)) addItem (zone, list); break; case Group::greenSkittle: if (isGreenSkittle (zone)) addItem (zone, list); break; case Group::base: if (isBase (zone)) addItem (zone, list); break; case Group::gap: if (isGap (zone)) addItem (zone, list); break; case Group::border: if (isBorder (zone)) addItem (zone, list); break; case Group::reflectBand: addItem (zone, list); break; } } bool isInside (const Zone &z1, const Zone &z2) { // const int maxOut = 300; // int out = 0; // test si le centre est à l'intérieur if ((z1.centerx <= z2.xmax) && (z1.centerx >= z2.xmin) && (z1.centery <= z2.ymax) && (z1.centery >= z2.ymin)) { return true; // if (z1.xmax > z2.xmax ) out += z1.xmax - z2.xmax; // if (z1.ymax > z2.ymax ) out += z1.ymax - z2.ymax; // if (z1.xmin < z2.xmin ) out += z2.xmin - z1.xmin; // if (z1.ymin < z2.ymin ) out += z2.ymin - z1.ymin; // if (out < maxOut) return true; } return false; } /// Test si l'object s'agit d'un doublon bool Magnifier::checkIsUnique (const Zone &zone, std::vector *list) { for (std::vector::iterator iter = list[zone.id].begin (); iter != list[zone.id].end (); ++iter) if (((abs (zone.centerx - iter->centerx) < oconfig_->magUniqueness) || (abs (zone.centery - iter->centery) < oconfig_->magUniqueness))) { if (isInside (zone, *iter) || isInside (*iter, zone)) // || (areBound (zone, *iter))) { // on met a jour les données de l'item déjà trouvé if (zone.xmin < iter->xmin) iter->xmin = zone.xmin; if (zone.ymin < iter->ymin) iter->ymin = zone.ymin; if (zone.xmax > iter->xmax) iter->xmax = zone.xmax; if (zone.ymax > iter->ymax) iter->ymax = zone.ymax; iter->centerx = (iter->xmax + iter->xmin) / 2; iter->centery = (iter->ymax + iter->ymin) / 2; return false; } } return true; } /// Test si l'objet est une quille Skittle* Magnifier::isSkittle (Zone &zone) { Skittle *s = new Skittle (img_, segm_); if (s->analyse (zone, itemList_[Group::reflectBand])) { return s; } else delete s; return 0; } /// Test si l'objet est une quille rouge bool Magnifier::isRedSkittle (const Zone &zone) const { return true; } /// Test si l'objet est une bordure bool Magnifier::isBorder (const Zone &zone) const { // test si la zone touche au moins deux bords de l'image /// XXX pas tout à fait vrai près du fossé unsigned count = 0; if (zone.xmin <= 0) ++count; if (zone.ymin <= 0) ++count; if (zone.xmax >= img_->width_) ++count; if (zone.ymax <= img_->height_) ++count; if (count < 2) return false; return true; } /// Test si l'objet est une quille verte bool Magnifier::isGreenSkittle (const Zone &zone) const { return true; } /// Test si l'objet est un socle bool Magnifier::isBase (const Zone &zone) const { return true; } /// Test si l'objet est un fossée bool Magnifier::isGap (const Zone &zone) const { return true; } /// Ajout d'un objet void Magnifier::addItem (Zone &zone, std::vector *list) { // TODO remplir les flags : partial, ... zone.area = (zone.xmax - zone.xmin) * (zone.ymax - zone.ymin); if ((zone.xmax == img_->width_) || (zone.xmin == 0) || (zone.ymax == img_->height_) || (zone.ymin == 0)) zone.partial = true; else zone.partial = false; list[zone.id].push_back (zone); } /// Affiche les zones trouvees après analyse void Magnifier::showItems (const Group::ZoneType type) const { std::cout << "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n"; std::cout << Group::translateToColorName (type) << "\n"; for (std::vector::const_iterator iter = itemList_[type].begin (); iter != itemList_[type].end (); ++iter) showZone (*iter); std::cout << "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n"; } /// Test si les zones sont liées bool Magnifier::areBound (const Zone &z1, const Zone &z2) { /// Ratio demandé pour la liaison const double ratioBound = 0.95; /// Coeff directeur de la droite reliant les 2 zones int yCenterDiff = z1.centery - z2.centery; int xCenterDiff = z1.centerx - z2.centerx; double a, b; if (yCenterDiff != 0) { a = yCenterDiff / (double)xCenterDiff; b = z1.centery - a * z1.centerx; } else { a = 0; b = z1.centery; } int min, max; if (xCenterDiff < 0) { min = z1.centerx; max = z2.centerx; } else { min = z2.centerx; max = z1.centerx; } /// Parcours des x entre les 2 zones int equal = 0; int y; for (int x = min; x < max; ++x) { y = img_->maxWithBorder (img_->minWithBorder ((int)(a*x+b), 0), img_->height_);; if (segm_->giveColor (img_->tabData_ + ((y*img_->width_+x) * 3), true, true) == z1.color) ++equal; } /// Retour avec marge d'erreur if (equal >= (max - min)*ratioBound-2) return true; return false; } void Magnifier::showZone (const Zone &z) const { std::cout << "------------------------------------------------------------------\n"; std::cout << " position image : " << z.xmin << ", " << z.xmax << ", " << z.ymin << ", " << z.ymax << "\n"; std::cout << " area : " << z.area << "\n"; std::cout << " small : " << z.small << "\n"; std::cout << " alone : " << z.alone << "\n"; // std::cout << " density: " << z.density << "\n"; // std::cout << " circleUp: " << z.circleUp << "\n"; std::cout << " ratio/vertical: " << z.ratio << " " << (z.vertical?"vertical":"") << "\n"; std::cout << " orientation : " << z.pcX << ", " << z.pcY << "\n"; std::cout << " partial : " << z.partial << "\n"; std::cout << " posOut : " << z.posOut << "\n"; }