00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038 #ifndef Contours_C_DEFINED
00039 #define Contours_C_DEFINED
00040
00041
00042 #include "Image/OpenCVUtil.H"
00043 #include "plugins/SceneUnderstanding/LFLineFitter/LFLineFitter.h"
00044 #include "plugins/SceneUnderstanding/Contours.H"
00045 #include "plugins/SceneUnderstanding/V1.H"
00046
00047 #include "Image/DrawOps.H"
00048 #include "Image/MathOps.H"
00049 #include "Image/Kernels.H"
00050 #include "Image/ColorMap.H"
00051 #include "Image/FilterOps.H"
00052 #include "Image/Transforms.H"
00053 #include "Image/fancynorm.H"
00054 #include "Image/Convolutions.H"
00055 #include "Simulation/SimEventQueue.H"
00056 #include "GUI/DebugWin.H"
00057 #include <math.h>
00058 #include <fcntl.h>
00059 #include <limits>
00060 #include <string>
00061
00062 const ModelOptionCateg MOC_Contours = {
00063 MOC_SORTPRI_3, "Contours-Related Options" };
00064
00065
00066 const ModelOptionDef OPT_ContoursShowDebug =
00067 { MODOPT_ARG(bool), "ContoursShowDebug", &MOC_Contours, OPTEXP_CORE,
00068 "Show debug img",
00069 "contours-debug", '\0', "<true|false>", "false" };
00070
00071
00072
00073 SIMMODULEINSTFUNC(Contours);
00074
00075
00076 Contours::Contours(OptionManager& mgr, const std::string& descrName,
00077 const std::string& tagName) :
00078 SimModule(mgr, descrName, tagName),
00079 SIMCALLBACK_INIT(SimEventV2Output),
00080 SIMCALLBACK_INIT(SimEventContoursBias),
00081 SIMCALLBACK_INIT(SimEventSaveOutput),
00082 SIMCALLBACK_INIT(SimEventUserInput),
00083 itsShowDebug(&OPT_ContoursShowDebug, this)
00084 {
00085
00086 itsCurrentContour = -1;
00087 }
00088
00089
00090 Contours::~Contours()
00091 {
00092 }
00093
00094
00095 void Contours::onSimEventV2Output(SimEventQueue& q,
00096 rutz::shared_ptr<SimEventV2Output>& e)
00097 {
00098 itsTensorFields = e->getTensorFields();
00099 evolve(q);
00100
00101
00102
00103
00104
00105
00106
00107 }
00108
00109
00110 void Contours::onSimEventContoursBias(SimEventQueue& q,
00111 rutz::shared_ptr<SimEventContoursBias>& e)
00112 {
00113 itsBiasContours.clear();
00114 itsBiasContours = e->getContours();
00115
00116
00117 LINFO("Size %i", (uint)itsBiasContours.size());
00118
00119
00120 if (itsBiasContours.size() > 0)
00121 {
00122 std::vector<V1::SpatialBias> v1Bias;
00123 for(uint i=0; i<itsBiasContours.size(); i++)
00124 {
00125 Point2D<int> center(0,0);
00126 for(uint j=0; j<itsBiasContours[i].points.size(); j++)
00127 {
00128
00129
00130 center += itsBiasContours[i].points[j];
00131 }
00132 center /= itsBiasContours[i].size();
00133
00134
00135
00136
00137
00138
00139 V1::SpatialBias sb;
00140 sb.loc = center;
00141 sb.threshold = 0.01;
00142 sb.dims = Dims(50,50);
00143 v1Bias.push_back(sb);
00144
00145 }
00146 q.post(rutz::make_shared(new SimEventV1Bias(this, v1Bias)));
00147
00148 }
00149
00150 }
00151
00152
00153
00154 void Contours::onSimEventSaveOutput(SimEventQueue& q, rutz::shared_ptr<SimEventSaveOutput>& e)
00155 {
00156 if (itsShowDebug.getVal())
00157 {
00158
00159
00160 nub::ref<FrameOstream> ofs =
00161 dynamic_cast<const SimModuleSaveInfo&>(e->sinfo()).ofs;
00162 Layout<PixRGB<byte> > disp = getDebugImage();
00163 if (disp.initialized())
00164 ofs->writeRgbLayout(disp, "Contours", FrameInfo("Contours", SRC_POS));
00165 }
00166 }
00167
00168
00169 void Contours::onSimEventUserInput(SimEventQueue& q, rutz::shared_ptr<SimEventUserInput>& e)
00170 {
00171
00172 LINFO("Got event %s %ix%i key=%i",
00173 e->getWinName(),
00174 e->getMouseClick().i,
00175 e->getMouseClick().j,
00176 e->getKey());
00177
00178 if (strcmp(e->getWinName(), "Contours"))
00179 return;
00180
00181 switch(e->getKey())
00182 {
00183 case 10:
00184 itsCurrentContour++;
00185 if (itsCurrentContour > (int)itsContours.size()) itsCurrentContour = itsContours.size()-1;
00186 break;
00187 case 24:
00188 itsCurrentContour--;
00189 if (itsCurrentContour < 0) itsCurrentContour = 0;
00190 break;
00191 case 38:
00192 itsCurrentContour=-1;
00193 break;
00194 }
00195
00196
00197 evolve(q);
00198
00199 }
00200
00201
00202 void Contours::evolve(SimEventQueue& q)
00203 {
00204
00205
00206
00207
00208
00209 int cid=0;
00210 itsContours.clear();
00211
00212
00213
00214
00215
00216
00217
00218
00219
00220
00221
00222
00223
00224
00225
00226
00227 Image<float> edgesMag;
00228 Image<float> edgesOri;
00229 for(uint cidx=0; cidx<3; cidx++)
00230 {
00231 if (!edgesMag.initialized())
00232 {
00233 edgesMag = Image<float>(itsTensorFields[cidx].getDims(), ZEROS);
00234 edgesOri = Image<float>(itsTensorFields[cidx].getDims(), ZEROS);
00235 }
00236
00237 EigenSpace eigen = getTensorEigen(itsTensorFields[cidx].getTensorField());
00238 Image<float> features = eigen.l1-eigen.l2;
00239 for(uint i=0; i<features.size(); i++)
00240 if (features.getVal(i) > edgesMag.getVal(i))
00241 {
00242 edgesMag.setVal(i, features.getVal(i));
00243 float u = eigen.e1[1].getVal(i);
00244 float v = eigen.e1[0].getVal(i);
00245 edgesOri.setVal(i,atan(-u/v));
00246 }
00247 }
00248
00249
00250 Image<float> contoursImg;
00251 std::vector<Point2D<int> > pointList = getPointList(edgesMag, edgesOri, contoursImg);
00252
00253
00254 for(uint i=0; i<pointList.size(); i++)
00255 {
00256 if (contoursImg.getVal(pointList[i]) == UNKNOWN)
00257 {
00258 Contour contour = followContour(cid, pointList[i], contoursImg, edgesMag, edgesOri);
00259 if (contour.points.size() > 5)
00260 {
00261 itsContours.push_back(contour);
00262 cid++;
00263 }
00264 }
00265 }
00266
00267
00268
00269 std::sort(itsContours.begin(), itsContours.end(), ContourCmp());
00270
00271
00272 Image<PixRGB<byte> > byEdges = toRGB(itsTensorFields[2].getTokensMag(true));
00273 Image<PixRGB<byte> > tmp(byEdges.getDims(), ZEROS);
00274
00275 for(uint i=0; i<itsContours.size(); i++)
00276 {
00277 Contour& contour = itsContours[i];
00278 for(uint j=0; j<contour.points.size(); j++)
00279 tmp.setVal(contour.points[j], PixRGB<byte>(0,255,0));
00280 }
00281
00282
00283
00284
00285
00286 q.post(rutz::make_shared(new SimEventContoursOutput(this, itsContours, edgesMag)));
00287 }
00288
00289 Contours::Contour Contours::followContour(int idx, Point2D<int> startLoc, Image<float>& contoursImg,
00290 const Image<float>& edgesMag, const Image<float>& edgesOri)
00291 {
00292 float origEdgeMag = edgesMag.getVal(startLoc);
00293
00294
00295 Image<float> t = edgesMag;
00296 inplaceNormalize(t, 0.0F, 255.0F);
00297 Image<PixRGB<byte> > tmp = t;
00298
00299
00300 Contour fcontour;
00301 fcontour.points.push_back(startLoc);
00302 fcontour.ori.push_back(edgesOri.getVal(startLoc));
00303 contoursImg.setVal(startLoc, idx);
00304
00305 Contour contour;
00306
00307
00308 Point2D<int> pEdge(-1,-1);
00309 for(uint i=0; i<fcontour.points.size(); i++)
00310 {
00311 Point2D<int> newEdge = findEdgeToFollow(fcontour.points[i], origEdgeMag,
00312 edgesMag, edgesOri, contoursImg, pEdge);
00313
00314 if (newEdge.isValid())
00315 {
00316 pEdge = newEdge;
00317 tmp.setVal(newEdge, PixRGB<byte>(0,255,0));
00318 contoursImg.setVal(newEdge,idx);
00319 fcontour.points.push_back(newEdge);
00320 fcontour.ori.push_back(edgesOri.getVal(newEdge));
00321 }
00322 }
00323
00324
00325 Point2D<int> newEdge = findEdgeToFollow(startLoc, origEdgeMag,
00326 edgesMag, edgesOri, contoursImg, pEdge);
00327
00328 if (newEdge.isValid())
00329 {
00330 tmp.setVal(newEdge, PixRGB<byte>(0,255,0));
00331
00332 Contour bcontour;
00333 bcontour.points.push_back(newEdge);
00334 bcontour.ori.push_back(edgesOri.getVal(newEdge));
00335 contoursImg.setVal(newEdge,idx);
00336
00337 for(uint i=0; i<bcontour.points.size(); i++)
00338 {
00339 Point2D<int> newEdge = findEdgeToFollow(bcontour.points[i], origEdgeMag,
00340 edgesMag, edgesOri, contoursImg, pEdge);
00341
00342 if (newEdge.isValid())
00343 {
00344 tmp.setVal(newEdge, PixRGB<byte>(0,255,0));
00345 contoursImg.setVal(newEdge,idx);
00346 bcontour.points.push_back(newEdge);
00347 bcontour.ori.push_back(edgesOri.getVal(newEdge));
00348 }
00349
00350
00351 }
00352
00353
00354 for(int i=bcontour.size()-1; i>=0; i--)
00355 {
00356 contour.points.push_back(bcontour.points[i]);
00357 contour.ori.push_back(bcontour.ori[i]);
00358 }
00359
00360 }
00361
00362
00363 for(uint i=0; i<fcontour.size(); i++)
00364 {
00365 contour.points.push_back(fcontour.points[i]);
00366 contour.ori.push_back(fcontour.ori[i]);
00367 }
00368
00369 return contour;
00370 }
00371
00372 Point2D<int> Contours::findEdgeToFollow(const Point2D<int>& edgeLoc,
00373 const float origEdgeMag,
00374 const Image<float>& edgesMag, const Image<float>& edgesOri,
00375 const Image<float>& contoursImg,
00376 const Point2D<int>& pEdge)
00377 {
00378 const int radius = 1;
00379 const float magDiffThreshold = 0.2;
00380
00381
00382
00383
00384 Point2D<int> newEdge(-1,-1);
00385
00386
00387 float w1 = 1;
00388 float w2 = 1;
00389 float w3 = 1.5;
00390
00391 float maxDiff = 0;
00392
00393
00394 for(int x=edgeLoc.i-radius; x<=edgeLoc.i+radius; x++)
00395 for(int y=edgeLoc.j-radius; y<=edgeLoc.j+radius; y++)
00396 {
00397 Point2D<int> loc(x,y);
00398 if (edgeLoc != loc &&
00399 contoursImg.coordsOk(loc) &&
00400 contoursImg.getVal(loc) == UNKNOWN)
00401 {
00402 float mag = 1.0F - (fabs(origEdgeMag - edgesMag.getVal(loc))/origEdgeMag);
00403
00404 if (mag > magDiffThreshold)
00405 {
00406 float edgeOri = edgesOri.getVal(edgeLoc);
00407
00408 float dist = 1.0F - (edgeLoc.squdist(loc)/(2*radius*2));
00409
00410
00411 float oriDiff = 1.0F - (angDiff(edgeOri, edgesOri.getVal(loc))/(M_PI));
00412
00413
00414
00415
00416
00417 float diff = w1*mag + w2*dist + w3*oriDiff;
00418
00419
00420 if (diff > maxDiff)
00421 {
00422 newEdge = loc;
00423 maxDiff = diff;
00424 }
00425 }
00426 }
00427 }
00428
00429
00430 return newEdge;
00431 }
00432
00433
00434
00435 std::vector<Point2D<int> > Contours::getPointList(TensorVoting& tv, Image<float>& contoursImg,
00436 Image<float>& edgesMag, Image<float>& edgesOri)
00437 {
00438 float maxMag = 1000;
00439 int nBins = 100;
00440
00441
00442
00443 contoursImg = Image<float>(tv.getDims(), NO_INIT);
00444
00445 EigenSpace eigen = getTensorEigen(tv.getTensorField());
00446 Image<float> features = eigen.l1-eigen.l2;
00447 inplaceNormalize(features, 0.0F, maxMag);
00448
00449 edgesMag = features;
00450
00451 edgesOri = Image<float>(features.getDims(), ZEROS);
00452
00453
00454
00455
00456 std::vector<std::vector<Point2D<int> > > pointBins(nBins);
00457 for(int j=0; j<features.getHeight(); j++)
00458 for(int i=0; i<features.getWidth(); i++)
00459 {
00460 float val = features.getVal(i,j);
00461 if (val > 0)
00462 {
00463 contoursImg.setVal(i,j, UNKNOWN);
00464
00465 int idx = (int)(val * nBins / maxMag);
00466 if (idx >= nBins) idx = nBins - 1;
00467 pointBins[idx].push_back(Point2D<int>(i,j));
00468
00469
00470 float u = eigen.e1[1].getVal(i,j);
00471 float v = eigen.e1[0].getVal(i,j);
00472 edgesOri.setVal(i,j, atan(-u/v));
00473 } else {
00474 contoursImg.setVal(i,j, NOTDEFINED);
00475 }
00476 }
00477
00478
00479 std::vector<Point2D<int> > points;
00480 for(int i=pointBins.size()-1; i > -1; i--)
00481 {
00482 for(uint j=0; j<pointBins[i].size(); j++)
00483 points.push_back(pointBins[i][j]);
00484 }
00485
00486 return points;
00487
00488 }
00489
00490 std::vector<Point2D<int> > Contours::getPointList(Image<float>& inMag, Image<float>& inOri, Image<float>& contoursImg)
00491 {
00492 float maxMag = 1000;
00493 int nBins = 100;
00494 float threshold = 0.1;
00495
00496
00497 contoursImg = Image<float>(inMag.getDims(), NO_INIT);
00498 inplaceNormalize(inMag, 0.0F, maxMag);
00499
00500
00501
00502
00503 std::vector<std::vector<Point2D<int> > > pointBins(nBins);
00504 for(int j=0; j<inMag.getHeight(); j++)
00505 for(int i=0; i<inMag.getWidth(); i++)
00506 {
00507 float val = inMag.getVal(i,j);
00508 if (val > threshold*maxMag)
00509 {
00510 contoursImg.setVal(i,j, UNKNOWN);
00511
00512 int idx = (int)(val * nBins / maxMag);
00513 if (idx >= nBins) idx = nBins - 1;
00514 pointBins[idx].push_back(Point2D<int>(i,j));
00515 } else {
00516 contoursImg.setVal(i,j, NOTDEFINED);
00517 }
00518 }
00519
00520
00521 std::vector<Point2D<int> > points;
00522 for(int i=pointBins.size()-1; i > -1; i--)
00523 {
00524 for(uint j=0; j<pointBins[i].size(); j++)
00525 points.push_back(pointBins[i][j]);
00526 }
00527
00528 return points;
00529
00530 }
00531
00532
00533 Layout<PixRGB<byte> > Contours::getDebugImage()
00534 {
00535 Layout<PixRGB<byte> > outDisp;
00536
00537
00538 Layout<PixRGB<byte> > tensorDisp;
00539 Image<PixRGB<byte> > lumEdges = toRGB(itsTensorFields[0].getTokensMag(true));
00540 Image<PixRGB<byte> > rgEdges = toRGB(itsTensorFields[1].getTokensMag(true));
00541 Image<PixRGB<byte> > byEdges = toRGB(itsTensorFields[2].getTokensMag(true));
00542
00543 tensorDisp = hcat(lumEdges, rgEdges);
00544 tensorDisp = hcat(tensorDisp, byEdges);
00545
00546
00547
00548 Image<PixRGB<byte> > contourImg(lumEdges.getDims(), ZEROS);
00549 ColorMap cm = ColorMap::LINES(100);
00550 if (itsCurrentContour != -1)
00551 {
00552 Contour& contour = itsContours[itsCurrentContour];
00553 for(uint j=0; j<contour.points.size(); j++)
00554 contourImg.setVal(contour.points[j], cm[itsCurrentContour%cm.size()]);
00555
00556 char msg[255];
00557 sprintf(msg, "C: %i", itsCurrentContour);
00558 writeText(contourImg, Point2D<int>(0,0), msg,
00559 PixRGB<byte>(255,255,255),
00560 PixRGB<byte>(0,0,0));
00561
00562 } else {
00563 for(uint i=0; i<itsContours.size(); i++)
00564 {
00565 Contour& contour = itsContours[i];
00566 for(uint j=0; j<contour.points.size(); j++)
00567 contourImg.setVal(contour.points[j], cm[i%cm.size()]);
00568 }
00569 }
00570
00571
00572
00573
00574
00575
00576 outDisp = contourImg;
00577
00578 return outDisp;
00579
00580 }
00581
00582
00583
00584
00585
00586
00587
00588
00589 #endif
00590