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