Tekkotsu Homepage
Demos
Overview
Downloads
Dev. Resources
Reference
Credits

BrickData.cc

Go to the documentation of this file.
00001 //-*-c++-*-
00002 
00003 #include <iostream>
00004 #include <vector>
00005 
00006 #include "BaseData.h"    // superclass
00007 #include "Point.h"       // Point data member
00008 #include "ShapeTypes.h"  // brickDataType
00009 
00010 #include "SketchSpace.h"
00011 #include "Sketch.h"
00012 #include "visops.h"
00013 
00014 #include "ShapeSpace.h"  // required by DATASTUFF_CC
00015 #include "ShapeRoot.h"   // required by DATASTUFF_CC
00016 
00017 #include "BrickData.h"
00018 #include "ShapeBrick.h"
00019 #include "ShapePoint.h"
00020 #include "Region.h"
00021 
00022 using namespace std;
00023 
00024 namespace DualCoding {
00025 
00026 BrickData::BrickData(ShapeSpace& _space,
00027          const EndPoint &_GFL, const EndPoint &_GBL, 
00028          const EndPoint &_GFR, const EndPoint &_GBR, 
00029          const EndPoint &_TFL, const EndPoint &_TBL, 
00030          const EndPoint &_TFR, const EndPoint &_TBR) 
00031   : BaseData(_space,brickDataType), 
00032     GFL(_GFL), GFR(_GFR), GBL(_GBL), GBR(_GBR),
00033     TFL(_TFL), TFR(_TFR), TBL(_TBL), TBR(_TBR),
00034     centroid((GFL + GFR + GBL + GBR + TFL + TFR + TBL + TBR) / 8)
00035 {
00036 }
00037   
00038 BrickData::BrickData(ShapeSpace& _space,
00039                        const fmat::SubVector<3,const fmat::fmatReal>& _centroid,
00040                        fmat::Column<3> extents,
00041                        const fmat::SubMatrix<3,3,const fmat::fmatReal>& o)
00042   : BaseData(_space, brickDataType),
00043     GFL(), GFR(), GBL(), GBR(), TFL(), TFR(), TBL(), TBR(),
00044     centroid(_centroid) {
00045     TFR.coords = o * extents + _centroid; //+++
00046     extents[2] = -extents[2];
00047     GFR.coords = o * extents + _centroid; //++-
00048     extents[1] = -extents[1];
00049     GBR.coords = o * extents + _centroid; //+--
00050     extents[2] = -extents[2];
00051     TBR.coords = o * extents + _centroid; //+-+
00052     extents[0] = -extents[0];
00053     TBL.coords = o * extents + _centroid; //--+
00054     extents[2] = -extents[2];
00055     GBL.coords = o * extents + _centroid; //---
00056     extents[1] = -extents[1];
00057     GFL.coords = o * extents + _centroid; //-+-
00058     extents[2] = -extents[2];
00059     TFL.coords = o * extents + _centroid; //-++
00060   }
00061 
00062   
00063 DATASTUFF_CC(BrickData);
00064 
00065 bool BrickData::isMatchFor(const ShapeRoot& other) const {
00066   if (!(isSameTypeAs(other) && isSameColorAs(other)))
00067     return false;
00068   // const Shape<BrickData>& other_point = ShapeRootTypeConst(other,BrickData);
00069   // float dist = the_point.distanceFrom(other_point->getCentroid());
00070   float dist = 0;
00071   return dist < 20; // *** DST hack
00072 }
00073 
00074 void BrickData::mergeWith(const ShapeRoot& other) {
00075   const Shape<BrickData>& other_brick = ShapeRootTypeConst(other,BrickData);
00076   if (other_brick->confidence <= 0)
00077     return;
00078   /*
00079   const int other_conf = other_point->confidence;
00080   confidence += other_conf;
00081   the_point = (the_point*confidence + other_point->getCentroid()*other_conf) / (confidence+other_conf);*/
00082 }
00083 
00084 bool BrickData::updateParams(const ShapeRoot& other, bool) {
00085   const Shape<BrickData>& other_brick = *static_cast<const Shape<BrickData>*>(&other);
00086   //  ++confidence;
00087   GFL = (GFL*(confidence-1) + other_brick->getGFL())/confidence;
00088   GFR = (GFR*(confidence-1) + other_brick->getGFR())/confidence;
00089   GBL = (GBL*(confidence-1) + other_brick->getGBL())/confidence;
00090   GBR = (GBR*(confidence-1) + other_brick->getGBR())/confidence;
00091   TFL = (TFL*(confidence-1) + other_brick->getTFL())/confidence;
00092   TFR = (TFR*(confidence-1) + other_brick->getTFR())/confidence;
00093   TBL = (TBL*(confidence-1) + other_brick->getTBL())/confidence;
00094   TBR = (TBR*(confidence-1) + other_brick->getTBR())/confidence;
00095   deleteRendering();
00096   return true;
00097 }
00098 
00099 //! Print information about this shape. (Virtual in BaseData.)
00100 void
00101 BrickData::printParams() const {
00102   cout << "Type = " << getTypeName();
00103   cout << "Shape ID = " << getId() << endl;
00104   cout << "Parent ID = " << getParentId() << endl;
00105   
00106   // Print critical points.
00107   cout << endl;
00108   //cout << "center{" << getCentroid().coordX() << ", " << getCentroid().coordY() << "}" << endl;
00109   /* Didn't work initially... not sure why, didn't try too hard.
00110     cout<<"GFL: "; GFL.printData(); cout<<endl;
00111   cout<<"GFR: "; GFR.printData(); cout<<endl;
00112   cout<<"GBL: "; GBL.printData(); cout<<endl;
00113   cout<<"GBR: "; GBR.printData(); cout<<endl;
00114   cout<<"TFL: "; TFL.printData(); cout<<endl;
00115   cout<<"TFR: "; TFR.printData(); cout<<endl;
00116   cout<<"TBL: "; TBL.printData(); cout<<endl;
00117   cout<<"TBR: "; TBR.printData(); cout<<endl;*/
00118   printf("color = %d %d %d\n",getColor().red,getColor().green,getColor().blue);
00119   cout << "viewable = " << isViewable() << endl;
00120 }
00121 
00122 
00123 //! Transformations. (Virtual in BaseData.)
00124 void BrickData::applyTransform(const fmat::Transform& Tmat, const ReferenceFrameType_t newref) {
00125   GFL.applyTransform(Tmat,newref);
00126   GFR.applyTransform(Tmat,newref);
00127   GBL.applyTransform(Tmat,newref);
00128   GBR.applyTransform(Tmat,newref);
00129   TFL.applyTransform(Tmat,newref);
00130   TFR.applyTransform(Tmat,newref);
00131   TBL.applyTransform(Tmat,newref);
00132   TBR.applyTransform(Tmat,newref);
00133 }
00134 
00135 void BrickData::projectToGround(const fmat::Transform& camToBase, const PlaneEquation& groundplane) {
00136   GFL.projectToGround(camToBase,groundplane);
00137   GFR.projectToGround(camToBase,groundplane);
00138   GBL.projectToGround(camToBase,groundplane);
00139   GBR.projectToGround(camToBase,groundplane);
00140 
00141   // Compute height at every corner except BL (because we didn't actually observe that corner)
00142   float FLHeight, FRHeight, BRHeight;
00143   TFL.projectToGround(camToBase,groundplane);
00144   TFR.projectToGround(camToBase,groundplane);
00145   TBR.projectToGround(camToBase,groundplane);
00146   FLHeight = TFL.getHeightAbovePoint(GFL, groundplane);
00147   FRHeight = TFR.getHeightAbovePoint(GFR, groundplane);
00148   BRHeight = TBR.getHeightAbovePoint(GBR, groundplane);
00149   float brickHeight = (FLHeight + FRHeight+ BRHeight) / 3.f;
00150   TFL.setCoords(GFL.coordX(), GFL.coordY(), GFL.coordZ() + FLHeight);
00151   TFR.setCoords(GFR.coordX(), GFR.coordY(), GFR.coordZ() + FRHeight);
00152   TBL.setCoords(GBL.coordX(), GBL.coordY(), GBL.coordZ() + brickHeight);
00153   TBR.setCoords(GBR.coordX(), GBR.coordY(), GBR.coordZ() + BRHeight);
00154   centroid = (GFL + GFR + GBL + GBR)/4;
00155   centroid.setCoords(centroid.coordX(), centroid.coordY(), brickHeight/2);
00156   centroid.setRefFrameType(egocentric);
00157   std::cout << "New centroid: " << centroid << endl;
00158 
00159 }
00160 
00161 // ==================================================
00162 // BEGIN SKETCH MANIPULATION AND BRICK EXTRACTION CODE
00163 // ==================================================
00164 
00165 
00166 //! Brick extraction.
00167 
00168 
00169 //! Render into a sketch space and return reference. (Private.)
00170 Sketch<bool>* BrickData::render() const {
00171   SketchSpace &renderspace = space->getDualSpace();
00172   //int const width = renderspace.getWidth();
00173   //int const height = renderspace.getHeight();
00174   //float x1,y1,x2,y2;
00175   Sketch<bool>* draw_result = 
00176     new Sketch<bool>(renderspace, "render("+getName()+")");
00177   (*draw_result)->setParentId(getViewableId());
00178   (*draw_result)->setColor(getColor());
00179   *draw_result = 0;
00180   LineData GF(*space, GFL, GFR);
00181   *draw_result = *draw_result & GF.getRendering();
00182   LineData GL(*space, GFL, GBL);
00183   *draw_result = *draw_result & GL.getRendering();
00184   LineData GB(*space, GBL, GBR);
00185   *draw_result = *draw_result & GB.getRendering();
00186   LineData GR(*space, GBR, GFR);
00187   *draw_result = *draw_result & GR.getRendering();
00188   
00189   return draw_result;
00190 }
00191 
00192 
00193 
00194 
00195   // Old version of brick extraction
00196   // Final version resides in extractBrick
00197 std::vector<Shape<BrickData> > BrickData::findBricks(ShapeSpace& ShS, std::vector<Shape<LineData> > lines)
00198 {
00199   const float lengthConst = .3f;
00200   std::vector<Shape<LineData> > resultLines;
00201   std::vector<Shape<BrickData> > resultBricks;
00202   float longLength, shortLength;
00203 
00204   if (lines.size() < 3)
00205     {
00206       return resultBricks;
00207     }
00208 
00209   lines = stable_sort(lines, not2(LineData::LengthLessThan()));
00210 
00211   DO_SHAPEVEC(lines, LineData, l1, {
00212     DO_SHAPENEXT(lines, LineData, l1, l2, {
00213     if (l1->getLength() > l2->getLength()){
00214       longLength = l1->getLength();
00215       shortLength = l2->getLength();
00216     }
00217     else {
00218       longLength = l2->getLength();
00219       shortLength = l1->getLength();
00220     }
00221     if (LineData::ParallelTest()(l1,l2) && !LineData::ColinearTest()(l1,l2) && 
00222   (shortLength / longLength > lengthConst)) {
00223       DO_SHAPENEXT(lines, LineData, l2, l3, {
00224   if (LineData::ParallelTest()(l1,l3) && 
00225       !LineData::ColinearTest()(l1,l3) &&
00226       LineData::ParallelTest()(l2,l3) && 
00227       !LineData::ColinearTest()(l2,l3) &&
00228       (l3->getLength() / longLength > lengthConst) && 
00229       (shortLength / l3->getLength() > lengthConst)) {
00230     NEW_SHAPE_N(l1_2, LineData,  new LineData(ShS, l1->leftPt(), l1->rightPt()));
00231     NEW_SHAPE_N(l2_2, LineData, new LineData(ShS, l2->leftPt(), l2->rightPt()));
00232     NEW_SHAPE_N(l3_2, LineData, new LineData(ShS, l3->leftPt(), l3->rightPt()));
00233     l1_2->setParentId(l1->getViewableId());
00234     l2_2->setParentId(l1->getViewableId());
00235     l3_2->setParentId(l1->getViewableId());
00236     resultLines.push_back(l1_2);
00237     resultLines.push_back(l2_2);
00238     resultLines.push_back(l3_2);
00239   }
00240       });
00241     }
00242     });
00243   });
00244         
00245   if (resultLines.size() < 3) {
00246       return resultBricks;
00247   }
00248   
00249   for (unsigned int i=0; i<resultLines.size(); i+=3)
00250     {
00251       const Shape<LineData>& final1 = ShapeRootTypeConst(resultLines[i+0],LineData);
00252       const Shape<LineData>& final2 = ShapeRootTypeConst(resultLines[i+1],LineData);
00253       const Shape<LineData>& final3 = ShapeRootTypeConst(resultLines[i+2],LineData);
00254       /*cout<<"3 lines:"<<endl;
00255   final1->printEnds();
00256   final2->printEnds();
00257   final3->printEnds();*/
00258       
00259       std::vector<Shape<LineData> > threeLines;
00260       
00261       if (final1->bottomPt().isBelow(final2->bottomPt(),camcentric))
00262   {
00263     if (final1->bottomPt().isBelow(final3->bottomPt(),camcentric))
00264       {
00265         threeLines.push_back(final1);
00266         if (final2->bottomPt().isBelow(final3->bottomPt(),camcentric))
00267     {
00268       threeLines.push_back(final2);
00269       threeLines.push_back(final3);
00270     }
00271         else
00272     {
00273       threeLines.push_back(final3);
00274       threeLines.push_back(final3);
00275     }
00276       }
00277     else
00278       {
00279         threeLines.push_back(final3);
00280         threeLines.push_back(final1);
00281         threeLines.push_back(final2);
00282       }
00283   }
00284       else
00285   {
00286     if (final2->bottomPt().isBelow(final3->bottomPt(),camcentric))
00287       {
00288         threeLines.push_back(final2);
00289         if (final1->bottomPt().isBelow(final3->bottomPt(),camcentric))
00290     {
00291       threeLines.push_back(final1);
00292       threeLines.push_back(final3);
00293     }
00294         else
00295     {
00296       threeLines.push_back(final3);
00297       threeLines.push_back(final1);
00298     }
00299       }
00300     else
00301       {
00302         threeLines.push_back(final3);
00303         threeLines.push_back(final2);
00304         threeLines.push_back(final1);
00305       }
00306   }
00307       const Shape<LineData> &bottom = ShapeRootTypeConst(threeLines[0], LineData);
00308       const Shape<LineData> &mid = ShapeRootTypeConst(threeLines[1], LineData);
00309       const Shape<LineData> &top = ShapeRootTypeConst(threeLines[2], LineData);
00310       
00311       /*cout<<"Sorted Lines: "<<endl;
00312   bottom->printEnds();
00313   mid->printEnds();
00314   top->printEnds();*/
00315       
00316       Point gbl(top->leftPt()+(bottom->leftPt() - mid->leftPt()));
00317       Point gbr(top->rightPt()+(bottom->rightPt() - mid->rightPt()));
00318       Shape<BrickData> newBrick (ShS, (Point&)(bottom->leftPt()), (Point&)bottom->rightPt(), 
00319          gbl, gbr, 
00320          (Point&)mid->leftPt(), (Point&)mid->rightPt(), 
00321          (Point&)top->leftPt(), (Point&)top->rightPt());
00322       
00323       newBrick->setParentId(final1->getViewableId());
00324 
00325       NEW_SHAPE(brickl1, LineData, Shape<LineData>(bottom.getData()));
00326       NEW_SHAPE(brickl2, LineData, Shape<LineData>(mid.getData()));
00327       NEW_SHAPE(brickl3, LineData, Shape<LineData>(top.getData()));
00328 
00329       brickl1->setParentId(newBrick->getViewableId());
00330       brickl2->setParentId(newBrick->getViewableId());
00331       brickl3->setParentId(newBrick->getViewableId());
00332       
00333       resultBricks.push_back(newBrick);
00334     }
00335   
00336   return resultBricks;
00337 }
00338 
00339 
00340 // Find bricks from 3 vectors of candidate blobs
00341 // Each vector is blobs of a different face color
00342 //
00343 // Also an old version. Final version is in extractBrick
00344 std::vector<Shape<BrickData> > BrickData::findBricksFromBlobs(ShapeSpace& ShS, 
00345                     std::vector<Shape<BlobData> > blobs1,
00346                     std::vector<Shape<BlobData> > blobs2,
00347                     std::vector<Shape<BlobData> > blobs3) 
00348 {
00349 
00350   const float distanceThresh = 10;
00351 
00352   unsigned int i, i1, i2;
00353   Shape<BlobData> blob1, blob2, blob3;
00354 
00355   std::vector<Shape<BrickData> > resultBricks;
00356 
00357   Point GFL, GFR, GBL, GBR, TFL, TFR, TBL, TBR;
00358   Point c12,c13,c23;
00359 
00360   std::vector<std::vector<Point> > corners1;
00361   std::vector<std::vector<Point> > corners2;
00362   std::vector<std::vector<Point> > corners3;
00363   std::vector<bool> used1;
00364   std::vector<bool> used2;
00365   std::vector<bool> used3;
00366   for (i=0; i<blobs1.size(); i++) { 
00367     used1.push_back(false); 
00368     corners1.push_back(blobs1[i]->findCornersDiagonal()); 
00369   }
00370   for (i=0; i<blobs2.size(); i++) { 
00371     used2.push_back(false); 
00372     corners2.push_back(blobs2[i]->findCornersDiagonal()); 
00373   }
00374   for (i=0; i<blobs3.size(); i++) { 
00375     used3.push_back(false); 
00376     corners3.push_back(blobs3[i]->findCornersDiagonal()); 
00377   }
00378 
00379   // Look for bricks with a good common edge between each pair of viable brick face colors
00380   int used;
00381   for (i1=0; i1<blobs1.size(); i1++){
00382     for (i2=0; i2<blobs2.size();i2++){
00383       if (!used1[i1] && !used2[i2]) {
00384   used = addBrickWithTwoSides(ShS, corners1[i1], corners2[i2], corners3, 
00385             resultBricks, distanceThresh);
00386   if (used>=0) {
00387     used1[i1] = true;
00388     used2[i2] = true;
00389     used3[used] = true;
00390     resultBricks[resultBricks.size()-1]->setParentId(blobs1[i1]->getViewableId());
00391   }
00392       }
00393     }
00394   }
00395 
00396   for (i1=0; i1<blobs1.size(); i1++){
00397     for (i2=0; i2<blobs3.size();i2++){
00398       if (!used1[i1] && !used3[i2]) {
00399   used = addBrickWithTwoSides(ShS, corners1[i1], corners3[i2], corners2, 
00400             resultBricks, distanceThresh);
00401   if (used>=0) {
00402     used1[i1] = true;
00403     used3[i2] = true;
00404     used2[used] = true;
00405     resultBricks[resultBricks.size()-1]->setParentId(blobs1[i1]->getViewableId());
00406   }
00407       }
00408     }
00409   }
00410 
00411   for (i1=0; i1<blobs3.size(); i1++){
00412     for (i2=0; i2<blobs2.size();i2++){
00413       if (!used3[i1] && !used2[i2]) {
00414   used = addBrickWithTwoSides(ShS, corners3[i1], corners2[i2], corners1, 
00415             resultBricks, distanceThresh);
00416   if (used>=0) {
00417     used3[i1] = true;
00418     used2[i2] = true;
00419     used1[used] = true;
00420     resultBricks[resultBricks.size()-1]->setParentId(blobs3[i1]->getViewableId());
00421   }
00422       }
00423     }
00424   }
00425 
00426 
00427   return resultBricks;
00428 }
00429 
00430 
00431 // Subroutine for blob brick detection
00432 // If the two sides match, finds the third side that matches
00433 // Extrapolates all the points and adds the brick to the vector
00434 // returns the index of the third face, or -1 if no match is found
00435 //
00436 // subroutine for an old version
00437 int BrickData::addBrickWithTwoSides(ShapeSpace &ShS,
00438             std::vector<Point>& corners1, 
00439             std::vector<Point>& corners2, 
00440             std::vector<std::vector<Point> >& blobs3, 
00441             std::vector<Shape<BrickData> >& result, 
00442             float distanceThresh)
00443 {
00444   unsigned int blobi;
00445   int i1=-1,j1=-1, i2=-1, j2=-1;
00446   for (int i=0; i<4 && i2<0; i++) {
00447     for (int j=0; j<4 && j2<0; j++) {
00448       if (corners1[i].distanceFrom(corners2[j]) < distanceThresh) {
00449   if (corners1[(i+1)%4].distanceFrom(corners2[(j+3)%4]) < distanceThresh) {
00450     i1 = i;
00451     i2 = (i+1)%4;
00452     j1 = (j+3)%4;
00453     j2 = j;
00454   }
00455   else if (corners1[(i+3)%4].distanceFrom(corners2[(j+1)%4]) < distanceThresh) {
00456     i1 = (i+3)%4;
00457     i2 = i;
00458     j1 = j;
00459     j2 = (j+1)%4;
00460   }
00461   if (i2>=0) {
00462     // Two matching corners have been found: (i1,j2), (i2, j1)
00463     // Look for the third side
00464     bool found = false;
00465     Point center, mid1, mid2, mid3, c1, c2, c3;
00466     for (blobi=0; blobi<blobs3.size() && !found; blobi++) {
00467       for(int k=0; k<4 && !found; k++) {
00468         if (((blobs3[blobi][k].distanceFrom(corners1[i1]) < distanceThresh) +
00469        (blobs3[blobi][(k+1)%4].distanceFrom(corners1[(i1+3)%4]) < distanceThresh) +
00470        (blobs3[blobi][(k+3)%4].distanceFrom(corners2[(j2+1)%4]) < distanceThresh)) > 1) {
00471     // (i1,j2, k) is the center
00472     found = true;
00473     mid1 = (corners1[i2]+corners2[j1])/2;
00474     if (blobs3[blobi][k].distanceFrom(corners1[i1]) < distanceThresh) 
00475       center = (corners1[i1]+corners2[j2]+blobs3[blobi][k])/3;
00476     else
00477       center = (corners1[i1]+corners2[j2])/2;
00478     if (blobs3[blobi][(k+1)%4].distanceFrom(corners1[(i1+3)%4]) < distanceThresh)
00479       mid2 = (blobs3[blobi][(k+1)%4] + corners1[(i1+3)%4])/2;
00480     else
00481       mid2 = corners1[(i1+3)%4];
00482     if (blobs3[blobi][(k+3)%4].distanceFrom(corners2[(j2+1)%4]) < distanceThresh)
00483       mid3 = (blobs3[blobi][(k+3)%4] + corners2[(j2+1)%4])/2;
00484     else
00485       mid3 = corners2[(j2+1)%4];
00486     c1 = corners1[(i1+2)%4];
00487     c2 = blobs3[blobi][(k+2)%4];
00488     c3 = corners2[(j2+2)%4];
00489         }
00490         else if (((blobs3[blobi][k].distanceFrom(corners1[i2]) < distanceThresh) +
00491        (blobs3[blobi][(k+1)%4].distanceFrom(corners2[(j1+3)%4]) < distanceThresh) +
00492        (blobs3[blobi][(k+3)%4].distanceFrom(corners1[(i2+1)%4]) < distanceThresh)) > 1) {
00493     // (i2, j1, k) is the center
00494     found = true;
00495     mid1 = (corners1[i1]+corners2[j2])/2;
00496     if (blobs3[blobi][k].distanceFrom(corners1[i2]) < distanceThresh) 
00497       center = (corners1[i2]+corners2[j1]+blobs3[blobi][k])/3;
00498     else
00499       center = (corners1[i2]+corners2[j1])/2;
00500     if (blobs3[blobi][(k+1)%4].distanceFrom(corners2[(j1+3)%4]) < distanceThresh)
00501       mid2 = (blobs3[blobi][(k+1)%4] + corners2[(j1+3)%4])/2;
00502     else
00503       mid2 = corners2[(j1+3)%4];
00504     if (blobs3[blobi][(k+3)%4].distanceFrom(corners1[(i2+1)%4]) < distanceThresh)
00505       mid3 = (blobs3[blobi][(k+3)%4] + corners1[(i2+1)%4])/2;
00506     else
00507       mid3 = corners1[(i2+1)%4];
00508     c1 = corners2[(j1+2)%4];
00509     c2 = blobs3[blobi][(k+2)%4];
00510     c3 = corners1[(i2+2)%4];
00511         }
00512       }
00513 
00514     }
00515 
00516     if (found) {
00517       // Found a brick, figure out where the top / left / etc sides are
00518 
00519       // Debug shapes
00520       NEW_SHAPE(centerp, PointData, new PointData(ShS, center));
00521       NEW_SHAPE(mid1p, PointData, new PointData(ShS, mid1));
00522       NEW_SHAPE(mid2p, PointData, new PointData(ShS, mid2));
00523       NEW_SHAPE(mid3p, PointData, new PointData(ShS, mid3));
00524       NEW_SHAPE(c1p, PointData, new PointData(ShS, c1));
00525       NEW_SHAPE(c2p, PointData, new PointData(ShS, c2));
00526       NEW_SHAPE(c3p, PointData, new PointData(ShS, c3));
00527       centerp->setColor(rgb(150,0,255));
00528       mid1p->setColor(rgb(150,0,255));
00529       mid2p->setColor(rgb(150,0,255));
00530       mid3p->setColor(rgb(150,0,255));
00531       c1p->setColor(rgb(150,0,255));
00532       c2p->setColor(rgb(150,0,255));
00533       c3p->setColor(rgb(150,0,255));
00534       
00535       Point GFL, GFR, GBL, GBR, TFL, TFR, TBL, TBR;
00536       
00537       TFR = center;
00538       if (mid1.isBelow(center, camcentric) && mid1.isBelow(mid2, camcentric) && mid1.isBelow(mid3, camcentric)) {
00539         GFR = mid1;
00540         GBR = c1;
00541         if (mid2.isRightOf(mid3, camcentric)) {
00542     TBR = mid2;
00543     TBL = c2;
00544     TFL = mid3;
00545     GFL = c3;
00546         }
00547         else {
00548     TBR = mid3;
00549     TBL = c3;
00550     TFL = mid2;
00551     GFL = c2;
00552         }
00553       }
00554       else if (mid2.isBelow(center, camcentric) && mid2.isBelow(mid1, camcentric) && mid2.isBelow(mid3, camcentric)) {
00555         GFR = mid2;
00556         GBR = c2;
00557         if (mid1.isRightOf(mid3, camcentric)) {
00558     TBR = mid1;
00559     TBL = c1;
00560     TFL = mid3;
00561     GFL = c3;
00562         }
00563         else {
00564     TBR = mid3;
00565     TBL = c3;
00566     TFL = mid1;
00567     GFL = c1;
00568         }
00569       }
00570       else {
00571         GFR = mid3;
00572         GBR = c3;
00573         if (mid2.isRightOf(mid1, camcentric)) {
00574     TBR = mid2;
00575     TBL = c2;
00576     TFL = mid1;
00577     GFL = c1;
00578         }
00579         else {
00580     TBR = mid1;
00581     TBL = c1;
00582     TFL = mid2;
00583     GFL = c2;
00584         }
00585       }
00586       
00587       GBL = GFL + (TBL - TFL);
00588 
00589       Shape<BrickData> newBrick(ShS, GFL, GFR, GBL, GBR, TFL, TFR, TBL, TBR);
00590       result.push_back(newBrick);
00591       centerp->setParentId(newBrick->getViewableId());
00592       mid1p->setParentId(newBrick->getViewableId());
00593       mid2p->setParentId(newBrick->getViewableId());
00594       mid3p->setParentId(newBrick->getViewableId());
00595       c1p->setParentId(newBrick->getViewableId());
00596       c2p->setParentId(newBrick->getViewableId());
00597       c3p->setParentId(newBrick->getViewableId());
00598       return blobi;
00599     }
00600     else {
00601       // What do we do if we get two good faces and no third?
00602     }
00603     
00604   }
00605       }
00606     }
00607   }
00608 
00609   return -1;
00610 
00611 }
00612 
00613 
00614 
00615 
00616 
00617 /* Unified brick extraction starting from 2 or 3 blobs, each of a different color 
00618  *
00619  *************    Final Version   ***************
00620  *
00621  * Checks the relative locations of the blobs (to ensure they are adjacent enough to 
00622  * be part of the same brick)
00623  *
00624  * Computes the interior edge lines from the regions close to two faces.
00625  *
00626  * Computes the corners of each face individually. 
00627  * This step is handled in blobData::findCorners
00628  *
00629  * Combine all the corner guesses together and extrapolate missing corners.
00630  *
00631  *
00632  * Some helper functions can be found in BrickOps.h 
00633  */
00634 Shape<BrickData> BrickData::extractBrick(ShapeSpace& space, vector<Shape<BlobData> > &blobs)
00635 {
00636   unsigned int nblobs = blobs.size();
00637   std::vector<Point> centroids;
00638 
00639   ShapeRoot invalid;
00640   if (nblobs > 3 || nblobs < 2) {
00641     return ShapeRootType(invalid,BrickData);
00642   }
00643 
00644   for (unsigned int i=0; i<nblobs; i++) {
00645     centroids.push_back(blobs[i]->getCentroid());
00646   }
00647 
00648   // Check inter-blob distance
00649   // If any pair of blobs are too far apart, this set is invalid
00650   for (unsigned int i=0; i<nblobs; i++) {
00651     for (unsigned int j=i+1; j<nblobs; j++) {
00652       if (centroids[i].distanceFrom(centroids[j]) >= 
00653     blobs[i]->topLeft.distanceFrom(centroids[i]) + 
00654     blobs[j]->topLeft.distanceFrom(centroids[j])){
00655   return ShapeRootType(invalid,BrickData);  
00656       }
00657     }
00658   }
00659 
00660   for(unsigned i = 0; i < centroids.size(); i++)
00661     centroids[i].refFrameType = blobs.front()->getRefFrameType();
00662 
00663 
00664   // arbitrary face assignment, aligned as the brick is in camera space
00665   // this will probably break down if the dog tilts its head
00666   // 
00667   // if we only have two faces, we're assuming only the top and "left" faces are visible
00668   // always assume a top face is visible, becuase any shape without a top face is much more likely
00669   // to be a pyramid than a tall brick
00670   int top=-1, left=-1, right=-1;
00671   
00672   if (centroids[0].isAbove(centroids[1])) {
00673     top = 0;
00674   }
00675   else {
00676     top = 1;
00677   }
00678   if (nblobs > 2 && centroids[2].isAbove(centroids[top])) {
00679     top = 2;
00680   }
00681 
00682   if ((top != 0 && centroids[0].isLeftOf(centroids[1])) || top == 1) {
00683     left = 0;
00684   }
00685   else {
00686     left = 1;
00687   }
00688   if (nblobs>2 && top != 2 && centroids[2].isLeftOf(centroids[left])) {
00689     left = 2;
00690   }
00691 
00692   if (nblobs > 2) {
00693     if (top != 0 && left != 0) {
00694       right = 0;
00695     }
00696     else if (top != 1 && left != 1) {
00697       right = 1;
00698     }
00699     else {
00700       right = 2;
00701     }
00702   }
00703 
00704   if (top == left || top == right || left == right){
00705     std::cout<<"ERROR: Brick side misclassification!"<<std::endl;
00706     return ShapeRootType(invalid,BrickData);  
00707   }
00708 
00709 
00710   // Compute two-blob boundary regions
00711   // This is used to find the interior edges of the brick
00712   // It is also used as a second check for inter-brick distance
00713   const int INTERSECT_DIST = 5, MIN_REQUIRED_DIST = 2;
00714   std::vector<Sketch<bool> > boundaries;
00715   NEW_SKETCH_N(topEdist, uchar, visops::mdist(blobs[top]->getRendering()));
00716   NEW_SKETCH_N(leftEdist, uchar, visops::mdist(blobs[left]->getRendering()));
00717   NEW_SKETCH(tlsmall, bool, (topEdist<MIN_REQUIRED_DIST) & (leftEdist<MIN_REQUIRED_DIST));
00718   if (!tlsmall->max()){
00719     return ShapeRootType(invalid,BrickData);  
00720   }
00721   NEW_SKETCH(tl, bool, (topEdist<INTERSECT_DIST) & (leftEdist<INTERSECT_DIST));
00722   rgb green_rgb(0,0,255);
00723   tl->setColor(green_rgb);
00724   boundaries.push_back(tl);
00725 
00726   if (nblobs>2) {
00727     NEW_SKETCH_N(rightEdist, uchar, visops::mdist(blobs[right]->getRendering()));
00728     NEW_SKETCH(trsmall, bool, (topEdist<MIN_REQUIRED_DIST) & (rightEdist<MIN_REQUIRED_DIST));
00729     if (!trsmall->max()){
00730       return ShapeRootType(invalid,BrickData);
00731     } 
00732     NEW_SKETCH(tr, bool, (topEdist<INTERSECT_DIST) & (rightEdist<INTERSECT_DIST));
00733     tr->setColor(green_rgb);
00734     boundaries.push_back(tr);
00735 
00736     NEW_SKETCH(lrsmall, bool, (leftEdist<MIN_REQUIRED_DIST) & (rightEdist<MIN_REQUIRED_DIST));
00737     if (!lrsmall->max()){
00738       return ShapeRootType(invalid,BrickData);
00739     } 
00740     NEW_SKETCH(lr, bool, (leftEdist<INTERSECT_DIST) & (rightEdist<INTERSECT_DIST));
00741     lr->setColor(green_rgb);
00742     boundaries.push_back(lr);
00743   }
00744 
00745 
00746 
00747   // Begin gathering evidence for each point
00748   // This should probably be augmented by an extra vector of confidences
00749   std::vector<std::vector<Point> > points(8);
00750 
00751   // Arbitrary corner / face assignemt (in cam space)
00752   //
00753   //      5------6
00754   //     /   T  /|
00755   //    /(4)   / 7
00756   //   1------2 / <-- R
00757   //   |  L   |/
00758   //   0------3
00759   //    
00760 
00761 
00762   // Construct the interior lines
00763   // Add their guesses to the appropriate points on the brick
00764   NEW_SHAPE(tlline, LineData, LineData::extractLine(boundaries[0]));
00765   Shape<LineData> trline, lrline;
00766 
00767   if (right!=-1) {
00768     trline = LineData::extractLine(boundaries[1]);
00769     lrline = LineData::extractLine(boundaries[2]);
00770 
00771     // shorten interior lines based on their intersections
00772     bool on1=false, on2=false;
00773     if (tlline.isValid() && trline.isValid()) {
00774       Point isectPt = tlline->intersectionWithLine(trline, on1, on2);
00775       if (on1) {
00776   tlline->rightPt().setCoords(isectPt);
00777       }
00778       if (on2) {
00779   trline->leftPt().setCoords(isectPt);
00780       }
00781     }
00782 
00783     if (tlline.isValid() && lrline.isValid()) {
00784       Point isectPt = tlline->intersectionWithLine(lrline, on1, on2);
00785       if (on1) {
00786   tlline->rightPt().setCoords(isectPt);
00787       }
00788       if (on2) {
00789   lrline->topPt().setCoords(isectPt);
00790       }
00791     }
00792 
00793     if (trline.isValid() && lrline.isValid()) {
00794       Point isectPt = trline->intersectionWithLine(lrline, on1, on2);
00795       if (on1) {
00796   trline->leftPt().setCoords(isectPt);
00797       }
00798       if (on2) {
00799   lrline->topPt().setCoords(isectPt);
00800       }
00801     }
00802 
00803 
00804     if (trline.isValid()) {
00805       points[2].push_back(trline->leftPt());
00806       points[6].push_back(trline->rightPt());
00807     }
00808 
00809     if (lrline.isValid()) {
00810       points[2].push_back(lrline->topPt());
00811       points[3].push_back(lrline->bottomPt());
00812     }
00813   }
00814 
00815   if (tlline.isValid()) {
00816     points[1].push_back(tlline->leftPt());
00817     points[2].push_back(tlline->rightPt());
00818   }
00819 
00820 
00821 
00822   // Extract the corners of the blob using the derivative approach
00823   //
00824   // corners are coming out of findCorners() in counter-clock-wise order around the blob
00825   //  with unknown starting position
00826   //
00827   // the findCorners function in BlobData is the other important part of the algorithm
00828   // Several different methods of corner extraction can be connected there. 
00829   std::vector<Point> candidates;
00830 
00831   // top face
00832 
00833   // Compute an orthogonal bounding box from the top-left line
00834   if (tlline.isValid()) {
00835     if (trline.isValid() && trline->getLength() > tlline->getLength()) {
00836       candidates = findOrthogonalBoundingBox(space, blobs[top], centroids[top], trline);
00837     }
00838     else {
00839       candidates = findOrthogonalBoundingBox(space, blobs[top], centroids[top], tlline);      
00840     }
00841   }
00842   else if (trline.isValid()) {
00843     candidates = findOrthogonalBoundingBox(space, blobs[top], centroids[top], trline);
00844   }
00845   
00846   for(unsigned i = 0; i < candidates.size(); i++)
00847     candidates[i].refFrameType = blobs.front()->getRefFrameType();
00848   
00849   float cornerValue; 
00850 
00851   std::vector<Point> tcorners = blobs[top]->findCorners(4, candidates, cornerValue);
00852 
00853   for(unsigned i = 0; i < tcorners.size(); i++)
00854     tcorners[i].refFrameType = blobs.front()->getRefFrameType();
00855   
00856   if (tcorners.size() == 4) {
00857     
00858     // Sort out which corner is which
00859     // if there's a clear left-most corner, its corner 1
00860     // if two corners are close in left-ness, then they should be 1 and 5
00861     unsigned int leftCorner = 0;
00862     for (unsigned int i=1; i<4; i++){
00863       if (tcorners[i].isLeftOf(tcorners[leftCorner])) {
00864   leftCorner = i;
00865       }
00866     }
00867     int closeCorner = -1;
00868     float mostLeft = tcorners[leftCorner].coordX();
00869     const int MAX_CLOSE_DIST = 5;
00870     for (unsigned int i=0; i<4; i++) {
00871       if (i != leftCorner && tcorners[i].coordX() - mostLeft < MAX_CLOSE_DIST) {
00872   closeCorner = i;
00873       }
00874     }
00875     
00876     if (closeCorner != -1) {
00877       // If 5 was actually left-most, switch leftCorner to 1
00878       if ((unsigned int)closeCorner == (leftCorner+1)%4) {
00879   leftCorner = closeCorner;
00880       }
00881       else if ((unsigned int)closeCorner != (leftCorner+3)%4) {
00882   std::cout<<"WARNING, opposite corners are close together!"<<std::endl;
00883       }
00884     }
00885     NEW_SHAPE(top1, PointData, PointData(space, tcorners[leftCorner]));
00886     points[1].push_back(tcorners[leftCorner]);
00887     points[2].push_back(tcorners[(leftCorner+1)%4]);
00888     points[6].push_back(tcorners[(leftCorner+2)%4]);
00889     points[5].push_back(tcorners[(leftCorner+3)%4]);
00890 
00891   }
00892   else {
00893     // Some versions of findCorners don't always return 4 corners. 
00894     // How to handle these cases is ambiguous at best. 
00895   }
00896 
00897   // repeat with other faces
00898 
00899   // left face
00900   candidates.clear();
00901   if (tlline.isValid()) {
00902     if (lrline.isValid() && lrline->getLength() > tlline->getLength()) {
00903       candidates = findOrthogonalBoundingBox(space, blobs[left], centroids[left], lrline);
00904     }
00905     else {
00906       candidates = findOrthogonalBoundingBox(space, blobs[left], centroids[left], tlline);      
00907     }
00908   }
00909   else if (trline.isValid()) {
00910     candidates = findOrthogonalBoundingBox(space, blobs[left], centroids[left], lrline);
00911   }
00912 
00913   for (unsigned int i=0; i<candidates.size(); i++) {
00914     NEW_SHAPE(candidate, PointData, PointData(space, candidates[i]));
00915     candidate->setParentId(blobs[left]->getViewableId());
00916   }
00917   std::vector<Point> lcorners = blobs[left]->findCorners(4, candidates, cornerValue);
00918   for(unsigned i = 0; i < lcorners.size(); i++)
00919     lcorners[i].refFrameType = blobs.front()->getRefFrameType();
00920   
00921   if (lcorners.size() == 4) {
00922     
00923     // if there's a clear right-most corner, its corner 3
00924     // if two corners are close in right-ness, then they should 3 and 2
00925     unsigned int rightCorner = 0;
00926     for (unsigned int i=1; i<4; i++){
00927       if (lcorners[i].isRightOf(lcorners[rightCorner])) {
00928   rightCorner = i;
00929       }
00930     }
00931     int closeCorner = -1;
00932     float mostRight = lcorners[rightCorner].coordX();
00933     const int MAX_CLOSE_DIST = 5;
00934     for (unsigned int i=0; i<4; i++) {
00935       if (i != rightCorner && mostRight - lcorners[i].coordX() < MAX_CLOSE_DIST) {
00936   closeCorner = i;
00937       }
00938     }
00939     
00940     if (closeCorner != -1) {
00941       // If 2 was actually right-most, switch rightCorner to 3
00942       if ((unsigned int)closeCorner == (rightCorner+3)%4) {
00943   rightCorner = closeCorner;
00944       }
00945       else if ((unsigned int)closeCorner != (rightCorner+1)%4) {
00946   std::cout<<"WARNING, opposite corners are close together!"<<std::endl;
00947       }
00948     }
00949     NEW_SHAPE(left2, PointData, PointData(space, lcorners[rightCorner]));
00950     points[3].push_back(lcorners[rightCorner]);
00951     points[2].push_back(lcorners[(rightCorner+1)%4]);
00952     points[1].push_back(lcorners[(rightCorner+2)%4]);
00953     points[0].push_back(lcorners[(rightCorner+3)%4]);
00954 
00955   }
00956   else {
00957 
00958   }
00959 
00960   // right face
00961   if (right != -1) {
00962 
00963     candidates.clear();
00964     if (trline.isValid()) {
00965       if (lrline.isValid() && lrline->getLength() > trline->getLength()) {
00966   candidates = findOrthogonalBoundingBox(space, blobs[right], centroids[right], lrline);
00967       }
00968       else {
00969   candidates = findOrthogonalBoundingBox(space, blobs[right], centroids[right], trline);      
00970       }
00971     }
00972     else if (lrline.isValid()) {
00973       candidates = findOrthogonalBoundingBox(space, blobs[right], centroids[right], lrline);
00974     }
00975 
00976     std::vector<Point> rcorners = blobs[right]->findCorners(4, candidates, cornerValue);
00977     
00978     for(unsigned i = 0; i < rcorners.size(); i++)
00979       rcorners[i].refFrameType = blobs.front()->getRefFrameType();
00980     
00981     
00982     if (rcorners.size() == 4) {
00983     
00984       // if there's a clear bottom-most corner, its corner 3
00985       // if two corners are close in bottom-ness, then they should 3 and 7
00986       unsigned int bottomCorner = 0;
00987       for (unsigned int i=1; i<4; i++){
00988   if (rcorners[i].isBelow(rcorners[bottomCorner])) {
00989     bottomCorner = i;
00990   }
00991       }
00992       int closeCorner = -1;
00993       float mostBottom = rcorners[bottomCorner].coordY();
00994       const int MAX_CLOSE_DIST = 5;
00995       for (unsigned int i=0; i<4; i++) {
00996   if (i != bottomCorner && mostBottom - rcorners[i].coordY() < MAX_CLOSE_DIST) {
00997     closeCorner = i;
00998   }
00999       }
01000     
01001       if (closeCorner != -1) {
01002   // If 7 was actually bottom-most, switch bottomCorner to 3
01003   if ((unsigned int)closeCorner == (bottomCorner+3)%4) {
01004     bottomCorner = closeCorner;
01005   }
01006   else if ((unsigned int)closeCorner != (bottomCorner+1)%4) {
01007     std::cout<<"WARNING, opposite corners are close together!"<<std::endl;
01008   }
01009       }
01010       NEW_SHAPE(right3, PointData, PointData(space,rcorners[bottomCorner]));
01011       points[3].push_back(rcorners[bottomCorner]);
01012       points[7].push_back(rcorners[(bottomCorner+1)%4]);
01013       points[6].push_back(rcorners[(bottomCorner+2)%4]);
01014       points[2].push_back(rcorners[(bottomCorner+3)%4]);
01015 
01016     }
01017   }
01018 
01019 
01020   // If we have additional ways of extracting candidate corners, 
01021   // add the corners they find to the vector of corners now.
01022 
01023 
01024   // debug output
01025   /*for (unsigned int i=0; i<8; i++){
01026     for (unsigned int j=0; j<points[i].size(); j++) {
01027       NEW_SHAPE(corner, PointData, PointData(space, points[i][j]));
01028       char name[10];
01029       sprintf(name, "corner%d%d",i,j);
01030       corner->setName(name);
01031     }
01032     }*/
01033 
01034 
01035   // Now merge all our candidate points to get the final brick
01036 
01037   vector<Point> finalCorners(8);
01038 
01039   // for now just average corners together to get the last corners
01040   // should at least weight the average based on confidence
01041   // could also do statistics
01042   // produce a final confidence based on the std. deviation
01043 
01044   // if we didn't get the center point of the brick then we don't have a shot
01045   // top-left line also is pretty critical, 
01046   // though I probably should re-work below to work in the case where top and right only work well
01047   if (points[2].size()==0 || points[1].size()==0){
01048     return ShapeRootType(invalid,BrickData);    
01049   }
01050 
01051   Point empty(0,0);
01052 
01053 
01054   // Lots of cases for which corners are visible and extrapolating the others
01055 
01056   for (unsigned int i=0; i<8; i++) {
01057     finalCorners[i] = empty;
01058     for (unsigned int j=0; j<points[i].size(); j++) {
01059       finalCorners[i]+=points[i][j];
01060     }
01061     if (points[i].size() > 0) {
01062       finalCorners[i]/=points[i].size();
01063     }
01064   }
01065 
01066   if (points[3].size()==0){
01067     // These should be easier cases
01068     return ShapeRootType(invalid,BrickData);        
01069   }
01070 
01071   if (points[6].size() == 0) {
01072     // If we have the top left line but not corner 6, infer corner 6 from the thickness of the top side
01073     if (tlline.isValid()) {
01074       NEW_SKETCH_N(topRendering, bool, blobs[top]->getRendering());
01075       Point topPt = (Region::extractRegion(topRendering)).mostDistantPtFrom(tlline.getData());
01076       NEW_SHAPE(intersectLine, LineData, LineData(space, topPt, tlline->getThetaNorm()));
01077       Point intersectPoint = intersectLine->intersectionWithLine(tlline);
01078       // lower confidence result
01079       finalCorners[6] = topPt+finalCorners[2]-intersectPoint;
01080     }
01081     // can also use right left line and the right side, but the top side is more likely to be good
01082     else {
01083       return ShapeRootType(invalid,BrickData);        
01084     }
01085  }
01086 
01087   if (points[0].size() == 0) {
01088     finalCorners[0] = finalCorners[3] + finalCorners[1]-finalCorners[2];
01089   }
01090 
01091   if (points[5].size() == 0) {
01092     finalCorners[5] = finalCorners[6] + finalCorners[1]-finalCorners[2];
01093   }
01094 
01095   if (points[7].size() == 0) {
01096     finalCorners[7] = finalCorners[3] + finalCorners[6]-finalCorners[2];
01097   }
01098 
01099   finalCorners[4] = finalCorners[5] + finalCorners[7] - finalCorners[6] +
01100     finalCorners[5] + finalCorners[0] - finalCorners[1] +
01101     finalCorners[0] + finalCorners[7] - finalCorners[3];
01102   finalCorners[4]/=3.f;
01103 
01104   // left == front for generalized brick
01105   NEW_SHAPE(returnbrick, BrickData, new BrickData(space, 
01106               finalCorners[0], finalCorners[3],
01107               finalCorners[4], finalCorners[7],
01108               finalCorners[1], finalCorners[2],
01109               finalCorners[5], finalCorners[6]));
01110   return returnbrick;
01111     
01112 }
01113 
01114 
01115 
01116   // Generates a wide bounding box around the blob from a parallel line along one edge
01117   // This bounding box will be used as a starting point for the quadrilateral-fitting algorithm
01118   // 
01119   // Generates 4 points based on the line, centroid of the blob, and parameters for extending the bounds
01120   // Then sorts the points into counter-clockwise order to satisfy the ordering constraints to make other 
01121   // extrapolations possible. 
01122 vector<Point> BrickData::findOrthogonalBoundingBox(ShapeSpace& space, Shape<BlobData> blob, Point centroid, Shape<LineData> parallel)
01123 {
01124   const float PARALLEL_EXTEND_FACTOR = .6f, ORTHO_EXTEND_FACTOR = .6f;
01125 
01126   vector<Point> candidates;
01127   LineData candidate1(space, parallel->end1Pt(), parallel->end2Pt());
01128 
01129   //candidate1.setEndPts(parallel->end1Pt(), parallel->end2Pt());
01130   Point parallelExtend(candidate1.end2Pt() - candidate1.end1Pt());
01131   parallelExtend *= PARALLEL_EXTEND_FACTOR;
01132   LineData ortho(space, centroid, candidate1.getThetaNorm());
01133   Point orthoIsect = candidate1.intersectionWithLine(ortho);
01134   Point candidate2Offset = (centroid - orthoIsect) * 2.f;
01135   Point orthoExtend = candidate2Offset * ORTHO_EXTEND_FACTOR;
01136 
01137   LineData candidate2(space, candidate1.end1Pt() + candidate2Offset + orthoExtend - parallelExtend,
01138           candidate1.end2Pt() + candidate2Offset + orthoExtend + parallelExtend);
01139   candidate1.setEndPts(candidate1.end1Pt() - orthoExtend - parallelExtend,
01140            candidate1.end2Pt() - orthoExtend + parallelExtend);
01141   candidates.push_back(candidate1.leftPt());
01142   candidates.push_back(candidate1.rightPt());
01143   candidates.push_back(candidate2.rightPt());
01144   candidates.push_back(candidate2.leftPt());
01145 
01146   // debug output
01147   for (unsigned int i=0; i<candidates.size(); i++) {
01148     NEW_SHAPE_N(candidate, PointData, PointData(space, candidates[i]));
01149     candidate->setParentId(blob->getViewableId());
01150   }
01151 
01152   // order counter-clockwise around the blob before returning
01153   Point centerPoint = (candidates[0] + candidates[1] + candidates[2] + candidates[3]) / 4.f;
01154   vector<float> centerAngles;
01155   for (unsigned int i=0; i<candidates.size(); i++) {
01156     NEW_SHAPE_N(centerLine, LineData, LineData(space, centerPoint, candidates[i]));
01157     centerLine->setParentId(blob->getViewableId());
01158     centerAngles.push_back(atan2(centerLine->end2Pt().coordY() - centerLine->end1Pt().coordY(),
01159          centerLine->end2Pt().coordX() - centerLine->end1Pt().coordX()));
01160   }
01161 
01162 
01163   vector<Point> orderedPoints;
01164   
01165   int maxi = 0, mini = 0;
01166   float maxAng = centerAngles[0];
01167   float minAng = maxAng;
01168   
01169   for (unsigned int i=1; i<candidates.size(); i++) {
01170     if (centerAngles[i] > maxAng) {
01171       maxAng = centerAngles[i];
01172       maxi = i;
01173     }
01174     if (centerAngles[i] < minAng) {
01175       minAng = centerAngles[i];
01176       mini = i;
01177     }
01178        
01179   }
01180 
01181   orderedPoints.push_back(candidates[maxi]);
01182   
01183   float lastMax = maxAng;
01184   for (unsigned int i=1; i<candidates.size(); i++) {
01185     maxi = mini;
01186     maxAng = minAng;
01187     for (unsigned int j=0; j<candidates.size(); j++) {
01188       float curAng = centerAngles[j];
01189       if (curAng > maxAng && curAng < lastMax) {
01190   maxi = j;
01191   maxAng = curAng;
01192       }
01193     }
01194     orderedPoints.push_back(candidates[maxi]);
01195     lastMax = maxAng;
01196   }
01197   
01198   // debug output
01199   for (unsigned int i=0; i<candidates.size(); i++) {
01200     NEW_SHAPE(orderedcandidate, PointData, PointData(space, orderedPoints[i]));
01201     orderedcandidate->setParentId(blob->getViewableId());
01202   }
01203 
01204   return orderedPoints;
01205 }
01206 
01207 
01208 
01209 } // namespace

DualCoding 5.1CVS
Generated Sat May 4 06:29:26 2013 by Doxygen 1.6.3