00001 /*!@file SceneUnderstanding/TwoHalfDSketch.C */ 00002 00003 // //////////////////////////////////////////////////////////////////// // 00004 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2000-2005 // 00005 // by the University of Southern California (USC) and the iLab at USC. // 00006 // See http://iLab.usc.edu for information about this project. // 00007 // //////////////////////////////////////////////////////////////////// // 00008 // Major portions of the iLab Neuromorphic Vision Toolkit are protected // 00009 // under the U.S. patent ``Computation of Intrinsic Perceptual Saliency // 00010 // in Visual Environments, and Applications'' by Christof Koch and // 00011 // Laurent Itti, California Institute of Technology, 2001 (patent // 00012 // pending; application number 09/912,225 filed July 23, 2001; see // 00013 // http://pair.uspto.gov/cgi-bin/final/home.pl for current status). // 00014 // //////////////////////////////////////////////////////////////////// // 00015 // This file is part of the iLab Neuromorphic Vision C++ Toolkit. // 00016 // // 00017 // The iLab Neuromorphic Vision C++ Toolkit is free software; you can // 00018 // redistribute it and/or modify it under the terms of the GNU General // 00019 // Public License as published by the Free Software Foundation; either // 00020 // version 2 of the License, or (at your option) any later version. // 00021 // // 00022 // The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope // 00023 // that it will be useful, but WITHOUT ANY WARRANTY; without even the // 00024 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // 00025 // PURPOSE. See the GNU General Public License for more details. // 00026 // // 00027 // You should have received a copy of the GNU General Public License // 00028 // along with the iLab Neuromorphic Vision C++ Toolkit; if not, write // 00029 // to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, // 00030 // Boston, MA 02111-1307 USA. // 00031 // //////////////////////////////////////////////////////////////////// // 00032 // 00033 // Primary maintainer for this file: Lior Elazary <elazary@usc.edu> 00034 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/plugins/SceneUnderstanding/TwoHalfDSketch.C $ 00035 // $Id: TwoHalfDSketch.C 14181 2010-10-28 22:46:20Z lior $ 00036 // 00037 00038 #ifndef TwoHalfDSketch_C_DEFINED 00039 #define TwoHalfDSketch_C_DEFINED 00040 00041 #include "plugins/SceneUnderstanding/TwoHalfDSketch.H" 00042 #include "Image/DrawOps.H" 00043 #include "Image/MathOps.H" 00044 #include "Image/Kernels.H" 00045 #include "Image/FilterOps.H" 00046 #include "Image/Transforms.H" 00047 #include "Image/fancynorm.H" 00048 #include "Image/Convolutions.H" 00049 #include "Image/MatrixOps.H" 00050 #include "Simulation/SimEventQueue.H" 00051 #include "GUI/DebugWin.H" 00052 #include <math.h> 00053 #include <fcntl.h> 00054 #include <limits> 00055 #include <string> 00056 00057 const ModelOptionCateg MOC_TwoHalfDSketch = { 00058 MOC_SORTPRI_3, "TwoHalfDSketch-Related Options" }; 00059 00060 // Used by: SimulationViewerEyeMvt 00061 const ModelOptionDef OPT_TwoHalfDSketchShowDebug = 00062 { MODOPT_ARG(bool), "TwoHalfDSketchShowDebug", &MOC_TwoHalfDSketch, OPTEXP_CORE, 00063 "Show debug img", 00064 "twohalfdsketch-debug", '\0', "<true|false>", "false" }; 00065 00066 //Define the inst function name 00067 SIMMODULEINSTFUNC(TwoHalfDSketch); 00068 00069 00070 // ###################################################################### 00071 TwoHalfDSketch::TwoHalfDSketch(OptionManager& mgr, const std::string& descrName, 00072 const std::string& tagName) : 00073 SimModule(mgr, descrName, tagName), 00074 SIMCALLBACK_INIT(SimEventV2Output), 00075 SIMCALLBACK_INIT(SimEventContoursOutput), 00076 SIMCALLBACK_INIT(SimEventSaveOutput), 00077 SIMCALLBACK_INIT(SimEventUserInput), 00078 itsShowDebug(&OPT_TwoHalfDSketchShowDebug, this), 00079 itsProposalThreshold(-1500), 00080 itsAcceptedThreshold(-50) 00081 00082 { 00083 itsCurrentProb = -1e10; 00084 itsCurrentIdx = 0; 00085 itsBiasMode = false; 00086 itsBias = -1; 00087 itsBiasId = -1; 00088 00089 initRandomNumbers(); 00090 00091 itsUserProposal.e=0.8; 00092 itsUserProposal.a=10; //25; 00093 itsUserProposal.b=11; //23; 00094 itsUserProposal.k1=0; //23; 00095 itsUserProposal.k2=0; //23; 00096 itsUserProposal.rot = 0; 00097 itsUserProposal.pos = Point2D<float>(257, 141); 00098 itsUserProposal.start = -M_PI; 00099 itsUserProposal.end = M_PI; 00100 itsUserProposal.gibs=0; 00101 00102 //AppleLogo 00103 itsModel.addLine(Line(7, 71, 17, 88)); 00104 itsModel.addLine(Line(19, 90, 27, 95)); 00105 itsModel.addLine(Line(29, 95, 38, 91)); 00106 itsModel.addLine(Line(39, 91, 55, 95)); 00107 itsModel.addLine(Line(56, 95, 61, 93)); 00108 itsModel.addLine(Line(62, 93, 74, 73)); 00109 itsModel.addLine(Line(74, 72, 65, 62)); 00110 itsModel.addLine(Line(65, 61, 63, 57)); 00111 itsModel.addLine(Line(63, 56, 65, 42)); 00112 itsModel.addLine(Line(66, 42, 71, 36)); 00113 itsModel.addLine(Line(70, 35, 68, 33)); 00114 itsModel.addLine(Line(67, 32, 53, 29)); 00115 itsModel.addLine(Line(52, 30, 45, 32)); 00116 itsModel.addLine(Line(44, 27, 56, 15)); 00117 itsModel.addLine(Line(56, 14, 57, 7)); 00118 itsModel.addLine(Line(56, 6, 53, 7)); 00119 itsModel.addLine(Line(52, 7, 40, 19)); 00120 itsModel.addLine(Line(40, 20, 42, 26)); 00121 itsModel.addLine(Line(44, 33, 25, 29)); 00122 itsModel.addLine(Line(24, 29, 17, 31)); 00123 itsModel.addLine(Line(15, 32, 6, 43)); 00124 itsModel.addLine(Line(5, 45, 5, 64)); 00125 itsModel.addLine(Line(6, 65, 7, 70)); 00126 00127 //Giraff 00128 //itsModel.lines.push_back(Line(39,44,14,7)); 00129 //itsModel.lines.push_back(Line(26,63,16,26)); 00130 //itsModel.lines.push_back(Line(61,64,87,70)); 00131 //itsModel.lines.push_back(Line(22,80,31,104)); 00132 //itsModel.lines.push_back(Line(74,94,53,94)); 00133 //itsModel.lines.push_back(Line(93,77,96,94)); 00134 //itsModel.lines.push_back(Line(47,49,58,62)); 00135 //itsModel.lines.push_back(Line(1,15,12,3)); 00136 //itsModel.lines.push_back(Line(89,104, 81, 92)); 00137 //itsModel.lines.push_back(Line(29,68,22,79)); 00138 //itsModel.lines.push_back(Line(96,95,99,106)); 00139 //itsModel.lines.push_back(Line(40,91,51,93)); 00140 //itsModel.lines.push_back(Line(3, 18, 13, 20)); 00141 //itsModel.lines.push_back(Line(39,93,38,103)); 00142 //itsModel.lines.push_back(Line(40,45,46,49)); 00143 //itsModel.lines.push_back(Line(92,76,88,71)); 00144 //itsModel.lines.push_back(Line(80,92,75,93)); 00145 //itsModel.lines.push_back(Line(15,25,14,21)); 00146 //itsModel.lines.push_back(Line(28,67,27,64)); 00147 //itsModel.lines.push_back(Line(1, 16, 2, 18)); 00148 //itsModel.lines.push_back(Line(14, 6, 13, 5)); 00149 //itsModel.lines.push_back(Line(11, 2, 10, 3)); 00150 //itsModel.lines.push_back(Line(88, 106, 89, 105)); 00151 //itsModel.lines.push_back(Line(39, 104, 38, 105)); 00152 //itsModel.lines.push_back(Line(60, 63, 59, 63)); 00153 00154 00155 itsModel.setCOM(); //Center to COM 00156 itsModel.quantize(60); //number of directions in the grid 00157 00158 } 00159 00160 // ###################################################################### 00161 TwoHalfDSketch::~TwoHalfDSketch() 00162 { 00163 } 00164 00165 // ###################################################################### 00166 void TwoHalfDSketch::onSimEventUserInput(SimEventQueue& q, rutz::shared_ptr<SimEventUserInput>& e) 00167 { 00168 00169 LINFO("Got event --%s-- %ix%i key=%i", 00170 e->getWinName(), 00171 e->getMouseClick().i, 00172 e->getMouseClick().j, 00173 e->getKey()); 00174 00175 if (strcmp(e->getWinName(), "TwoHalfDSketch")) 00176 return; 00177 SurfaceState& surface = itsUserProposal; 00178 00179 switch(e->getKey()) 00180 { 00181 case 111: //98: //111: //up 00182 surface.pos.i -= 1; 00183 break; 00184 case 116: //104: //116: //down 00185 surface.pos.i += 1; 00186 break; 00187 case 113: //100: //113: //left 00188 surface.pos.j -= 1; 00189 break; 00190 case 114: //102: //114: //right 00191 surface.pos.j += 1; 00192 break; 00193 case 21: //= 00194 break; 00195 case 20: //- 00196 break; 00197 case 38: //a 00198 break; 00199 case 52: //z 00200 break; 00201 case 39: //s 00202 break; 00203 case 53: //x 00204 break; 00205 case 40: //d 00206 break; 00207 case 54: //c 00208 break; 00209 case 10: //1 00210 surface.a += 1.0; 00211 break; 00212 case 24: //q 00213 surface.a -= 1.0; 00214 break; 00215 case 11: //2 00216 surface.b += 1.0; 00217 break; 00218 case 25: //w 00219 surface.b -= 1.0; 00220 break; 00221 case 12: //3 00222 surface.e += 0.1; 00223 break; 00224 case 26: //e 00225 surface.e -= 0.1; 00226 break; 00227 case 13: //4 00228 surface.k1 += 0.1; 00229 break; 00230 case 27: //r 00231 surface.k1 -= 0.1; 00232 break; 00233 case 14: //5 00234 surface.k2 += 0.1; 00235 break; 00236 case 28: //t 00237 surface.k2 -= 0.1; 00238 break; 00239 case 15: //6 00240 surface.rot += 1*M_PI/180; 00241 break; 00242 case 29: //y 00243 surface.rot -= 1*M_PI/180; 00244 break; 00245 } 00246 00247 LINFO("Pos(%f,%f), param((%0.2f,%0.2f,%0.2f)", 00248 surface.pos.i, surface.pos.j, 00249 surface.a, surface.b, surface.e); 00250 00251 00252 evolve(q); 00253 00254 } 00255 00256 00257 // ###################################################################### 00258 void TwoHalfDSketch::onSimEventV2Output(SimEventQueue& q, rutz::shared_ptr<SimEventV2Output>& e) 00259 { 00260 //Check if we have the smap 00261 //if (SeC<SimEventSMapOutput> smap = q.check<SimEventSMapOutput>(this)) 00262 // itsSMap = smap->getSMap(); 00263 00264 //Check if we have the corners 00265 itsLines = e->getLines(); 00266 Dims dims = e->getDims(); 00267 00268 itsLinesMag = Image<float>(dims, ZEROS); 00269 itsLinesOri = Image<float>(dims, NO_INIT); 00270 for(uint i=0; i<itsLinesOri.size(); i++) 00271 itsLinesOri[i] = NOTDEF; 00272 00273 std::vector<Line> lines; 00274 for(uint i=0; i<itsLines.size(); i++) 00275 { 00276 V2::LineSegment& ls = itsLines[i]; 00277 drawLine(itsLinesMag, Point2D<int>(ls.p1), Point2D<int>(ls.p2), 255.0F); //ls.length); 00278 drawLine(itsLinesOri, Point2D<int>(ls.p1), Point2D<int>(ls.p2), ls.ori); 00279 lines.push_back(Line(ls.p1, ls.p2)); 00280 } 00281 00282 //Build the FDCM 00283 itsOriChamferMatcher.setLines(lines, 00284 60, //Num Orientation to quantize 00285 5, //Direction cost 00286 itsLinesMag.getDims()); 00287 00288 evolve(q); 00289 00290 } 00291 00292 void TwoHalfDSketch::onSimEventContoursOutput(SimEventQueue& q, rutz::shared_ptr<SimEventContoursOutput>& e) 00293 { 00294 LINFO("Contours output"); 00295 00296 itsContours = e->getContours(); 00297 00298 itsLinesMag = Image<float>(e->getImg().getDims(), ZEROS); 00299 itsLinesOri = Image<float>(e->getImg().getDims(), NO_INIT); 00300 for(uint i=0; i<itsLinesOri.size(); i++) 00301 itsLinesOri[i] = NOTDEF; 00302 00303 std::vector<Line> lines; 00304 00305 for(uint i=0; i<itsContours.size(); i++) 00306 { 00307 std::vector<Point2D<int> > polygon = approxPolyDP(itsContours[i].points, 2); 00308 for(uint j=0; j<polygon.size()-1; j++) 00309 { 00310 drawLine(itsLinesMag, polygon[j], polygon[(j+1)], 255.0F); 00311 00312 float ori = atan2(polygon[j].j-polygon[(j+1)].j, polygon[(j+1)].i - polygon[j].i); 00313 if (ori < 0) ori += M_PI; 00314 if (ori >= M_PI) ori -= M_PI; 00315 drawLine(itsLinesOri, polygon[j], polygon[(j+1)], ori); 00316 00317 lines.push_back(Line(polygon[j], polygon[(j+1)])); 00318 } 00319 } 00320 00321 //Build the FDCM 00322 itsOriChamferMatcher.setLines(lines, 00323 60, //Num Orientation to quantize 00324 0.5, //Direction cost 00325 itsLinesMag.getDims()); 00326 00327 evolve(q); 00328 00329 } 00330 00331 double TwoHalfDSketch::getCost(OriChamferMatching& cm, 00332 Polygon& poly, Point2D<float> loc, bool biasMode) 00333 { 00334 00335 //Image<PixRGB<byte> > tmp = itsLinesMag; 00336 //LINFO("Loc %f %f", loc.i, loc.j); 00337 ////We have a polygon 00338 //for(uint j=0; j<poly.getNumLines(); j++) 00339 //{ 00340 // Line l = poly.getLine(j); //Get the line up to scale and pos 00341 // l.trans(loc); 00342 // Point2D<int> p1 = (Point2D<int>)l.getP1(); 00343 // Point2D<int> p2 = (Point2D<int>)l.getP2(); 00344 // drawLine(tmp, p1,p2, PixRGB<byte>(255,0,0)); 00345 //} 00346 00347 00348 00349 double totalProb = 0; 00350 //double totalHalLength = 0; //The total length we have been hallucinating 00351 //double factor = 1.0/poly.getLength(); 00352 for (uint i=0 ; i<poly.getNumLines(); i++) 00353 { 00354 Line l = poly.getLine(i); //Make a copy so that we dont change the position of the original 00355 l.trans(loc); //Move the line to the correct location 00356 00357 Point2D<int> p1 = (Point2D<int>)l.getP1(); 00358 Point2D<int> p2 = (Point2D<int>)l.getP2(); 00359 double sum = cm.getCost(l.getDirectionIdx(), p1, p2); 00360 00361 double prob = exp(-sum/double(2*l.getLength())); 00362 if (sum < 0) 00363 { 00364 LINFO("Invalid sum %f", sum); 00365 prob = 0; 00366 } 00367 if (!biasMode) 00368 { 00369 if (prob < exp(-500/10)) //If we are very far off, then there might be an edge there, we just dont see it 00370 { 00371 //prob = 0.10; 00372 //totalHalLength+=l.getLength(); 00373 } 00374 } else { 00375 //calcNFA(l); 00376 } 00377 //Weight the line based on how much it contributes to the overall length 00378 prob = pow(prob, 1-l.getWeight()); 00379 //LINFO("%i sum=%f l=%f w=%f p=%f", i, sum, l.getLength(), l.getWeight(), prob ); 00380 //Image<PixRGB<byte> > tmp = itsLinesMag; 00381 //drawLine(tmp, p1, p2, PixRGB<byte>(255,0,0)); 00382 //SHOWIMG(tmp); 00383 00384 totalProb += log(prob); 00385 } 00386 00387 //We need at least 10% of the contour to exist in order to hallucinate 00388 //TODO this should be a continues function change the totalProb as the totalHalLength decreases 00389 //if (totalHalLength/poly.getLength() > 0.9) 00390 // totalProb = -1000; 00391 //LINFO("Hal %f %f %f %f", poly.getLength(), totalHalLength, totalHalLength/poly.getLength(), totalProb); 00392 //LINFO("TOtal prob %f", totalProb); 00393 00394 //SHOWIMG(tmp); 00395 return totalProb; 00396 } 00397 00398 00399 double TwoHalfDSketch::calcNFA(Line& line) 00400 { 00401 //Image<PixRGB<byte> > tmp = itsLinesMag; 00402 00403 00404 //double theta = line.getOri(); 00405 //double prec = M_PI/8.0; 00406 //double p = 1.0 / (double) 8; 00407 00408 //int w = itsLinesMag.getWidth(); 00409 //int h = itsLinesMag.getHeight(); 00410 //double logNT = 5.0 * ( log10( (double) w ) + 00411 // log10( (double) h ) ) / 2.0; 00412 00413 00414 //int pts = 0; 00415 //int alg = 0; 00416 //double nfa_val; 00417 00418 00419 //rect rec; 00420 //if (line.p1.j > line.p2.j) 00421 //{ 00422 // rec.x1 = line.p2.i*2; 00423 // rec.y1 = line.p2.j*2; 00424 // rec.x2 = line.p1.i*2; 00425 // rec.y2 = line.p1.j*2; 00426 //} else { 00427 // rec.x1 = line.p1.i*2; 00428 // rec.y1 = line.p1.j*2; 00429 // rec.x2 = line.p2.i*2; 00430 // rec.y2 = line.p2.j*2; 00431 //} 00432 00433 //rec.theta = theta; //ori*M_PI/180; 00434 //rec.dx = (float) cos( (double) rec.theta ); 00435 //rec.dy = (float) sin( (double) rec.theta ); 00436 //rec.width=15; 00437 00438 //rect_iter * i; 00439 00440 //for(i=ri_ini(&rec); !ri_end(i); ri_inc(i)) 00441 // if( i->x>=0 && i->y>=0 && i->x < itsLinesMag.getWidth() && i->y < itsLinesMag.getHeight() ) 00442 // { 00443 // Point2D<int> loc(i->x, i->y); 00444 // if (itsLinesMag.getVal(loc) > 0) 00445 // { 00446 // pts++; 00447 // if( isaligned(loc,itsLinesOri,theta,prec) ) 00448 // { 00449 // tmp.setVal(loc, PixRGB<byte>(0,255,0)); 00450 // ++alg; 00451 // } 00452 // } 00453 // } 00454 //ri_del(i); 00455 00456 //nfa_val = nfa(pts,alg,p,logNT); 00457 //LINFO("pts=%i alg=%i NFA %f",pts, alg, nfa_val); 00458 00459 //SHOWIMG(tmp); 00460 00461 return 0; 00462 } 00463 00464 /*----------------------------------------------------------------------------*/ 00465 float TwoHalfDSketch::inter_low(float x, float x1, float y1, float x2, float y2) 00466 { 00467 if( x1 > x2 || x < x1 || x > x2 ) 00468 { 00469 LFATAL("inter_low: x %g x1 %g x2 %g.\n",x,x1,x2); 00470 LFATAL("Impossible situation."); 00471 } 00472 if( x1 == x2 && y1<y2 ) return y1; 00473 if( x1 == x2 && y1>y2 ) return y2; 00474 return y1 + (x-x1) * (y2-y1) / (x2-x1); 00475 } 00476 00477 /*----------------------------------------------------------------------------*/ 00478 float TwoHalfDSketch::inter_hi(float x, float x1, float y1, float x2, float y2) 00479 { 00480 if( x1 > x2 || x < x1 || x > x2 ) 00481 { 00482 LFATAL("inter_hi: x %g x1 %g x2 %g.\n",x,x1,x2); 00483 LFATAL("Impossible situation."); 00484 } 00485 if( x1 == x2 && y1<y2 ) return y2; 00486 if( x1 == x2 && y1>y2 ) return y1; 00487 return y1 + (x-x1) * (y2-y1) / (x2-x1); 00488 } 00489 00490 /*----------------------------------------------------------------------------*/ 00491 void TwoHalfDSketch::ri_del(rect_iter * iter) 00492 { 00493 free(iter); 00494 } 00495 00496 /*----------------------------------------------------------------------------*/ 00497 int TwoHalfDSketch::ri_end(rect_iter * i) 00498 { 00499 return (float)(i->x) > i->vx[2]; 00500 } 00501 00502 /*----------------------------------------------------------------------------*/ 00503 void TwoHalfDSketch::ri_inc(rect_iter * i) 00504 { 00505 if( (float) (i->x) <= i->vx[2] ) i->y++; 00506 00507 while( (float) (i->y) > i->ye && (float) (i->x) <= i->vx[2] ) 00508 { 00509 /* new x */ 00510 i->x++; 00511 00512 if( (float) (i->x) > i->vx[2] ) return; /* end of iteration */ 00513 00514 /* update lower y limit for the line */ 00515 if( (float) i->x < i->vx[3] ) 00516 i->ys = inter_low((float)i->x,i->vx[0],i->vy[0],i->vx[3],i->vy[3]); 00517 else i->ys = inter_low((float)i->x,i->vx[3],i->vy[3],i->vx[2],i->vy[2]); 00518 00519 /* update upper y limit for the line */ 00520 if( (float)i->x < i->vx[1] ) 00521 i->ye = inter_hi((float)i->x,i->vx[0],i->vy[0],i->vx[1],i->vy[1]); 00522 else i->ye = inter_hi( (float)i->x,i->vx[1],i->vy[1],i->vx[2],i->vy[2]); 00523 00524 /* new y */ 00525 i->y = (int)((float) ceil( (double) i->ys )); 00526 } 00527 } 00528 00529 /*----------------------------------------------------------------------------*/ 00530 TwoHalfDSketch::rect_iter * TwoHalfDSketch::ri_ini(struct rect * r) 00531 { 00532 float vx[4],vy[4]; 00533 int n,offset; 00534 rect_iter * i; 00535 00536 i = (rect_iter *) malloc(sizeof(rect_iter)); 00537 if(!i) LFATAL("ri_ini: Not enough memory."); 00538 00539 vx[0] = r->x1 - r->dy * r->width / 2.0; 00540 vy[0] = r->y1 + r->dx * r->width / 2.0; 00541 vx[1] = r->x2 - r->dy * r->width / 2.0; 00542 vy[1] = r->y2 + r->dx * r->width / 2.0; 00543 vx[2] = r->x2 + r->dy * r->width / 2.0; 00544 vy[2] = r->y2 - r->dx * r->width / 2.0; 00545 vx[3] = r->x1 + r->dy * r->width / 2.0; 00546 vy[3] = r->y1 - r->dx * r->width / 2.0; 00547 00548 if( r->x1 < r->x2 && r->y1 <= r->y2 ) offset = 0; 00549 else if( r->x1 >= r->x2 && r->y1 < r->y2 ) offset = 1; 00550 else if( r->x1 > r->x2 && r->y1 >= r->y2 ) offset = 2; 00551 else offset = 3; 00552 /* else if( r->x1 <= r->x2 && r->y1 > r->y2 ) offset = 3; */ 00553 00554 for(n=0; n<4; n++) 00555 { 00556 i->vx[n] = vx[(offset+n)%4]; 00557 i->vy[n] = vy[(offset+n)%4]; 00558 } 00559 00560 #define BIG_NUMBER 1.0e+300 00561 00562 /* starting point */ 00563 i->x = (int)(ceil( (double) (i->vx[0]) ) - 1); 00564 i->y = (int)(ceil( (double) (i->vy[0]) )); 00565 i->ys = i->ye = -BIG_NUMBER; 00566 00567 /* advance to the first point */ 00568 ri_inc(i); 00569 00570 return i; 00571 } 00572 00573 00574 00575 int TwoHalfDSketch::isaligned(Point2D<int> loc, Image<float>& angles, float theta, float prec) 00576 { 00577 float a = angles.getVal(loc); 00578 00579 printf("IsAligned %f %f %f ", a*180/M_PI, theta*180/M_PI, prec*180/M_PI); 00580 if( a == NOTDEF ) return false; 00581 00582 /* it is assumed that theta and a are in the range [-pi,pi] */ 00583 theta -= a; 00584 if( theta < 0.0 ) theta = -theta; 00585 if( theta > M_3_2_PI ) 00586 { 00587 theta -= M_2__PI; 00588 if( theta < 0.0 ) theta = -theta; 00589 } 00590 00591 printf(" %f < %f \n", theta*180/M_PI, prec*180/M_PI); 00592 return theta < prec; 00593 } 00594 00595 /*----------------------------------------------------------------------------*/ 00596 /*----------------------------- NFA computation ------------------------------*/ 00597 /*----------------------------------------------------------------------------*/ 00598 00599 /*----------------------------------------------------------------------------*/ 00600 /* 00601 Calculates the natural logarithm of the absolute value of 00602 the gamma function of x using the Lanczos approximation, 00603 see http://www.rskey.org/gamma.htm. 00604 00605 The formula used is 00606 \Gamma(x) = \frac{ \sum_{n=0}^{N} q_n x^n }{ \Pi_{n=0}^{N} (x+n) } 00607 (x+5.5)^(x+0.5) e^{-(x+5.5)} 00608 so 00609 \log\Gamma(x) = \log( \sum_{n=0}^{N} q_n x^n ) + (x+0.5) \log(x+5.5) 00610 - (x+5.5) - \sum_{n=0}^{N} \log(x+n) 00611 and 00612 q0 = 75122.6331530 00613 q1 = 80916.6278952 00614 q2 = 36308.2951477 00615 q3 = 8687.24529705 00616 q4 = 1168.92649479 00617 q5 = 83.8676043424 00618 q6 = 2.50662827511 00619 */ 00620 double TwoHalfDSketch::log_gamma_lanczos(double x) 00621 { 00622 static double q[7] = { 75122.6331530, 80916.6278952, 36308.2951477, 00623 8687.24529705, 1168.92649479, 83.8676043424, 00624 2.50662827511 }; 00625 double a = (x+0.5) * log(x+5.5) - (x+5.5); 00626 double b = 0.0; 00627 int n; 00628 00629 for(n=0;n<7;n++) 00630 { 00631 a -= log( x + (double) n ); 00632 b += q[n] * pow( x, (double) n ); 00633 } 00634 return a + log(b); 00635 } 00636 00637 /*----------------------------------------------------------------------------*/ 00638 /* 00639 Calculates the natural logarithm of the absolute value of 00640 the gamma function of x using Robert H. Windschitl method, 00641 see http://www.rskey.org/gamma.htm. 00642 00643 The formula used is 00644 \Gamma(x) = \sqrt(\frac{2\pi}{x}) ( \frac{x}{e} 00645 \sqrt{ x\sinh(1/x) + \frac{1}{810x^6} } )^x 00646 so 00647 \log\Gamma(x) = 0.5\log(2\pi) + (x-0.5)\log(x) - x 00648 + 0.5x\log( x\sinh(1/x) + \frac{1}{810x^6} ). 00649 00650 This formula is good approximation when x > 15. 00651 */ 00652 double TwoHalfDSketch::log_gamma_windschitl(double x) 00653 { 00654 return 0.918938533204673 + (x-0.5)*log(x) - x 00655 + 0.5*x*log( x*sinh(1/x) + 1/(810.0*pow(x,6.0)) ); 00656 } 00657 00658 /*----------------------------------------------------------------------------*/ 00659 /* 00660 Calculates the natural logarithm of the absolute value of 00661 the gamma function of x. When x>15 use log_gamma_windschitl(), 00662 otherwise use log_gamma_lanczos(). 00663 */ 00664 //#define log_gamma(x) ((x)>15.0?log_gamma_windschitl(x):log_gamma_lanczos(x)) 00665 00666 /*----------------------------------------------------------------------------*/ 00667 /* 00668 Computes the logarithm of NFA to base 10. 00669 00670 NFA = NT.b(n,k,p) 00671 the return value is log10(NFA) 00672 00673 n,k,p - binomial parameters. 00674 logNT - logarithm of Number of Tests 00675 */ 00676 //#define TABSIZE 100000 00677 00678 00679 double TwoHalfDSketch::nfa(int n, int k, double p, double logNT) 00680 { 00681 static double inv[TABSIZE]; /* table to keep computed inverse values */ 00682 double tolerance = 0.1; /* an error of 10% in the result is accepted */ 00683 double log1term,term,bin_term,mult_term,bin_tail,err; 00684 double p_term = p / (1.0-p); 00685 int i; 00686 00687 if( n<0 || k<0 || k>n || p<0.0 || p>1.0 ) 00688 LFATAL("Wrong n, k or p values in nfa()"); 00689 00690 if( n==0 || k==0 ) return -logNT; 00691 if( n==k ) return -logNT - (double) n * log10(p); 00692 00693 log1term = log_gamma((double)n+1.0) - log_gamma((double)k+1.0) 00694 - log_gamma((double)(n-k)+1.0) 00695 + (double) k * log(p) + (double) (n-k) * log(1.0-p); 00696 00697 term = exp(log1term); 00698 if( term == 0.0 ) /* the first term is almost zero */ 00699 { 00700 if( (double) k > (double) n * p ) /* at begin or end of the tail? */ 00701 return -log1term / M_LN10 - logNT; /* end: use just the first term */ 00702 else 00703 return -logNT; /* begin: the tail is roughly 1 */ 00704 } 00705 00706 bin_tail = term; 00707 for(i=k+1;i<=n;i++) 00708 { 00709 bin_term = (double) (n-i+1) * ( i<TABSIZE ? 00710 ( inv[i] == 0.0 ? inv[i] : (inv[i]=1.0/(double)i)) 00711 : 1.0/(double)i ); 00712 mult_term = bin_term * p_term; 00713 term *= mult_term; 00714 bin_tail += term; 00715 if(bin_term<1.0) 00716 { 00717 /* when bin_term<1 then mult_term_j<mult_term_i for j>i. 00718 then, the error on the binomial tail when truncated at 00719 the i term can be bounded by a geometric series of form 00720 term_i * sum mult_term_i^j. */ 00721 err = term * ( ( 1.0 - pow( mult_term, (double) (n-i+1) ) ) / 00722 (1.0-mult_term) - 1.0 ); 00723 00724 /* one wants an error at most of tolerance*final_result, or: 00725 tolerance * abs(-log10(bin_tail)-logNT). 00726 now, the error that can be accepted on bin_tail is 00727 given by tolerance*final_result divided by the derivative 00728 of -log10(x) when x=bin_tail. that is: 00729 tolerance * abs(-log10(bin_tail)-logNT) / (1/bin_tail) 00730 finally, we truncate the tail if the error is less than: 00731 tolerance * abs(-log10(bin_tail)-logNT) * bin_tail */ 00732 if( err < tolerance * fabs(-log10(bin_tail)-logNT) * bin_tail ) break; 00733 } 00734 } 00735 return -log10(bin_tail) - logNT; 00736 } 00737 00738 00739 00740 00741 // ###################################################################### 00742 void TwoHalfDSketch::onSimEventSaveOutput(SimEventQueue& q, rutz::shared_ptr<SimEventSaveOutput>& e) 00743 { 00744 if (itsShowDebug.getVal()) 00745 { 00746 // get the OFS to save to, assuming sinfo is of type 00747 // SimModuleSaveInfo (will throw a fatal exception otherwise): 00748 nub::ref<FrameOstream> ofs = 00749 dynamic_cast<const SimModuleSaveInfo&>(e->sinfo()).ofs; 00750 Layout<PixRGB<byte> > disp = getDebugImage(q); 00751 if (disp.initialized()) 00752 ofs->writeRgbLayout(disp, "TwoHalfDSketch", FrameInfo("TwoHalfDSketch", SRC_POS)); 00753 } 00754 } 00755 00756 00757 // ###################################################################### 00758 void TwoHalfDSketch::evolve(SimEventQueue& q) 00759 { 00760 00761 if (!itsBiasMode) 00762 { 00763 Image<SurfaceState> surfaces = proposeSurfaces(false); 00764 00765 itsProposals.clear(); 00766 for(uint i=0; i<50; i++) 00767 { 00768 Point2D<int> maxLoc; SurfaceState maxSurface; 00769 findMax(surfaces, maxLoc, maxSurface); 00770 00771 if (maxSurface.prob == INVALID_PROB) 00772 break; //No more valid surfaces 00773 00774 itsProposals.push_back(maxSurface); 00775 00776 //Apply IOR 3/4 the size of the object 00777 double radius = maxSurface.polygon.getRadius()*0.75; 00778 drawDisk(surfaces, maxLoc, (int)radius); 00779 } 00780 } else { 00781 optimizePolygon(itsProposals[itsBiasId]); 00782 LINFO("Optimized match %f\n", itsProposals[itsBiasId].prob); 00783 } 00784 00785 printResults(itsBias); 00786 00787 //sort by prob 00788 //Update the surfaces 00789 itsSurfaces.clear(); 00790 for(uint i=0; i<itsProposals.size(); i++) 00791 { 00792 if (itsProposals[i].prob > itsAcceptedThreshold) 00793 itsSurfaces.push_back(itsProposals[i]); 00794 } 00795 00796 //Layout<PixRGB<byte> > layout = getDebugImage(q); 00797 //Image<PixRGB<byte> > tmp = layout.render(); 00798 //SHOWIMG(tmp); 00799 00800 if (itsSurfaces.size() > 0) 00801 q.post(rutz::make_shared(new SimEventTwoHalfDSketchOutput(this, itsSurfaces))); 00802 00803 if (itsProposals.size() > 0 && !itsBiasMode) //Check to see if we can bias 00804 { 00805 itsBiasMode = true; 00806 LINFO("Biasing"); 00807 00808 for(float bias=0; bias<0.30; bias += 0.10) 00809 { 00810 for(uint sid=0; sid<itsProposals.size(); sid++) 00811 { 00812 itsBias = bias; 00813 itsBiasId = sid; 00814 std::vector<V1::SpatialBias> v1Bias; 00815 00816 Polygon& polygon = itsProposals[sid].polygon; 00817 for(uint j=0; j<polygon.getNumLines(); j++) 00818 { 00819 Line l = itsProposals[sid].getLine(j); //Get the line up to scale and pos 00820 00821 Point2D<int> p1 = (Point2D<int>)l.getP1(); 00822 Point2D<int> p2 = (Point2D<int>)l.getP2(); 00823 00824 Point2D<int> bP1 = p1; 00825 Point2D<int> bP2 = (p1+p2)/2; 00826 Point2D<int> bP3 = (p1+bP2)/2; 00827 Point2D<int> bP4 = (p2+bP2)/2; 00828 00829 //Bias V1 00830 { 00831 V1::SpatialBias sb; 00832 sb.loc = bP1; 00833 sb.threshold = bias ; 00834 sb.dims = Dims(15,15); 00835 v1Bias.push_back(sb); 00836 } 00837 00838 { 00839 V1::SpatialBias sb; 00840 sb.loc = bP2; 00841 sb.threshold = bias ; 00842 sb.dims = Dims(15,15); 00843 v1Bias.push_back(sb); 00844 } 00845 00846 { 00847 V1::SpatialBias sb; 00848 sb.loc = bP3; 00849 sb.threshold = bias ; 00850 sb.dims = Dims(15,15); 00851 v1Bias.push_back(sb); 00852 } 00853 00854 { 00855 V1::SpatialBias sb; 00856 sb.loc = bP4; 00857 sb.threshold = bias ; 00858 sb.dims = Dims(15,15); 00859 v1Bias.push_back(sb); 00860 } 00861 } 00862 LINFO("Bias %f for %i\n", itsBias, sid); 00863 q.post(rutz::make_shared(new SimEventV1Bias(this, v1Bias))); 00864 } 00865 00866 } 00867 } 00868 00869 } 00870 00871 00872 Image<float> TwoHalfDSketch::getSurfaceProbImage(Image<SurfaceState>& surfaceState) 00873 { 00874 00875 Image<float> probImg(surfaceState.getDims(), NO_INIT); 00876 for(uint i=0; i<probImg.size(); i++) 00877 { 00878 if (surfaceState[i].prob < -1000) 00879 probImg[i] = 0; 00880 else 00881 probImg[i] = surfaceState[i].prob; 00882 } 00883 00884 return probImg; 00885 } 00886 00887 void TwoHalfDSketch::optimizePolygon(TwoHalfDSketch::SurfaceState& surfaceState) 00888 { 00889 00890 float matchingScale = 1; //0.5; 00891 00892 //int x = 285; 00893 //int y = 328; 00894 //double scale = 0.9; 00895 ////float aspectx = 1.9; 00896 //float aspecty = 1.11; 00897 //float rot = 2.0; 00898 00899 00900 double maxProb = getCost(itsOriChamferMatcher, surfaceState.polygon,surfaceState.pos, true); 00901 if (maxProb > -200 || maxProb < -400) 00902 { 00903 surfaceState.prob = maxProb; 00904 return; 00905 } 00906 LINFO("Optimize Polygon %f", maxProb); 00907 00908 for(float aspectx = surfaceState.aspect.i; aspectx < surfaceState.aspect.i+0.5; aspectx +=0.2) 00909 { 00910 for(float aspecty = surfaceState.aspect.j; aspecty < surfaceState.aspect.j+0.5; aspecty +=0.2) 00911 { 00912 LINFO("Aspectx %f %f", aspectx, aspecty); 00913 if (aspectx <= 0.5 || aspecty <= 0.5) 00914 continue; 00915 for(double scale = surfaceState.scale-0.2 ; scale< surfaceState.scale+0.2 ; scale += 0.01) 00916 { 00917 for(float rot = surfaceState.rot-5 ; rot< surfaceState.rot+5 ; rot+= 1) 00918 { 00919 Polygon model = surfaceState.polygon; 00920 //LINFO("Rot %f Scale %f aspect %f %f\n", rot, scale, aspectx, aspecty); 00921 00922 model.rotate(rot*M_PI/180.0); 00923 model.scale(scale*matchingScale*aspectx, scale*matchingScale*aspecty); 00924 00925 model.setWeights(); 00926 00927 for (int x=surfaceState.pos.i-5 ; x<surfaceState.pos.i+5; x++) 00928 { 00929 for (int y=surfaceState.pos.j-5 ; y<surfaceState.pos.j+5; y++) 00930 { 00931 double prob = getCost(itsOriChamferMatcher, model,Point2D<float>(x,y), true); 00932 00933 if (prob>maxProb) 00934 { 00935 maxProb = prob; 00936 surfaceState.pos = Point2D<float>(x,y); 00937 surfaceState.aspect = Point2D<float>(aspectx, aspecty); 00938 surfaceState.scale = scale; 00939 surfaceState.rot = rot; 00940 surfaceState.prob = prob; 00941 surfaceState.polygon = model; 00942 surfaceState.matchingScale = matchingScale; 00943 } 00944 } 00945 } 00946 } 00947 } 00948 } 00949 00950 } 00951 } 00952 00953 00954 Image<TwoHalfDSketch::SurfaceState> TwoHalfDSketch::proposeSurfaces(bool biasMode) 00955 { 00956 00957 LINFO("Propose surfaces"); 00958 00959 float matchingScale = 1; //0.5; 00960 00961 Image<SurfaceState> surfacesImg(itsLinesMag.getDims(), NO_INIT); 00962 00963 //int aspectx =0; 00964 //int aspecty = 2; 00965 //double scale = 1.1; 00966 //int x = 283; 00967 //int y = 325; 00968 00969 for(int aspectx = 0; aspectx < 4; aspectx++) 00970 { 00971 for(int aspecty = 0; aspecty < 4; aspecty++) 00972 { 00973 for(double scale = 0.2 ; scale< 6.0 ; scale+= 0.1) 00974 { 00975 float rot = 0; 00976 //for(float rot = -60 ; rot< 60 ; rot+= 5) 00977 { 00978 Polygon model = itsModel; 00979 double ax = pow(1.1, aspectx); 00980 double ay = pow(1.1, aspecty); 00981 LINFO("Rot %f Scale %f aspect %f %f\n", rot, scale, ax, ay); 00982 00983 model.rotate(rot*M_PI/180.0); 00984 model.scale(scale*matchingScale*ax, scale*matchingScale*ay); 00985 00986 model.setWeights(); 00987 00988 double minx, miny, maxx, maxy; 00989 model.getBoundary(minx, miny, maxx, maxy); 00990 00991 int width = surfacesImg.getWidth(); 00992 int height = surfacesImg.getHeight(); 00993 00994 //Minx/miny is neg since our template is from -w/-h untill w/h 00995 //Skip the first 4*2 pixels 00996 for (int x=-(int)(minx-4) ; x<width-((int)maxx+4) ; x += 4) 00997 { 00998 for (int y=-(int)(miny-4); y<height-((int)maxy+4); y += 4) 00999 { 01000 01001 double prob = getCost(itsOriChamferMatcher, model,Point2D<float>(x,y), biasMode); 01002 01003 if (prob>itsProposalThreshold) 01004 { 01005 if (surfacesImg.coordsOk(x,y)) 01006 if (prob > surfacesImg.getVal(x,y).prob) 01007 { 01008 SurfaceState ss; 01009 ss.pos = Point2D<float>(x,y); 01010 ss.aspect = Point2D<float>(ax, ay); 01011 ss.scale = scale; 01012 ss.rot = rot; 01013 ss.prob = prob; 01014 ss.polygon = model; 01015 ss.matchingScale = matchingScale; 01016 surfacesImg.setVal(x,y, ss); 01017 01018 } 01019 } 01020 } 01021 } 01022 } 01023 } 01024 01025 } 01026 01027 } 01028 01029 return surfacesImg; 01030 } 01031 01032 void TwoHalfDSketch::calcSurfaceLikelihood(SurfaceState& surface) 01033 { 01034 Image<float> edges; 01035 Image<float> lumSurface; 01036 double edgeProb = calcSurfaceEdgeLikelihood(surface, edges, lumSurface); 01037 //double surfaceProb = calcSurfaceLumLikelihood(surface, edges, lumSurface); 01038 surface.prob = edgeProb; // * surfaceProb; 01039 } 01040 01041 double TwoHalfDSketch::calcSurfaceLumLikelihood(SurfaceState& surface, Image<float>& edges, Image<float>& surfaceLum) 01042 { 01043 //Remove the edges from the surface 01044 for(uint i=0; i<surfaceLum.size(); i++) 01045 if (edges[i] > 0) 01046 surfaceLum[i] = 0; 01047 01048 return getSurfaceLumProb(itsEdgesDT,surfaceLum); 01049 01050 } 01051 01052 double TwoHalfDSketch::getSurfaceLumProb(Image<float>& data, Image<float>& model) 01053 { 01054 01055 double prob = 0; 01056 int pixCount = 0; 01057 01058 for(int y=0; y < model.getHeight(); y++) 01059 for(int x=0; x < model.getWidth(); x++) 01060 if (model.getVal(x,y) > 0) 01061 { 01062 prob += (10-data.getVal(x,y)); 01063 pixCount++; 01064 } 01065 prob /= (10*pixCount); 01066 01067 return exp(-prob); 01068 } 01069 01070 01071 01072 01073 01074 double TwoHalfDSketch::calcSurfaceEdgeLikelihood(SurfaceState& surface, Image<float>& edges, Image<float>& surfaceLum) 01075 { 01076 int pixCount = 0; 01077 double prob = 0; 01078 01079 if (surface.polygon.getNumLines() > 0) 01080 { 01081 01082 for(uint j=0; j<surface.polygon.getNumLines(); j++) 01083 { 01084 Point2D<int> p1; // = (Point2D<int>)(surface.polygon[j] + surface.pos); 01085 Point2D<int> p2; // = (Point2D<int>)(surface.polygon[(j+1)%surface.polygon.size()] + surface.pos); 01086 01087 //Point2D<float> center = (p1 + p2)/2; 01088 float ori = atan2(p1.j-p2.j, p2.i - p1.i); 01089 if (ori < 0) ori += M_PI; 01090 if (ori >= M_PI) ori -= M_PI; 01091 01092 prob += getLineProb(p1, p2, ori, pixCount); 01093 01094 //prob += getEdgeProb(Point2D<int>(p1), ori); 01095 //prob += getEdgeProb(Point2D<int>(center), ori); 01096 } 01097 pixCount *= 2; 01098 01099 } else { 01100 01101 float nSeg = 20; 01102 const float dTheta = 2*M_PI / (float)nSeg; 01103 01104 float a = surface.a; 01105 float b = surface.b; 01106 float e = surface.e; 01107 float k1 = surface.k1; 01108 float k2 = surface.k2; 01109 float rot = surface.rot; 01110 01111 Point2D<float> p = surface.pos; 01112 01113 for (float theta=surface.start; theta < surface.end; theta += dTheta) 01114 { 01115 Point2D<float> p1 = ellipsoid(a,b, e, theta); 01116 Point2D<float> p2 = ellipsoid(a,b, e, theta + dTheta); 01117 01118 Point2D<float> tmpPos1; 01119 Point2D<float> tmpPos2; 01120 01121 //Sheer 01122 tmpPos1.i = p1.i + p1.j*k1; 01123 tmpPos1.j = p1.i*k2 + p1.j; 01124 01125 tmpPos2.i = p2.i + p2.j*k1; 01126 tmpPos2.j = p2.i*k2 + p2.j; 01127 01128 //Rotate and move to p 01129 p1.i = (cos(rot)*tmpPos1.i - sin(rot)*tmpPos1.j) + p.i; 01130 p1.j = (sin(rot)*tmpPos1.i + cos(rot)*tmpPos1.j) + p.j; 01131 01132 p2.i = (cos(rot)*tmpPos2.i - sin(rot)*tmpPos2.j) + p.i; 01133 p2.j = (sin(rot)*tmpPos2.i + cos(rot)*tmpPos2.j) + p.j; 01134 01135 01136 Point2D<float> center = (p1 + p2)/2; 01137 float ori = atan2(p1.j-p2.j, p2.i - p1.i); 01138 if (ori < 0) ori += M_PI; 01139 if (ori >= M_PI) ori -= M_PI; 01140 01141 prob += getEdgeProb(Point2D<int>(p1), ori); 01142 prob += getEdgeProb(Point2D<int>(center), ori); 01143 pixCount += 2; 01144 } 01145 pixCount *= 1; 01146 } 01147 01148 //double pr = exp(-prob/ double(pixCount)); 01149 //LINFO("%i: PRob %f pixCount %i = %f", (uint)surface.polygon.size(), prob, pixCount*2, pr); 01150 01151 return exp(-prob/ double(pixCount))*2; 01152 //return prob/ double(pixCount); 01153 01154 01155 } 01156 01157 double TwoHalfDSketch::getEdgeProb(Point2D<int> loc, float ori) 01158 { 01159 01160 int numOfEntries = itsOriEdgesDT.size(); 01161 01162 double lambda = (1/6)*M_PI/180; //6 degrees error = 1 pixel distance 01163 01164 double D = M_PI/numOfEntries; 01165 int oriIdx = (int)floor(ori/D); 01166 01167 float minDist = 10000; 01168 if (itsOriEdgesDT[0].coordsOk(loc)) 01169 { 01170 for(int i=0; i<numOfEntries; i++) 01171 { 01172 float v1 = itsOriEdgesDT[i].getVal(loc) + lambda*angDiff(oriIdx*D, i*D); 01173 if (v1 < minDist) 01174 minDist = v1; 01175 } 01176 } 01177 01178 return minDist; 01179 } 01180 01181 double TwoHalfDSketch::getLineProb(Point2D<int> p1, Point2D<int> p2, float ori, int& pixCount) 01182 { 01183 01184 int numOfEntries = itsOriEdgesDT.size(); 01185 01186 double lambda = (1/2)*M_PI/180; //6 degrees error = 1 pixel distance 01187 01188 double D = M_PI/numOfEntries; 01189 int oriIdx = (int)floor(ori/D); 01190 01191 int dx = p2.i - p1.i, ax = abs(dx) << 1, sx = signOf(dx); 01192 int dy = p2.j - p1.j, ay = abs(dy) << 1, sy = signOf(dy); 01193 int x = p1.i, y = p1.j; 01194 01195 double prob = 0; 01196 int wSize = 1; 01197 if (ax > ay) 01198 { 01199 int d = ay - (ax >> 1); 01200 for (;;) 01201 { 01202 //search for a max edge prob in a window 01203 for(int yy = y-wSize; yy < y+wSize; yy++) 01204 for(int xx = x-wSize; xx < x+wSize; xx++) 01205 { 01206 float minDist = 10000; 01207 if (itsOriEdgesDT[0].coordsOk(xx,yy)) 01208 { 01209 for(int i=0; i<numOfEntries; i++) 01210 { 01211 float v1 = itsOriEdgesDT[i].getVal(xx,yy) + lambda*angDiff(oriIdx*D, i*D); 01212 if (v1 < minDist) 01213 minDist = v1; 01214 } 01215 } 01216 prob += minDist; 01217 pixCount++; 01218 } 01219 01220 if (x == p2.i) return prob; 01221 if (d >= 0) { y += sy; d -= ax; } 01222 x += sx; d += ay; 01223 } 01224 } else { 01225 int d = ax - (ay >> 1); 01226 for (;;) 01227 { 01228 for(int yy = y-wSize; yy < y+wSize; yy++) 01229 for(int xx = x-wSize; xx < x+wSize; xx++) 01230 { 01231 float minDist = 10000; 01232 if (itsOriEdgesDT[0].coordsOk(xx,yy)) 01233 { 01234 for(int i=0; i<numOfEntries; i++) 01235 { 01236 float v1 = itsOriEdgesDT[i].getVal(xx,yy) + lambda*angDiff(oriIdx*D, i*D); 01237 if (v1 < minDist) 01238 minDist = v1; 01239 } 01240 } 01241 prob += minDist; 01242 pixCount++; 01243 } 01244 if (y == p2.j) return prob; 01245 01246 if (d >= 0) { x += sx; d -= ay; } 01247 y += sy; d += ax; 01248 } 01249 } 01250 01251 return prob; 01252 01253 } 01254 01255 01256 void TwoHalfDSketch::printResults(float bias) 01257 { 01258 for(uint i=0; i<itsProposals.size(); i++) 01259 { 01260 Rectangle bb = itsProposals[i].getBB(); 01261 01262 if (i == (uint)itsBiasId) 01263 bias = itsBias; 01264 else 01265 bias = -1; 01266 01267 printf("Result: %i %i %f %i %i %i %i %f %f %f\n", 01268 i, (uint)itsBiasId, 01269 bias, 01270 bb.topLeft().i, 01271 bb.topLeft().j, 01272 bb.bottomRight().i, 01273 bb.bottomRight().j, 01274 itsProposals[i].prob, 01275 itsProposals[i].pos.i, 01276 itsProposals[i].pos.j 01277 01278 ); 01279 } 01280 01281 } 01282 01283 01284 Layout<PixRGB<byte> > TwoHalfDSketch::getDebugImage(SimEventQueue& q) 01285 { 01286 Layout<PixRGB<byte> > outDisp; 01287 01288 Image<float> input = itsLinesMag; 01289 inplaceNormalize(input, 0.0F, 255.0F); 01290 01291 Image<PixRGB<byte> > worldFrame = input; 01292 for(uint i=0; i<itsSurfaces.size(); i++) 01293 { 01294 if (itsSurfaces[i].polygon.getNumLines()> 0) 01295 { 01296 Polygon& polygon = itsSurfaces[i].polygon; 01297 //We have a polygon 01298 for(uint j=0; j<polygon.getNumLines(); j++) 01299 { 01300 Line l = itsProposals[i].getLine(j); //Get the line up to scale and pos 01301 Point2D<int> p1 = (Point2D<int>)l.getP1(); 01302 Point2D<int> p2 = (Point2D<int>)l.getP2(); 01303 drawLine(worldFrame, p1, p2, PixRGB<byte>(0,255,0)); 01304 } 01305 01306 } else { 01307 drawSuperquadric(worldFrame, 01308 Point2D<int>(itsSurfaces[i].pos), 01309 itsSurfaces[i].a, itsSurfaces[i].b, itsSurfaces[i].e, 01310 PixRGB<byte>(0,255,0), 01311 itsSurfaces[i].rot, itsSurfaces[i].k1, itsSurfaces[i].k2, 01312 itsSurfaces[i].start,itsSurfaces[i].end); 01313 } 01314 //char msg[255]; 01315 //sprintf(msg, "%0.2f", itsSurfaces[i].prob); 01316 //writeText(worldFrame, (Point2D<int>)itsSurfaces[i].getPos(), msg, 01317 // PixRGB<byte>(255,255,255), 01318 // PixRGB<byte>(0,0,0)); 01319 01320 } 01321 01322 Image<PixRGB<byte> > proposalsFrame = input; 01323 float maxProb = -100000; 01324 for(uint i=0; i<itsProposals.size(); i++) 01325 { 01326 LINFO("Propsal %i p:%fx%f s:%f a:%fx%f r:%f p:%f", i, 01327 itsProposals[i].pos.i, itsProposals[i].pos.j, 01328 itsProposals[i].scale, 01329 itsProposals[i].aspect.i, itsProposals[i].aspect.j, 01330 itsProposals[i].rot, 01331 itsProposals[i].prob); 01332 //if (itsProposals[i].prob > 0.00) 01333 { 01334 if (itsProposals[i].prob > maxProb) 01335 maxProb = itsProposals[i].prob; 01336 01337 if (itsProposals[i].polygon.getNumLines() > 0) 01338 { 01339 Polygon& polygon = itsProposals[i].polygon; 01340 //We have a polygon 01341 for(uint j=0; j<polygon.getNumLines(); j++) 01342 { 01343 Line l = itsProposals[i].getLine(j); //Get the line up to scale and pos 01344 Point2D<int> p1 = (Point2D<int>)l.getP1(); 01345 Point2D<int> p2 = (Point2D<int>)l.getP2(); 01346 drawLine(proposalsFrame, p1,p2, PixRGB<byte>(255,0,0)); 01347 } 01348 } else { 01349 01350 float nSeg = 20; 01351 const float dTheta = 2*M_PI / (float)nSeg; 01352 01353 float a = itsProposals[i].a; 01354 float b = itsProposals[i].b; 01355 float e = itsProposals[i].e; 01356 float k1 = itsProposals[i].k1; 01357 float k2 = itsProposals[i].k2; 01358 float rot = itsProposals[i].rot; 01359 float start = itsProposals[i].start; 01360 float end = itsProposals[i].end; 01361 01362 Point2D<float> p = itsProposals[i].pos; 01363 01364 for (float theta=start; theta < end; theta += dTheta) 01365 { 01366 Point2D<float> p1 = ellipsoid(a,b, e, theta); 01367 Point2D<float> tmpPos; 01368 01369 //Sheer 01370 tmpPos.i = p1.i + p1.j*k1; 01371 tmpPos.j = p1.i*k2 + p1.j; 01372 01373 //Rotate and move to p 01374 p1.i = (cos(rot)*tmpPos.i - sin(rot)*tmpPos.j) + p.i; 01375 p1.j = (sin(rot)*tmpPos.i + cos(rot)*tmpPos.j) + p.j; 01376 01377 drawCircle(proposalsFrame, (Point2D<int>)p1, 3, PixRGB<byte>(255,0,0)); 01378 } 01379 } 01380 01381 char msg[255]; 01382 sprintf(msg, "%0.2f", itsProposals[i].prob); 01383 writeText(proposalsFrame, (Point2D<int>)itsProposals[i].getPos(), msg, 01384 PixRGB<byte>(255,255,255), 01385 PixRGB<byte>(0,0,0)); 01386 } 01387 01388 } 01389 char msg[255]; 01390 sprintf(msg, "Max: %0.2f", maxProb); 01391 writeText(proposalsFrame, Point2D<int>(0,proposalsFrame.getHeight()-20), msg, 01392 PixRGB<byte>(255,255,255), 01393 PixRGB<byte>(0,0,0)); 01394 01395 01396 outDisp = proposalsFrame; //hcat(toRGB(Image<byte>(input)), proposalsFrame); 01397 outDisp = hcat(outDisp, worldFrame); 01398 01399 return outDisp; 01400 01401 } 01402 01403 01404 // ###################################################################### 01405 /* So things look consistent in everyone's emacs... */ 01406 /* Local Variables: */ 01407 /* indent-tabs-mode: nil */ 01408 /* End: */ 01409 01410 #endif 01411