00001
00002 #include <iostream>
00003 #include <vector>
00004
00005 #include "Vision/cmvision.h"
00006
00007 #include "SketchSpace.h"
00008 #include "Sketch.h"
00009 #include "ShapeSpace.h"
00010 #include "ShapeRoot.h"
00011
00012 #include "BlobData.h"
00013 #include "LineData.h"
00014 #include "ShapeBlob.h"
00015 #include "visops.h"
00016 #include "Region.h"
00017 #include "ShapeLine.h"
00018 #include "ShapePoint.h"
00019
00020 #include "BrickOps.h"
00021
00022 using namespace std;
00023
00024 namespace DualCoding {
00025
00026 BlobData::BlobData(ShapeSpace& _space,
00027 const Point &_topLeft, const Point &_topRight,
00028 const Point &_bottomLeft, const Point &_bottomRight,
00029 const float _area, const std::vector<run> &_runvec,
00030 const BlobOrientation_t _orientation, coordinate_t _assumedHeight,
00031 rgb _rgbvalue) :
00032 BaseData(_space, getStaticType()),
00033 orientation(_orientation), assumedHeight(_assumedHeight),
00034 topLeft(_topLeft), topRight(_topRight),
00035 bottomLeft(_bottomLeft), bottomRight(_bottomRight),
00036 area(_area), runvec(_runvec)
00037 {
00038 setColor(_rgbvalue);
00039 }
00040
00041 DATASTUFF_CC(BlobData);
00042
00043
00044 Point BlobData::getCentroid() const {
00045 return Point((topLeft.coords + topRight.coords + bottomLeft.coords + bottomRight.coords) / 4,
00046 getRefFrameType());
00047 }
00048
00049 BoundingBox2D BlobData::getBoundingBox() const {
00050
00051
00052 BoundingBox2D result(topLeft.coords);
00053 result.expand(topRight.coords);
00054 result.expand(bottomLeft.coords);
00055 result.expand(bottomRight.coords);
00056 return result;
00057 }
00058
00059 void BlobData::printParams() const {
00060 cout << "Type = " << getTypeName() << " ID=" << getId() << " ParentID=" << getParentId() << endl;
00061 printf(" color = %d %d %d\n",getColor().red,getColor().green,getColor().blue);
00062 cout << " tl=" << topLeft.coords << endl
00063 << " tr=" << topRight.coords << endl
00064 << " bl=" << bottomLeft.coords << endl
00065 << " br=" << bottomRight.coords << endl
00066 << " area=" << area << ", assumedHeight=" << assumedHeight
00067 << endl;
00068 }
00069
00070 Sketch<bool>* BlobData::render() const {
00071 SketchSpace &SkS = space->getDualSpace();
00072 Sketch<bool>* result = new Sketch<bool>(SkS, "render("+getName()+")");
00073 *result = false;
00074 switch ( orientation ) {
00075 case groundplane:
00076 if ( space->getRefFrameType() == camcentric ) {
00077 for ( std::vector<BlobData::run>::const_iterator it = runvec.begin();
00078 it != runvec.end(); it++ ) {
00079 const BlobData::run &r = *it;
00080 int const xstop = r.x + r.width;
00081 for ( int xi=r.x; xi<xstop; xi++ )
00082 (*result)(xi, r.y) = true;
00083 }
00084 } else {
00085 fmat::Column<3> tl(topLeft.getCoords()), tr(topRight.getCoords()),
00086 bl(bottomLeft.getCoords()), br(bottomRight.getCoords());
00087 SkS.applyTmat(tl); SkS.applyTmat(tr); SkS.applyTmat(bl); SkS.applyTmat(br);
00088 LineData::drawline2d(*result, (int)tl[0], (int)tl[1], (int)tr[0], (int)tr[1]);
00089 LineData::drawline2d(*result, (int)tr[0], (int)tr[1], (int)br[0], (int)br[1]);
00090 LineData::drawline2d(*result, (int)br[0], (int)br[1], (int)bl[0], (int)bl[1]);
00091 LineData::drawline2d(*result, (int)bl[0], (int)bl[1], (int)tl[0], (int)tl[1]);
00092 }
00093 break;
00094 case pillar:
00095 case poster:
00096 cout << "BlobData::render() : Can't yet render blobs in pillar/poster orientations" << endl;
00097 break;
00098 }
00099 return result;
00100 }
00101
00102
00103 void BlobData::applyTransform(const fmat::Transform& Tmat, const ReferenceFrameType_t newref) {
00104 topLeft.applyTransform(Tmat,newref);
00105 topRight.applyTransform(Tmat,newref);
00106 bottomLeft.applyTransform(Tmat,newref);
00107 bottomRight.applyTransform(Tmat,newref);
00108 }
00109
00110 void BlobData::projectToGround(const fmat::Transform& camToBase, const PlaneEquation& gndplane) {
00111 switch ( orientation ) {
00112 case groundplane:
00113 topLeft.projectToGround(camToBase,gndplane);
00114 topRight.projectToGround(camToBase,gndplane);
00115 bottomLeft.projectToGround(camToBase,gndplane);
00116 bottomRight.projectToGround(camToBase,gndplane);
00117 break;
00118 case pillar:
00119 bottomLeft.projectToGround(camToBase,gndplane);
00120 bottomRight.projectToGround(camToBase,gndplane);
00121 topLeft = bottomLeft;
00122 topRight = bottomRight;
00123 topLeft.coords[2] += assumedHeight;
00124 topRight.coords[2] += assumedHeight;
00125 break;
00126 case poster:
00127
00128
00129 PlaneEquation elevatedPlane = gndplane;
00130 float const new_displacement = elevatedPlane.getDisplacement() + assumedHeight*elevatedPlane.getZsign();
00131 elevatedPlane.setDisplacement(new_displacement);
00132
00133
00134 Point centroid = getCentroid();
00135 centroid.projectToGround(camToBase, elevatedPlane);
00136 bottomLeft = centroid;
00137 bottomRight = centroid;
00138 topLeft = centroid;
00139 topRight = centroid;
00140 break;
00141 }
00142 update_derived_properties();
00143 }
00144
00145 void BlobData::update_derived_properties() {
00146 switch ( orientation ) {
00147
00148 case groundplane:
00149
00150 float side1, side2, side3, side4,side5, areatri1, areatri2, s;
00151 side1 = topLeft.distanceFrom(topRight);
00152 side2 = topRight.distanceFrom(bottomRight);
00153 side3 = topLeft.distanceFrom(bottomRight);
00154 side4 = bottomLeft.distanceFrom(bottomRight);
00155 side5 = topLeft.distanceFrom(bottomLeft);
00156
00157 s =(side1+side2+side3) / 2;
00158 areatri1=sqrt(s*(s-side1)*(s-side2)*(s-side3));
00159
00160 s =(side3+side4+side5) / 2;
00161 areatri2=sqrt(s*(s-side3)*(s-side4)*(s-side5));
00162
00163 area = areatri1 + areatri2;
00164 break;
00165
00166 case poster:
00167 area = (bottomRight-bottomLeft).xyNorm() * assumedHeight;
00168 break;
00169
00170 case pillar:
00171
00172 float radius = (bottomRight-bottomLeft).xyNorm() / 2;
00173 area = radius * radius * M_PI;
00174 break;
00175 }
00176 }
00177
00178 bool BlobData::isMatchFor(const ShapeRoot& other) const {
00179 if ( ! (isSameTypeAs(other) && isSameColorAs(other)) )
00180 return false;
00181 const Shape<BlobData>& other_blob = ShapeRootTypeConst(other,BlobData);
00182 float dist = getCentroid().distanceFrom(other_blob->getCentroid());
00183 return dist < 2*sqrt(area);
00184 }
00185
00186 bool BlobData::updateParams(const ShapeRoot& other, bool forceUpdate) {
00187 const Shape<BlobData>& other_blob = ShapeRootTypeConst(other,BlobData);
00188 int other_conf = other_blob->confidence;
00189 if (other_conf <= 0) {
00190 if (forceUpdate)
00191 other_conf = 1;
00192 else
00193 return false;
00194 }
00195 confidence += other_conf;
00196 const int sumconf = confidence + other_conf;
00197 topLeft = (topLeft*confidence + other_blob->topLeft*other_conf) / sumconf;
00198 topRight = (topRight*confidence + other_blob->topRight*other_conf) / sumconf;
00199 bottomLeft = (bottomLeft*confidence + other_blob->bottomLeft*other_conf) / sumconf;
00200 bottomRight = (bottomRight*confidence + other_blob->bottomRight*other_conf) / sumconf;
00201 float const newArea = (area*confidence + other_blob->area*other_conf) / sumconf;
00202 update_derived_properties();
00203 area = newArea;
00204 return true;
00205 }
00206
00207
00208
00209
00210 std::vector<Shape<BlobData> >
00211 BlobData::extractBlobs(const Sketch<bool> &sketch,
00212 int minarea,
00213 BlobOrientation_t orient,
00214 coordinate_t height,
00215 int maxblobs) {
00216
00217
00218
00219
00220
00221 set<color_index> dummyColors;
00222 dummyColors.insert(1);
00223 map<color_index,int> minareas;
00224 minareas[1] = minarea;
00225 map<color_index,BlobOrientation_t> orients;
00226 orients[1] = orient;
00227 map<color_index,coordinate_t> heights;
00228 heights[1] = height;
00229 std::vector<Shape<BlobData> > result(extractBlobs((Sketch<uchar>&)sketch,dummyColors,minareas,orients,heights,maxblobs));
00230 rgb sketchColor(sketch->getColor());
00231 for ( std::vector<Shape<BlobData> >::iterator it = result.begin();
00232 it != result.end(); it++ )
00233 (*it)->setColor(sketchColor);
00234 return result;
00235 }
00236
00237 std::vector<Shape<BlobData> >
00238 BlobData::extractBlobs(const Sketch<uchar> &sketch,
00239 int minarea,
00240 BlobOrientation_t orient,
00241 coordinate_t height,
00242 int maxblobs) {
00243 const int numColors = ProjectInterface::getNumColors();
00244 set<color_index> colors;
00245 map<color_index,int> minareas;
00246 map<color_index,BlobOrientation_t> orients;
00247 map<color_index,coordinate_t> heights;
00248 for (int i = 1; i < numColors; i++) {
00249 colors.insert(i);
00250 minareas[i] = minarea;
00251 orients[i] = orient;
00252 heights[i] = height;
00253 }
00254 return extractBlobs(sketch, colors, minareas, orients, heights, maxblobs);
00255 }
00256
00257 std::vector<Shape<BlobData> >
00258 BlobData::extractBlobs(const Sketch<uchar> &sketch,
00259 const std::set<color_index>& colors,
00260 const std::map<color_index,int>& minareas,
00261 const std::map<color_index,BlobOrientation_t>& orients,
00262 const std::map<color_index,coordinate_t>& heights,
00263 int maxblobs) {
00264 int parent = sketch->getId();
00265 uchar *pixels = &((*sketch.pixels)[0]);
00266
00267
00268 int const maxRuns = (sketch.width * sketch.height) / 8;
00269 CMVision::run<uchar> *rle_buffer = new CMVision::run<uchar>[maxRuns];
00270 unsigned int const numRuns = CMVision::EncodeRuns(rle_buffer, pixels, sketch.width, sketch.height, maxRuns);
00271
00272
00273 CMVision::ConnectComponents(rle_buffer,numRuns);
00274 int const maxRegions = (sketch.width * sketch.height) / 16;
00275 CMVision::region *regions = new CMVision::region[maxRegions];
00276 unsigned int numRegions = CMVision::ExtractRegions(regions, maxRegions, rle_buffer, numRuns);
00277 unsigned int const numColors = ProjectInterface::getNumColors();
00278 CMVision::color_class_state *ccs = new CMVision::color_class_state[numColors];
00279 unsigned int const maxArea = CMVision::SeparateRegions(ccs, numColors, regions, numRegions);
00280 CMVision::SortRegions(ccs, numColors, maxArea);
00281 CMVision::MergeRegions(ccs, int(numColors), rle_buffer);
00282
00283
00284 std::vector<Shape<BlobData> > result(20);
00285 result.clear();
00286 ShapeSpace &ShS = sketch->getSpace().getDualSpace();
00287
00288 for (set<color_index>::const_iterator it = colors.begin();
00289 it != colors.end(); it++) {
00290 int const color = *it;
00291 const CMVision::region* list_head = ccs[color].list;
00292 if ( list_head != NULL ) {
00293 const rgb rgbvalue = ProjectInterface::getColorRGB(color);
00294 int const minarea = (minareas.find(color)==minareas.end()) ? 50 : const_cast<map<color_index,int>&>(minareas)[color];
00295 BlobOrientation_t const orient = (orients.find(color)==orients.end()) ?
00296 groundplane : const_cast<map<color_index,BlobOrientation_t>&>(orients)[color];
00297 coordinate_t const height = (heights.find(color)==heights.end()) ? 0 : const_cast<map<color_index,coordinate_t>&>(heights)[color];
00298 for (int i=0; list_head!=NULL && i<maxblobs && list_head->area >= minarea;
00299 list_head = list_head->next, i++) {
00300 BlobData* blobdat = new_blob(ShS,*list_head, rle_buffer, orient, height, rgbvalue);
00301 blobdat->setParentId(parent);
00302 result.push_back(Shape<BlobData>(blobdat));
00303 }
00304 }
00305 }
00306 delete[] ccs;
00307 delete[] regions;
00308 delete[] rle_buffer;
00309 return result;
00310 }
00311
00312 BlobData* BlobData::new_blob(ShapeSpace& space,
00313 const CMVision::region ®,
00314 const CMVision::run<CMVision::uchar> *rle_buff,
00315 const BlobOrientation_t orient,
00316 const coordinate_t height,
00317 const rgb rgbvalue) {
00318 int const x1 = reg.x1;
00319 int const y1 = reg.y1;
00320 int const x2 = reg.x2;
00321 int const y2 = reg.y2;
00322
00323
00324 int numruns = 0;
00325 for (int runidx = reg.run_start; runidx != -1;
00326 runidx = rle_buff[runidx].next ? rle_buff[runidx].next : -1)
00327 ++numruns;
00328 std::vector<BlobData::run> runvec(numruns);
00329 runvec.clear();
00330
00331 for (int runidx = reg.run_start; runidx != -1;
00332 runidx = rle_buff[runidx].next ? rle_buff[runidx].next : -1) {
00333 const CMVision::run<uchar> &this_run = rle_buff[runidx];
00334 runvec.push_back(BlobData::run(this_run.x, this_run.y, this_run.width));
00335 }
00336 if ( space.getRefFrameType() == camcentric )
00337 return new BlobData(space,
00338 Point(x1,y1,0,camcentric),Point(x2,y1,0,camcentric),
00339 Point(x1,y2,0,camcentric),Point(x2,y2,0,camcentric),
00340 reg.area, runvec, orient, height, rgbvalue);
00341 else
00342 return new BlobData(space,
00343 Point(x2,y2,0,space.getRefFrameType()),Point(x1,y2,0,space.getRefFrameType()),
00344 Point(x2,y1,0,space.getRefFrameType()),Point(x1,y1,0,space.getRefFrameType()),
00345 reg.area, runvec, orient, height, rgbvalue);
00346 }
00347
00348
00349
00350
00351
00352
00353
00354
00355
00356
00357
00358
00359
00360
00361
00362
00363
00364 std::vector<Point> BlobData::findCorners(unsigned int nExpected,
00365 std::vector<Point>& candidates,
00366 float &bestValue) {
00367
00368 std::vector<Point> fitCorners = findCornersShapeFit(nExpected, candidates, bestValue);
00369
00370
00371 for (unsigned int i=0; i<fitCorners.size(); i++){
00372 NEW_SHAPE(fitline, LineData, LineData(*space, fitCorners[i], fitCorners[(i+1)%nExpected]));
00373 fitline->setParentId(getViewableId());
00374 }
00375
00376
00377
00378
00379 bool onEdge = false;
00380 int width = space->getDualSpace().getWidth();
00381 int height = space->getDualSpace().getHeight();
00382 for (unsigned int i=0; i<nExpected; i++) {
00383 if (fitCorners[i].coordX() < 5 || fitCorners[i].coordX() > width - 5 ||
00384 fitCorners[i].coordY() < 5 || fitCorners[i].coordY() > height - 5) {
00385 onEdge = true;
00386 break;
00387 }
00388 }
00389 if (onEdge && nExpected == 4) {
00390 std::vector<int> outsideCandidates;
00391 for (unsigned int i=0; i<nExpected; i++) {
00392 if (candidates[i].coordX() < 5 || candidates[i].coordX() > width - 5 ||
00393 candidates[i].coordY() < 5 || candidates[i].coordY() > height - 5) {
00394 outsideCandidates.push_back(i);
00395 }
00396 }
00397
00398
00399 std::vector<Point> candidates3(candidates), candidates5;
00400
00401 if (outsideCandidates.size() == 0) {
00402 std::cout<<"Err? final points are near the edge, but the candidates aren't?"<<std::endl;
00403 }
00404
00405
00406
00407
00408 if (outsideCandidates.size() == 1) {
00409 int outC = outsideCandidates[0];
00410 candidates3.erase(candidates3.begin() + outC);
00411
00412 Point p1, p2;
00413 if (candidates[outC].coordX() < 5) {
00414 p1.setCoords(0,0);
00415 p2.setCoords(0,height);
00416 }
00417 else if (candidates[outC].coordX() > width - 5) {
00418 p1.setCoords(width,0);
00419 p2.setCoords(width,height);
00420 }
00421 else if (candidates[outC].coordY() < 5) {
00422 p1.setCoords(0,0);
00423 p2.setCoords(width,0);
00424 }
00425 else {
00426 p1.setCoords(0,height);
00427 p2.setCoords(width,height);
00428 }
00429 LineData edgeLine(*space, p1,p2);
00430 LineData l1(*space, candidates[(outC+3)%4], candidates[outC]);
00431 LineData l2(*space, candidates[(outC+1)%4], candidates[outC]);
00432 candidates5.push_back(candidates[(outC+3)%4]);
00433 candidates5.push_back(l1.intersectionWithLine(edgeLine));
00434 candidates5.push_back(l2.intersectionWithLine(edgeLine));
00435 candidates5.push_back(candidates[(outC+1)%4]);
00436 candidates5.push_back(candidates[(outC+2)%4]);
00437 }
00438
00439 if (outsideCandidates.size() == 2) {
00440 Point betweenOutside = (candidates[outsideCandidates[0]] + candidates[outsideCandidates[1]])/2;
00441 candidates3[outsideCandidates[0]].setCoords(betweenOutside);
00442 candidates3.erase(candidates3.begin() + outsideCandidates[1]);
00443
00444 int dC = outsideCandidates[1] - outsideCandidates[0];
00445 int c1 = outsideCandidates[1];
00446 candidates5.push_back(candidates[outsideCandidates[0]]);
00447 candidates5.push_back(betweenOutside);
00448 candidates5.push_back(candidates[outsideCandidates[1]]);
00449 candidates5.push_back(candidates[(c1+dC)%4]);
00450 candidates5.push_back(candidates[(c1+2*dC)%4]);
00451 }
00452
00453 if (outsideCandidates.size() > 2) {
00454
00455 }
00456
00457 float value3, value5;
00458 for (unsigned int i=0; i<candidates3.size(); i++) {
00459 NEW_SHAPE(candidate3, PointData, PointData(*space, candidates3[i]));
00460 candidate3->setParentId(getViewableId());
00461 }
00462 for (unsigned int i=0; i<candidates5.size(); i++) {
00463 NEW_SHAPE(candidate5, PointData, PointData(*space, candidates5[i]));
00464 candidate5->setParentId(getViewableId());
00465 }
00466 std::vector<Point> fitcorners3 = findCornersShapeFit(3, candidates3, value3);
00467 std::vector<Point> fitcorners5 = findCornersShapeFit(5, candidates5, value5);
00468 for (unsigned int i=0; i<fitcorners3.size(); i++) {
00469 NEW_SHAPE(fit3, PointData, PointData(*space, fitcorners3[i]));
00470 fit3->setParentId(getViewableId());
00471 }
00472 for (unsigned int i=0; i<fitcorners5.size(); i++) {
00473 NEW_SHAPE(fit5, PointData, PointData(*space, fitcorners5[i]));
00474 fit5->setParentId(getViewableId());
00475 }
00476 }
00477
00478
00479 return fitCorners;
00480
00481
00482
00483
00484
00485
00486
00487
00488
00489
00490
00491
00492
00493
00494
00495
00496
00497
00498
00499
00500
00501
00502
00503
00504
00505
00506
00507
00508
00509
00510
00511
00512
00513
00514
00515
00516
00517
00518
00519 }
00520
00521
00522
00523
00524
00525
00526
00527
00528
00529
00530 std::vector<Point> BlobData::findCornersDerivative()
00531 {
00532 std::vector<Point> corners;
00533
00534 float radius = sqrt((topRight.coordX()-topLeft.coordX())*(topRight.coordX()-topLeft.coordX()) +
00535 (bottomLeft.coordY()-topLeft.coordY())*(bottomLeft.coordY()-topLeft.coordY()))/2 + 1;
00536 int len = (int)(2*M_PI*radius + 1);
00537 float distances[len];
00538 std::vector<Point> points(len);
00539 Point centroid = getCentroid();
00540 NEW_SKETCH(rendering, bool, getRendering());
00541
00542 int i=0;
00543
00544 findRadialDistancesFromPoint(centroid, radius, rendering, distances, points);
00545 float gdist[len], ddist[len], d2dist[len], d3dist[len];
00546 applyGaussian(distances, gdist, len);
00547 takeDerivative(gdist, ddist, len);
00548 takeDerivative(ddist, d2dist, len);
00549 takeDerivative(d2dist, d3dist, len);
00550
00551 drawHist(gdist, len, rendering);
00552 drawHist(ddist, len, rendering);
00553 drawHist(d2dist, len, rendering);
00554
00555
00556
00557
00558
00559
00560 const float MIN_D2 = 5.f;
00561
00562 float curmin = -MIN_D2;
00563 int curi = -1;
00564 int curonpeak = 0;
00565 for (i=0; i<len; i++) {
00566 if (d2dist[i] < curmin) {
00567 curmin = d2dist[i];
00568 curi = i;
00569 curonpeak = 1;
00570 }
00571 else if (curonpeak) {
00572 if (d2dist[i] > -MIN_D2 || (d3dist[i-1] > 0 && d3dist[i] <= 0)) {
00573 curonpeak = 0;
00574 curmin = -MIN_D2;
00575 corners.push_back(points[curi]);
00576 NEW_SHAPE(cornerpoint, PointData, Shape<PointData>(*space, points[curi]));
00577 cornerpoint->setParentId(rendering->getViewableId());
00578 }
00579 }
00580 }
00581
00582
00583
00584 vector<Point> reversedCorners;
00585 for (i=corners.size()-1; i>=0; i--){
00586 reversedCorners.push_back(corners[i]);
00587 }
00588
00589 return reversedCorners;
00590 }
00591
00592
00593
00594
00595
00596
00597
00598
00599
00600
00601
00602
00603
00604
00605
00606
00607
00608
00609
00610 std::vector<Point> BlobData::findCornersDiagonal()
00611 {
00612 std::vector<Point> corners;
00613
00614 float radius = sqrt((topRight.coordX()-topLeft.coordX())*(topRight.coordX()-topLeft.coordX()) +
00615 (bottomLeft.coordY()-topLeft.coordY())*(bottomLeft.coordY()-topLeft.coordY()))/2 + 1;
00616 int len = (int)(2*M_PI*radius + 1);
00617 float distances[len];
00618 std::vector<Point> points(len);
00619 Point centroid = getCentroid();
00620 NEW_SKETCH(rendering, bool, getRendering());
00621
00622 int i=0;
00623 int maxi = 0, origmaxi = 0;
00624 bool stillmax = false;
00625
00626 maxi = findRadialDistancesFromPoint(centroid, radius, rendering, distances, points);
00627
00628
00629 int maxi2 = 0;
00630 float max2 = 0;
00631 stillmax = false;
00632 origmaxi = -1;
00633 for (i=0; i<len; i++) {
00634 if (distances[i] >= max2 &&
00635 abs(i-maxi) > len*3/8 &&
00636 abs(i-maxi) < len*5/8) {
00637 if (distances[i] > max2) {
00638 maxi2 = i;
00639 max2 = distances[i];
00640 origmaxi = maxi2;
00641 stillmax = true;
00642 }
00643 else if (stillmax){
00644 maxi2 = (origmaxi+i)/2;
00645 }
00646 }
00647 else {
00648 stillmax = false;
00649 }
00650 }
00651
00652 corners.push_back(points[maxi]);
00653 corners.push_back(points[maxi2]);
00654 std::cout<<"Corners: ("<<corners[0].coordX()<<","<<corners[0].coordY()<<") ("<<
00655 corners[1].coordX()<<","<<corners[1].coordY()<<")\n";
00656
00657
00658
00659 NEW_SHAPE(diag, LineData, Shape<LineData>(*space, corners[0], corners[1]));
00660 diag->firstPt().setActive(false);
00661 diag->secondPt().setActive(false);
00662 diag->setParentId(rendering->getViewableId());
00663
00664 NEW_SKETCH_N(filled, bool, visops::topHalfPlane(diag));
00665 NEW_SKETCH(side1, bool, filled & rendering);
00666 NEW_SKETCH(side2, bool, !filled & rendering);
00667
00668 const float MIN_PT_DIST = 3.f;
00669
00670 Point pt3 = (Region::extractRegion(side1)).mostDistantPtFrom(diag.getData());
00671 Point pt4 = (Region::extractRegion(side2)).mostDistantPtFrom(diag.getData());
00672 if (diag->perpendicularDistanceFrom(pt3) > MIN_PT_DIST)
00673 corners.push_back(pt3);
00674 if (diag->perpendicularDistanceFrom(pt4) > MIN_PT_DIST)
00675 corners.push_back(pt4);
00676
00677
00678
00679 std::vector<Point> resultCorners;
00680 std::vector<float> angles;
00681
00682 float ta;
00683 Point tp;
00684 for (i=0; i<(int)corners.size(); i++) {
00685 Point di = corners[i] - centroid;
00686 angles.push_back(atan2(di.coordY(), di.coordX()));
00687 resultCorners.push_back(corners[i]);
00688 for (int j=i-1; j>=0; j--) {
00689 if (angles[j+1] > angles[j]) {
00690 ta = angles[j];
00691 angles[j] = angles[j+1];
00692 angles[j+1] = ta;
00693 tp = resultCorners[j];
00694 resultCorners[j] = resultCorners[j+1];
00695 resultCorners[j+1] = tp;
00696 }
00697 else{
00698 break;
00699 }
00700 }
00701 }
00702
00703 NEW_SHAPE(cornerline1, LineData, Shape<LineData>(*space, resultCorners[0], resultCorners[1]));
00704 cornerline1->setParentId(rendering->getViewableId());
00705 if (resultCorners.size() > 3) {
00706 NEW_SHAPE(cornerline2, LineData, Shape<LineData>(*space, resultCorners[2], resultCorners[3]));
00707 cornerline2->setParentId(rendering->getViewableId());
00708 }
00709
00710 return resultCorners;
00711 }
00712
00713
00714
00715
00716
00717
00718
00719
00720
00721
00722
00723
00724
00725
00726
00727 std::vector<Point> BlobData::findCornersShapeFit(unsigned int ncorners, std::vector<Point>& candidates,
00728 float &bestValue)
00729 {
00730 NEW_SKETCH(rendering, bool, getRendering());
00731
00732 std::vector<Point> bestPoints(ncorners), curTest(ncorners);
00733 float bestScore;
00734 int bestEdgeCount;
00735 std::vector<std::vector<Point> > testPoints;
00736 std::vector<float> testScores;
00737 std::vector<int> testEdgeCounts;
00738
00739 if (candidates.size() == ncorners) {
00740 for (unsigned int i=0; i<ncorners; i++) {
00741 bestPoints[i].setCoords(candidates[i]);
00742 curTest[i].setCoords(candidates[i]);
00743 }
00744 }
00745 else {
00746 std::cout<<"Warning: incorrect number of candidates provided. Got "<<candidates.size()<<" but wanted "<<ncorners<<std::endl;
00747 return bestPoints;
00748 }
00749
00750 NEW_SKETCH_N(nsum, uchar, visops::neighborSum(getRendering()));
00751 NEW_SKETCH(borderPixels, bool, (nsum > 0) & (nsum < 8) & getRendering());
00752 int edgeTotal = 0;
00753 for (unsigned int x=0; x<borderPixels->getWidth(); x++) {
00754 borderPixels(x,0) = 0;
00755 borderPixels(x,borderPixels->getHeight() - 1) = 0;
00756 }
00757 for (unsigned int y=0; y<borderPixels->getHeight(); y++) {
00758 borderPixels(0,y) = 0;
00759 borderPixels(borderPixels->getWidth() - 1, y) = 0;
00760 }
00761 for (unsigned int i=0; i<borderPixels->getNumPixels(); i++) {
00762 if (borderPixels->at(i))
00763 edgeTotal++;
00764 }
00765
00766 bestScore = getBoundingQuadrilateralScore(*this, bestPoints, borderPixels, bestEdgeCount, *space);
00767
00768 int testCount = 0, testEdgeCount;
00769 Point dp;
00770 float dpDist, testRatio;
00771 bool hasMoved;
00772
00773 float annealingScalar = 1.f;
00774 bool doingRandomMovement = false;
00775 const float ANNEALING_CAP = 25.f;
00776 const float WEIGHT_SCALAR = .2f;
00777
00778 const float MIN_DISTANCE = 10.f;
00779 const float MIN_BOUNDING_RATIO = 0.8f;
00780
00781 int iterationCount = 0, annealingStart = 0;
00782
00783
00784
00785 while (annealingScalar < ANNEALING_CAP) {
00786
00787 hasMoved = false;
00788
00789
00790 for (unsigned int i=0; i<ncorners; i++) {
00791
00792 testScores.clear();
00793 testPoints.clear();
00794 testEdgeCounts.clear();
00795 testCount = 0;
00796
00797
00798
00799 for (unsigned int j=0; j<ncorners; j++)
00800 curTest[j].setCoords(bestPoints[j]);
00801 dp.setCoords(curTest[(i+1)%ncorners] - curTest[i]);
00802 dpDist = curTest[i].distanceFrom(curTest[(i+1)%ncorners]);
00803
00804 if (dpDist > MIN_DISTANCE) {
00805
00806 dp/=dpDist;
00807 curTest[i]+=dp;
00808 testRatio = getBoundingQuadrilateralInteriorPointRatio(*this, curTest, *space);
00809 if (testRatio > MIN_BOUNDING_RATIO) {
00810 testScores.push_back(getBoundingQuadrilateralScore(*this, curTest, borderPixels,
00811 testEdgeCount, *space));
00812 testPoints.push_back(curTest);
00813 testEdgeCounts.push_back(testEdgeCount);
00814 testCount++;
00815 }
00816
00817
00818 if (doingRandomMovement) {
00819 curTest[i].setCoords(bestPoints[i]);
00820 curTest[i]-=dp;
00821 testRatio = getBoundingQuadrilateralInteriorPointRatio(*this, curTest, *space);
00822 if (testRatio > MIN_BOUNDING_RATIO) {
00823 testScores.push_back(getBoundingQuadrilateralScore(*this, curTest, borderPixels,
00824 testEdgeCount, *space));
00825 testPoints.push_back(curTest);
00826 testEdgeCounts.push_back(testEdgeCount);
00827 testCount++;
00828 }
00829
00830 }
00831
00832 }
00833
00834 curTest[i].setCoords(bestPoints[i]);
00835 dp.setCoords(curTest[(i+ncorners-1)%ncorners] - curTest[i]);
00836 dpDist = curTest[i].distanceFrom(curTest[(i+ncorners-1)%ncorners]);
00837
00838 if (dpDist > MIN_DISTANCE) {
00839
00840 dp/=dpDist;
00841 curTest[i]+=dp;
00842 testRatio = getBoundingQuadrilateralInteriorPointRatio(*this, curTest, *space);
00843 if (testRatio > MIN_BOUNDING_RATIO) {
00844 testScores.push_back(getBoundingQuadrilateralScore(*this, curTest, borderPixels,
00845 testEdgeCount, *space));
00846 testPoints.push_back(curTest);
00847 testEdgeCounts.push_back(testEdgeCount);
00848 testCount++;
00849 }
00850
00851
00852 if (doingRandomMovement) {
00853 curTest[i].setCoords(bestPoints[i]);
00854 curTest[i]-=dp;
00855 testRatio = getBoundingQuadrilateralInteriorPointRatio(*this, curTest, *space);
00856 if (testRatio > MIN_BOUNDING_RATIO) {
00857 testScores.push_back(getBoundingQuadrilateralScore(*this, curTest, borderPixels,
00858 testEdgeCount, *space));
00859 testPoints.push_back(curTest);
00860 testEdgeCounts.push_back(testEdgeCount);
00861 testCount++;
00862 }
00863 }
00864
00865 }
00866
00867
00868 testScores.push_back(bestScore);
00869 testPoints.push_back(bestPoints);
00870 testEdgeCounts.push_back(bestEdgeCount);
00871 testCount++;
00872
00873 int move = -1;
00874 if (doingRandomMovement) {
00875 move = pickMove(testScores, annealingScalar);
00876 }
00877 else {
00878 move = 0;
00879 for (int j=0; j<testCount; j++) {
00880 if (testScores[j] < testScores[move])
00881 move = j;
00882 }
00883 if (move != testCount-1) {
00884 hasMoved = true;
00885 }
00886 }
00887
00888 if (move < 0 || move >= testCount)
00889 std::cout<<"Hmm, picked a bad move somewhere ("<<move<<")\n";
00890 else {
00891 bestPoints[i].setCoords(testPoints[move][i]);
00892 bestScore = testScores[move];
00893 bestEdgeCount = testEdgeCounts[move];
00894 }
00895
00896 }
00897
00898
00899
00900 if (doingRandomMovement) {
00901 annealingScalar += bestEdgeCount*WEIGHT_SCALAR/edgeTotal;
00902 }
00903 else if (!hasMoved) {
00904 doingRandomMovement = true;
00905
00906
00907 annealingStart = iterationCount;
00908 for (unsigned int z=0; z<ncorners; z++) {
00909 NEW_SHAPE(preannealing, PointData, PointData(*space, bestPoints[z]));
00910 preannealing->setParentId(borderPixels->getViewableId());
00911 }
00912 }
00913
00914 iterationCount++;
00915 if (iterationCount > 500) {
00916 std::cout<<"Warning, annealing stopped by max iteration count\n"<<std::endl;
00917 break;
00918 }
00919
00920 }
00921
00922 std::cout<<"Shape fit took "<<iterationCount<<" iterations ("<<iterationCount - annealingStart<<" of annealing)\n";
00923 bestValue = bestScore;
00924 return bestPoints;
00925
00926 }
00927
00928
00929
00930
00931 bool BlobData::AreaLessThan::operator() (const Shape<BlobData> &b1, const Shape<BlobData> &b2) const {
00932 return b1->getArea() < b2->getArea();
00933 }
00934
00935 }