V2.C

Go to the documentation of this file.
00001 /*!@file plugins/SceneUnderstanding/V2.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/V2.C $
00035 // $Id: V2.C 14683 2011-04-05 01:30:59Z lior $
00036 //
00037 
00038 #ifndef V2_C_DEFINED
00039 #define V2_C_DEFINED
00040 
00041 #include "plugins/SceneUnderstanding/V2.H"
00042 
00043 #include "Image/DrawOps.H"
00044 #include "Image/MathOps.H"
00045 //#include "Image/OpenCVUtil.H"
00046 #include "Image/Kernels.H"
00047 #include "Image/FilterOps.H"
00048 #include "Image/Transforms.H"
00049 #include "Image/fancynorm.H"
00050 #include "Image/Convolutions.H"
00051 #include "Raster/Raster.H"
00052 #include "Simulation/SimEventQueue.H"
00053 #include "Util/CpuTimer.H"
00054 #include "Util/JobServer.H"
00055 #include "Util/JobWithSemaphore.H"
00056 #include "GUI/DebugWin.H"
00057 #include <math.h>
00058 #include <fcntl.h>
00059 #include <limits>
00060 #include <string>
00061 #include <stdio.h>
00062 
00063 const ModelOptionCateg MOC_V2 = {
00064   MOC_SORTPRI_3,   "V2-Related Options" };
00065 
00066 // Used by: SimulationViewerEyeMvt
00067 const ModelOptionDef OPT_V2ShowDebug =
00068   { MODOPT_ARG(bool), "V2ShowDebug", &MOC_V2, OPTEXP_CORE,
00069     "Show debug img",
00070     "v2-debug", '\0', "<true|false>", "false" };
00071 
00072 const ModelOptionDef OPT_V2TrainNFA =
00073   { MODOPT_ARG(bool), "V2TrainNFA", &MOC_V2, OPTEXP_CORE,
00074     "Train the Number Of False Alarms (NFA)",
00075     "v2-trainNFA", '\0', "<true|false>", "false" };
00076 
00077 const ModelOptionDef OPT_V2TrainNFAFile =
00078   { MODOPT_ARG(std::string), "V2TrainNFAFile", &MOC_V2, OPTEXP_CORE,
00079     "Train the Number Of False Alarms (NFA) output file",
00080     "v2-trainNFAFile", '\0', "<string>", "NFATrain.dat" };
00081 
00082 //Define the inst function name
00083 SIMMODULEINSTFUNC(V2);
00084 
00085 namespace
00086 {
00087 
00088   typedef std::map<size_t,size_t> BinPDFMap;
00089 
00090   void writePDF(std::vector< std::vector<NFAInfo> > pdf)
00091   {
00092     LINFO("Dump Data");
00093     FILE *fp = fopen("BinPDFMap.dat", "w");
00094     for(uint i=0; i<pdf.size(); i++)
00095     {
00096       for(uint j=0; j<pdf[i].size(); j++)
00097       {
00098         fprintf(fp, "%i %i %i %i %i %i %i\n",  i,
00099             pdf[i][j].ori,
00100             pdf[i][j].xLoc,
00101             pdf[i][j].yLoc,
00102             pdf[i][j].length,
00103             pdf[i][j].pts,
00104             pdf[i][j].alg);
00105       }
00106     }
00107     fclose(fp);
00108   }
00109 
00110   void writePDF(std::vector<NFAPDFMap>& pdf,const char* filename)
00111   {
00112     LINFO("Dump Data");
00113     FILE *fp = fopen(filename, "w");
00114     for(uint i=0; i<pdf.size(); i++)
00115     {
00116       NFAPDFMap::iterator itr1;
00117       for(itr1=pdf[i].begin(); itr1 != pdf[i].end(); itr1++)
00118       {
00119         std::map<short int, //xLoc
00120           std::map<short int, //yLoc,
00121           std::map<short int, //length, 
00122           std::map<short int, //alg, 
00123           NumEntries > > > >::iterator itr2;
00124         for(itr2=itr1->second.begin(); itr2 != itr1->second.end(); itr2++)
00125         {
00126           std::map<short int, //yLoc,
00127             std::map<short int, //length, 
00128             std::map<short int, //alg, 
00129             NumEntries > > >::iterator itr3;
00130           for(itr3=itr2->second.begin(); itr3 != itr2->second.end(); itr3++)
00131           {
00132             std::map<short int, //length, 
00133               std::map<short int, //alg, 
00134               NumEntries > >::iterator itr4;
00135             for(itr4=itr3->second.begin(); itr4 != itr3->second.end(); itr4++)
00136             {
00137               std::map<short int, //alg, 
00138                 NumEntries >::iterator itr5;
00139               for(itr5=itr4->second.begin(); itr5 != itr4->second.end(); itr5++)
00140               {
00141                 fprintf(fp, "%i %i %i %i %i %i %i %zu\n", 
00142                     i, 
00143                     itr1->first, itr2->first, itr3->first, itr4->first, itr5->first,
00144                     itr5->second.pts, itr5->second.num);
00145               }
00146 
00147             }
00148           }
00149 
00150         }
00151 
00152       }
00153     }
00154     fclose(fp);
00155   }
00156 
00157   class TrainNFAJob : public JobWithSemaphore
00158   {
00159     public:
00160 
00161       TrainNFAJob(V2* v2,Image<float> angles,
00162           const std::vector<Point2D<int> >& pos,
00163           int rectWidth, int startWidth, 
00164           NFAPDFMap& pdf) :
00165         itsV2(v2),
00166         itsAngles(angles),
00167         itsPositions(pos),
00168         itsRectWidth(rectWidth),
00169         itsStartWidth(startWidth),
00170         itsPDF(pdf)
00171     {}
00172 
00173       virtual ~TrainNFAJob() {}
00174 
00175       virtual void run()
00176       {
00177         int width = itsAngles.getWidth();
00178         int height = itsAngles.getHeight();
00179         int maxLength = sqrt(width*width + height*height);
00180         LINFO("Start thread for %i", itsRectWidth);
00181 
00182         for(int ori  = -180; ori < 180; ori += 4)
00183         {
00184           for(uint locIdx=0; locIdx<(itsPositions.size()/250); locIdx++)
00185           {
00186             for(int length=4; length<maxLength; length+=4)
00187             {
00188               Dims size(length, itsRectWidth);
00189               Rect rect(itsPositions[locIdx], size, (float)ori*M_PI/180.0);
00190 
00191               int pts=0;
00192               int alg=0;
00193               int x1=0,x2=0,y1=0;
00194 
00195               for(rect.initIter(); !rect.iterEnd(); rect.incIter(x1,x2,y1))
00196               {
00197                 for(int x = x1; x <= x2; x++)
00198                 {
00199                   ++pts;
00200                   if( x>=0 && y1>=0 &&
00201                       x<width && y1<height )
00202                   {
00203                     if( itsV2->isaligned(Point2D<int>(x,y1),
00204                           itsAngles,ori,M_PI/20) )
00205                       ++alg;
00206                   }
00207                 }
00208               }
00209 
00210               if (alg > 0)
00211               {
00212                 const short int xPos = itsPositions[locIdx].i;
00213                 const short int yPos = itsPositions[locIdx].j;
00214                 NumEntries& info = itsPDF[ori][xPos][yPos][length][alg];
00215                 info.num++;
00216                 info.pts = pts;
00217               }
00218             }
00219           }
00220           LINFO("Ori %i", ori);
00221         }
00222         LINFO("Done %i: size %zu", itsRectWidth, itsPDF.size());
00223         this->markFinished();
00224       }
00225 
00226       virtual const char* jobType() const { return "TrainNFAJob"; }
00227       V2* itsV2;
00228       Image<float> itsAngles;
00229       const std::vector<Point2D<int> >& itsPositions;
00230       int itsRectWidth;
00231       int itsStartWidth;
00232       NFAPDFMap& itsPDF; 
00233   };
00234 }
00235 
00236 
00237 
00238 // ######################################################################
00239 V2::V2(OptionManager& mgr, const std::string& descrName,
00240     const std::string& tagName) :
00241   SimModule(mgr, descrName, tagName),
00242   SIMCALLBACK_INIT(SimEventV1Output),
00243   SIMCALLBACK_INIT(SimEventSaveOutput),
00244   SIMCALLBACK_INIT(SimEventUserInput),
00245   itsShowDebug(&OPT_V2ShowDebug, this),
00246   itsTrainNFA(&OPT_V2TrainNFA, this),
00247   itsTrainNFAFile(&OPT_V2TrainNFAFile, this),
00248   itsLSDVerbose(false),
00249   itsQuantError(2.0),
00250   itsAngleTolerance(20.0),
00251   itsEPS(0)
00252   //itsStorage(cvCreateMemStorage(0))
00253 {
00254   //itsThreadServer.reset(new WorkThreadServer("V2", 20));
00255   itsPDF.resize(20);
00256  // itsStoredFrames = "true";
00257  
00258   //Pick random locations to sample
00259   int width = 640;
00260   int height = 480;
00261   for(int y=0; y<height; y++)
00262     for(int x=0; x<width; x++)
00263       itsLocations.push_back(Point2D<int>(x,y));
00264   randShuffle(&itsLocations[0], itsLocations.size());
00265 
00266 
00267 }
00268 
00269 // ######################################################################
00270 V2::~V2()
00271 {
00272   //cvReleaseMemStorage(&itsStorage);
00273 }
00274 
00275 // ######################################################################
00276 void V2::init(Dims numCells)
00277 {
00278 
00279 }
00280 
00281 // ######################################################################
00282 void V2::onSimEventV1Output(SimEventQueue& q,
00283                                   rutz::shared_ptr<SimEventV1Output>& e)
00284 {
00285   itsV1EdgesState = e->getEdgesState();
00286 
00287   if (SeC<SimEventLGNOutput> lgn = q.check<SimEventLGNOutput>(this))
00288     itsLGNInput = lgn->getCells();
00289   
00290   evolve(q);
00291 
00292 
00293 }
00294 
00295 // ######################################################################
00296 void V2::onSimEventSaveOutput(SimEventQueue& q, rutz::shared_ptr<SimEventSaveOutput>& e)
00297 {
00298   if (itsShowDebug.getVal())
00299     {
00300       // get the OFS to save to, assuming sinfo is of type
00301       // SimModuleSaveInfo (will throw a fatal exception otherwise):
00302       nub::ref<FrameOstream> ofs =
00303         dynamic_cast<const SimModuleSaveInfo&>(e->sinfo()).ofs;
00304       Layout<PixRGB<byte> > disp = getDebugImage();
00305       ofs->writeRgbLayout(disp, "V2", FrameInfo("V2", SRC_POS));
00306     }
00307 }
00308 
00309 // ######################################################################
00310 void V2::onSimEventUserInput(SimEventQueue& q, rutz::shared_ptr<SimEventUserInput>& e)
00311 {
00312 
00313   LINFO("Got event %s %ix%i key=%i",
00314       e->getWinName(),
00315       e->getMouseClick().i,
00316       e->getMouseClick().j,
00317       e->getKey());
00318 
00319   if (strcmp(e->getWinName(), "V2"))
00320     return;
00321 
00322   switch(e->getKey())
00323   {
00324     case 10: //1
00325       itsQuantError += 1;
00326       break;
00327     case 24: //q
00328       itsQuantError -= 1;
00329       break;
00330     case 11: //1
00331       itsAngleTolerance += 1;
00332       break;
00333     case 25: //q
00334       itsAngleTolerance -= 1;
00335       break;
00336     case 12: //1
00337       itsEPS += 1;
00338       break;
00339     case 26: //q
00340       itsEPS -= 1;
00341       break;
00342     default:
00343       break;
00344   }
00345 
00346   LINFO("Q %f A %f EPS %f",
00347       itsQuantError, itsAngleTolerance,
00348       itsEPS);
00349 
00350   //itsQuantError(2.0),
00351   //itsAngleTolerance(20.0),
00352   //itsEPS(0),
00353   
00354   
00355   if (e->getMouseClick().isValid())
00356   {
00357   }
00358 
00359   evolve(q);
00360 
00361 }
00362 
00363 void V2::evolve(SimEventQueue& q)
00364 {
00365   evolveLines();
00366 
00367   //Find corners and symetries
00368   //cornerSymetryDetection(itsLines);
00369   //evolveContours();
00370   //evolveBorderOwner();
00371   
00372   q.post(rutz::make_shared(new SimEventV2Output(this, itsLines,
00373           itsCornersState, itsCornersProposal, itsEdges, itsTensorFields, itsEdges.getDims())));
00374 }
00375 
00376 void V2::evolveBorderOwner()
00377 {
00378   std::vector<ContourState> contours = proposeContoursBO(itsLines);
00379   itsContours = contours;
00380 }
00381 
00382 std::vector<V2::ContourState> V2::proposeContoursBO(std::vector<LineSegment>& lines)
00383 {
00384 
00385   std::vector<ContourState> contours;
00386 
00387   //Propose countors based on border ownership
00388 
00389 
00390   //Group all lines that have the same color together
00391   std::list<LineSegment> currentLines;
00392   for(uint i=0; i<lines.size(); i++)
00393     currentLines.push_back(lines[i]);
00394 
00395   //Pick a line and find all matches
00396 
00397   while(!currentLines.empty())
00398   {
00399     ContourState contour;
00400     LineSegment ls = currentLines.front();
00401     currentLines.pop_front();
00402     contour.lines.push_back(ls);
00403 
00404     std::list<LineSegment>::iterator iter;
00405     for(iter = currentLines.begin(); iter != currentLines.end(); )
00406     {
00407       if (ls.colorDist(*iter) < 50.0F)
00408       {
00409         contour.lines.push_back(*iter);
00410         currentLines.erase(iter++); //increment the iter after erasing
00411       } else {
00412         iter++;
00413       }
00414     }
00415 
00416     contours.push_back(contour);
00417   }
00418 
00419   return contours;
00420 }
00421 
00422 void V2::evolveContours()
00423 {
00424 
00425   //Link lines
00426 
00427   itsContours.clear();
00428 
00429   std::vector<ContourState> contours = proposeContours(itsLines);
00430 
00431   //Take the input as the perception for now
00432   itsContours = contours;
00433 }
00434 
00435 std::vector<V2::ContourState> V2::proposeContours(std::vector<LineSegment>& lines)
00436 {
00437 
00438   std::vector<ContourState> contours;
00439 
00440   std::list<LineSegment> currentLines;
00441 
00442   for(uint i=0; i<lines.size(); i++)
00443     currentLines.push_back(lines[i]);
00444 
00445   while(!currentLines.empty())
00446   {
00447     LineSegment ls = currentLines.front();
00448     currentLines.pop_front();
00449 
00450     Point2D<float> p1 = ls.p1;
00451     Point2D<float> p2 = ls.p2;
00452 
00453     LINFO("End Points %0.2fx%0.2f %0.2fx%0.2f",
00454         p1.i, p1.j,
00455         p2.i, p2.j);
00456 
00457     ContourState contour;
00458     contour.lines.push_back(ls);
00459 
00460     std::stack<Point2D<float> > endPoints;
00461     endPoints.push(p1);
00462     endPoints.push(p2);
00463 
00464     Image<PixRGB<byte> > contoursImg = itsLGNInput[0];
00465     drawLine(contoursImg, (Point2D<int>)p1, (Point2D<int>)p2,
00466         PixRGB<byte>(255,0,0), 1);
00467 
00468     //SHOWIMG(contoursImg);
00469 
00470     //std::vector<LineSegment> nerestLines = findNerestLines(currentLines, endPoints);
00471     //LINFO("Found %lu closest lines", nerestLines.size());
00472 
00473     //while(nerestLines.size() > 0)
00474     //{
00475     //  for(uint i=0; i<nerestLines.size(); i++)
00476     //  {
00477     //    contour.lines.push_back(nerestLines[i]);
00478 
00479     //    LineSegment& ls = nerestLines[i];
00480     //    drawLine(contoursImg, (Point2D<int>)ls.p1,
00481     //        (Point2D<int>)ls.p2, PixRGB<byte>(0,255,0), 1);
00482     //  }
00483     //  SHOWIMG(contoursImg);
00484     //  nerestLines = findNerestLines(currentLines, endPoints);
00485     //  LINFO("Found Again %lu closest lines", nerestLines.size());
00486 
00487     //}
00488 
00489     //if (contour.lines.size() > 1)
00490     //  contours.push_back(contour);
00491 
00492     LINFO("Loop\n");
00493   }
00494 
00495 
00496   return contours;
00497 
00498 }
00499 
00500 std::vector<V2::LineSegment> V2::findNerestLines(std::list<LineSegment>& lines,
00501     std::stack<Point2D<float> >& endPoints)
00502 {
00503 
00504   std::vector<LineSegment> nerestLines;
00505 
00506   Point2D<float> p = endPoints.top();
00507   endPoints.pop();
00508 
00509   //Find the closest line to the endpoint
00510   //float thresh = 5.0;
00511   //std::list<LineSegment>::iterator iter;
00512 
00513   //for(iter = lines.begin(); iter != lines.end(); iter++)
00514   //{
00515   //  if (p.distance(iter->p1) < thresh)
00516   //  {
00517   //    endPoints.push(iter->p2);
00518   //    nerestLines.push_back(*iter);
00519   //    lines.erase(iter);
00520   //  } else if (p.distance(iter->p2) < thresh)
00521   //  {
00522   //    nerestLines.push_back(*iter);
00523   //    endPoints.push(iter->p1);
00524   //    lines.erase(iter);
00525   //  }
00526   //}
00527 
00528   return nerestLines;
00529 
00530 }
00531 
00532 void V2::evolveLines()
00533 {
00534 
00535 
00536   std::vector<LineSegment> lines;
00537 
00538   if (itsTrainNFA.getVal())
00539   {
00540     double logNT = 0;
00541     double p = 1.0/20.0;
00542     //print out the raguler NFA computations
00543     for(uint n=1; n<18000; n++)
00544     {
00545       for(uint k=1; k<n && k<3000; k++)
00546       {
00547         double nfaValue = nfa(n, k, p, logNT);
00548         if (!std::isinf(nfaValue) || nfaValue != 0)
00549           printf("%i %i %f\n", k, n, nfaValue);
00550 
00551       }
00552     }
00553     //trainNFA(itsV1EdgesState);
00554 
00555   } else {
00556     //Use the LGN Input
00557     //std::vector<LineSegment> lines = proposeLineSegments(itsLGNInput);
00558 
00559     //Use the V1 Input
00560     lines = proposeLineSegments(itsV1EdgesState);
00561 
00562   }
00563 
00564 
00565   ////For each proposed line find the most Likely line
00566   ////segment in our current perception
00567   //for(uint i=0; i<lines.size(); i++)
00568   //{
00569   //  float prob;
00570   //  int lineIdx = findMostProbableLine(lines[i], prob);
00571 
00572   //  if (lineIdx >= 0)
00573   //  {
00574   //    //Line Found, update it
00575   //    itsLines[lineIdx] = lines[i];
00576 
00577 
00578   //    //Update the strength
00579   //    itsLines[lineIdx].strength += 0.5;
00580   //    if ( itsLines[lineIdx].strength > 1)
00581   //      itsLines[lineIdx].strength = 1;
00582   //  } else {
00583   //    //Add the New line to the current perception
00584   //    lines[i].strength = 0.5;
00585 
00586   //    itsLines.push_back(lines[i]);
00587   //  }
00588   //}
00589 
00590   ////Leaky itegrator line
00591   ////Slowly kill off any lines that are in the current perception but not in the data
00592   //for(uint i =0; i<itsLines.size(); i++)
00593   //{
00594   //  itsLines[i].strength -= 0.10;
00595 
00596   //  if (itsLines[i].strength < 0)
00597   //  {
00598   //    //Remove the line for the perception
00599   //  }
00600   //}
00601 
00602 
00603   itsLines = lines;
00604 
00605 }
00606 
00607 
00608 int V2::findMostProbableLine(const LineSegment& line, float& prob)
00609 {
00610 
00611   for(uint i=0; i<itsLines.size(); i++)
00612   {
00613     if (itsLines[i].distance(line) < 5)
00614     {
00615       prob = itsLines[i].distance(line);
00616       return i;
00617     }
00618   }
00619 
00620   return -1;
00621 }
00622 
00623 std::vector<V2::LineSegment> V2::proposeLineSegments(ImageSet<float> &LGNInput)
00624 {
00625 
00626   std::vector<LineSegment> lines;
00627 
00628   LINFO("Evolve tensors");
00629   std::vector<LineSegment> linesLum = lineSegmentDetection(LGNInput[0]);
00630   std::vector<LineSegment> linesRG = lineSegmentDetection(LGNInput[1]);
00631   std::vector<LineSegment> linesBY = lineSegmentDetection(LGNInput[2]);
00632   LINFO("Done");
00633 
00634   for(uint i=0; i<linesLum.size(); i++)
00635   {
00636     linesLum[i].color=0;
00637     lines.push_back(linesLum[i]);
00638   }
00639   for(uint i=0; i<linesRG.size(); i++)
00640   {
00641     linesRG[i].color=1;
00642     lines.push_back(linesRG[i]);
00643   }
00644   for(uint i=0; i<linesBY.size(); i++)
00645   {
00646     linesBY[i].color=2;
00647     lines.push_back(linesBY[i]);
00648   }
00649 
00650 
00651   return lines;
00652 
00653 }
00654 
00655 std::vector<V2::LineSegment> V2::proposeLineSegments(V1::EdgesState& edgesState)
00656 {
00657 
00658   //Preform TensorVoting
00659 
00660   //Preform nonMax surpression if true
00661   TensorField lumTensorField = itsLumTV.evolve(edgesState.lumTensorField, false);
00662   TensorField rgTensorField  = itsRGTV.evolve(edgesState.rgTensorField, false);
00663   TensorField byTensorField  = itsBYTV.evolve(edgesState.byTensorField, false);
00664 
00665   itsTensorFields.clear();
00666   itsTensorFields.push_back(itsLumTV);
00667   itsTensorFields.push_back(itsRGTV);
00668   itsTensorFields.push_back(itsBYTV);
00669 
00670 
00671   EigenSpace eigen = getTensorEigen(lumTensorField);
00672   itsEdges = eigen.l1-eigen.l2;
00673   itsCornersProposal = eigen.l2;
00674 
00675   //Get the max edge from all color spaces
00676   itsMaxTF = lumTensorField;
00677   //itsMaxTF.setMax(rgTensorField);
00678   //itsMaxTF.setMax(byTensorField);
00679 
00680 
00681   std::vector<LineSegment> lines = lineSegmentDetection(itsMaxTF, itsQuantError, itsAngleTolerance, itsEPS);
00682   //std::vector<LineSegment> linesRG = lineSegmentDetection(rgTensorField, itsQuantError, itsAngleTolerance, itsEPS);
00683   //std::vector<LineSegment> linesBY = lineSegmentDetection(byTensorField, itsQuantError, itsAngleTolerance, itsEPS);
00684 
00685 
00686   //for(uint i=0; i<linesLum.size(); i++)
00687   //{
00688   //  linesLum[i].color=0;
00689   //  lines.push_back(linesLum[i]);
00690   //}
00691   //for(uint i=0; i<linesRG.size(); i++)
00692   //{
00693   //  linesRG[i].color=0;
00694   //  lines.push_back(linesRG[i]);
00695   //}
00696   //for(uint i=0; i<linesBY.size(); i++)
00697   //{
00698   //  linesBY[i].color=0;
00699   //  lines.push_back(linesBY[i]);
00700   //}
00701 
00702 
00703   return lines;
00704 
00705 }
00706 
00707 
00708 V2::rect V2::getRect(const Point2D<int> p1, const Point2D<int> p2, int width)
00709 {
00710 
00711   rect rec;
00712   // set the first and second point of the line segment
00713   if (p1.j > p2.j)
00714   {
00715     rec.x1 = p2.i*2; rec.y1 = p2.j*2;
00716     rec.x2 = p1.i*2; rec.y2 = p1.j*2;
00717   } else {
00718     rec.x1 = p1.i*2; rec.y1 = p1.j*2;
00719     rec.x2 = p2.i*2; rec.y2 = p2.j*2;
00720   }
00721 
00722   double theta = atan2(p2.j-p1.j,p2.i-p1.i);
00723   if (theta<0)
00724     theta += M_PI;
00725 
00726   rec.theta = theta;
00727   rec.dx = (float) cos( (double) rec.theta );
00728   rec.dy = (float) sin( (double) rec.theta );
00729   rec.width=width;
00730   rec.prec = M_PI / 20; /* tolerance angle */
00731   rec.p = 1.0 / (double) 20;
00732   return rec;
00733 }
00734 
00735 void V2::trainNFA(V1::EdgesState& edgesState)
00736 {
00737 
00738   //Preform TensorVoting
00739 
00740   //Preform nonMax surpression if true
00741   TensorField lumTensorField = itsLumTV.evolve(edgesState.lumTensorField, false);
00742   //TensorField rgTensorField  = itsRGTV.evolve(edgesState.rgTensorField, false);
00743   //TensorField byTensorField  = itsBYTV.evolve(edgesState.byTensorField, false);
00744 
00745   itsTensorFields.clear();
00746   itsTensorFields.push_back(itsLumTV);
00747   //itsTensorFields.push_back(itsRGTV);
00748   //itsTensorFields.push_back(itsBYTV);
00749 
00750   //std::vector<LineSegment> linesRG = lineSegmentDetection(rgTensorField, itsQuantError, itsAngleTolerance, itsEPS);
00751   //std::vector<LineSegment> linesBY = lineSegmentDetection(byTensorField, itsQuantError, itsAngleTolerance, itsEPS);
00752 
00753 
00754   
00755 
00756   std::vector<Point2D<int> > list_p;
00757   Image<float> modgrad;
00758 
00759   int max_grad = 260100;
00760   int n_bins = 16256;
00761   Image<float> angles = ll_angle(lumTensorField,max_grad*0.10,list_p,modgrad,n_bins,max_grad);
00762 
00763 
00764   CpuTimer timer;
00765   timer.reset();
00766 
00767   WorkThreadServer threadServer("V2", 20);
00768 
00769   std::vector<rutz::shared_ptr<TrainNFAJob> > jobs;
00770   for(int rw=0; rw<20; rw += 1)
00771   {
00772     jobs.push_back(rutz::make_shared(new TrainNFAJob(this, angles,
00773             itsLocations, rw+3,
00774             0, itsPDF[rw])));
00775     threadServer.enqueueJob(jobs.back());
00776   }
00777 
00778   LINFO("Waiting for jobs to finish");
00779   while((uint)threadServer.getNumRun() < jobs.size())
00780   {
00781     //LINFO("%i/%zu jobs completed", threadServer.getNumRun(),jobs.size());
00782     sleep(1);
00783   }
00784   timer.mark();
00785   LINFO("Total time for image %0.2f sec", timer.real_secs());
00786 
00787   writePDF(itsPDF, itsTrainNFAFile.getVal().c_str());
00788 }
00789 
00790 void V2::cornerSymetryDetection(std::vector<LineSegment>& lines)
00791 {
00792   itsCornersState.clear();
00793   itsSymmetries.clear();
00794 
00795   for(uint ls1Idx=0; ls1Idx<itsLines.size(); ls1Idx++)
00796   {
00797     for(uint ls2Idx=ls1Idx+1; ls2Idx<itsLines.size(); ls2Idx++)
00798     {
00799       //find parallel lines
00800       /* This code is based on the solution of these two input equations:
00801        *  Pa = P1 + ua (P2-P1)
00802        *  Pb = P3 + ub (P4-P3)
00803        *
00804        * Where line one is composed of points P1 and P2 and line two is composed
00805        *  of points P3 and P4.
00806        *
00807        * ua/b is the fractional value you can multiple the x and y legs of the
00808        *  triangle formed by each line to find a point on the line.
00809        *
00810        * The two equations can be expanded to their x/y components:
00811        *  Pa.x = p1.x + ua(p2.x - p1.x)
00812        *  Pa.y = p1.y + ua(p2.y - p1.y)
00813        *
00814        *  Pb.x = p3.x + ub(p4.x - p3.x)
00815        *  Pb.y = p3.y + ub(p4.y - p3.y)
00816        *
00817        * When Pa.x == Pb.x and Pa.y == Pb.y the lines intersect so you can come
00818        *  up with two equations (one for x and one for y):
00819        *
00820        * p1.x + ua(p2.x - p1.x) = p3.x + ub(p4.x - p3.x)
00821        * p1.y + ua(p2.y - p1.y) = p3.y + ub(p4.y - p3.y)
00822        *
00823        * ua and ub can then be individually solved for.  This results in the
00824        *  equations used in the following code.
00825        */
00826       //Finding Intersection of the two lines
00827       LineSegment& lineSeg1 = itsLines[ls1Idx];
00828       LineSegment& lineSeg2 = itsLines[ls2Idx];
00829 
00830       double x1 = lineSeg1.p1.i, y1 = lineSeg1.p1.j;
00831       double x2 = lineSeg1.p2.i, y2 = lineSeg1.p2.j;
00832       double x3 = lineSeg2.p1.i, y3 = lineSeg2.p1.j;
00833       double x4 = lineSeg2.p2.i, y4 = lineSeg2.p2.j;
00834 
00835       /*
00836        * If the denominator for the equations for ua and ub is 0 then the two lines are parallel.
00837        * If the denominator and numerator for the equations for ua and ub are 0 then the two
00838        * lines are coincident.
00839        */
00840       double den = ((y4 - y3)*(x2 - x1)) - ((x4 - x3)*(y2 - y1) );
00841       Point2D<float> intersectionPoint;
00842       if(den == 0.0F)
00843       {
00844         ////LINFO("Parallel lines");
00845         ////LINFO("%0.2fx%0.2f %0.2fx%0.2f     %0.2fx%0.2f %0.2fx%0.2f",
00846         ////    x1, y1, x2, y2,
00847         ////    x3, y3, x4, y4);
00848 
00849         ////LINFO("%f %f %f %f",
00850         ////    x1-x3, y1-y3, x2-x4, y2-y4);
00851 
00852         //float L1 = lineSeg1.length;
00853         //float L2 = lineSeg2.length;
00854 
00855         ////float xVL = ( (lineSeg1.center.i * L1) + (lineSeg2.center.i * L2) ) / (L1 + L2);
00856         ////float yVL = ( (lineSeg1.center.j * L1) + (lineSeg2.center.j * L2) ) / (L1 + L2);
00857 
00858         //float xG = ((L1 *(x1 + x2) ) + (L2*(x3 + x4)))/(2*(L1+L2));
00859         //float yG = ((L1 *(y1 + y2) ) + (L2*(y3 + y4)))/(2*(L1+L2));
00860 
00861         //float ori1 = lineSeg1.ori;
00862         //float ori2 = lineSeg2.ori;
00863 
00864         //float ang = 0;
00865         //if ( fabs(ori1 - ori2) <= M_PI/2)
00866         //  ang = ( (ori1 * L1) + (ori2 * L2) ) / (L1 + L2);
00867         //else
00868         //  ang = ( (ori1 * L1) + ((ori2 - (M_PI*ori2/fabs(ori2))) * L2) ) / (L1 + L2);
00869 
00870         //Point2D<int> center((int)xG, (int)yG);
00871 
00872         //Image<PixRGB<byte> > tmp(itsV1EdgesDims, ZEROS);
00873         //drawCircle(tmp, center, 3, PixRGB<byte>(0,255,255), 2);
00874         //drawLine(tmp, center, ang, 3000.0F, PixRGB<byte>(255,0,0));
00875         //drawLine(tmp, (Point2D<int>)lineSeg1.p1, (Point2D<int>)lineSeg1.p2, PixRGB<byte>(255,0,0));
00876         //drawLine(tmp, (Point2D<int>)lineSeg2.p1, (Point2D<int>)lineSeg2.p2, PixRGB<byte>(0,255,0));
00877         //SHOWIMG(tmp);
00878 
00879         //drawLine(tmp, (Point2D<int>)lineSeg1.center, lineSeg1.ori, 3000.0F, PixRGB<byte>(255,0,0));
00880         //drawLine(tmp, (Point2D<int>)lineSeg2.center, lineSeg2.ori, 3000.0F, PixRGB<byte>(0,255,0));
00881         //SHOWIMG(tmp);
00882       } else {
00883         //Find the intersection
00884         double u_a = (((x4 - x3)*(y1 - y3) ) - (( y4 - y3)*(x1 - x3))) / den;
00885         double u_b = (((x2 - x1)*(y1 - y3) ) - (( y2 - y1)*(x1 - x3))) / den;
00886 
00887         intersectionPoint.i = x1 + (u_a * (x2 - x1));
00888         intersectionPoint.j = y1 + (u_a * (y2 - y1));
00889 
00890         if (u_a >= -0.1 && u_a <= 1.1 &&
00891             u_b >= -0.1 && u_b <= 1.1)
00892         {
00893 
00894           //LINFO("Line1 Ori %0.2f line 2 Ori %0.2f",
00895           //    lineSeg1.ori*180/M_PI, lineSeg2.ori*180/M_PI);
00896 
00897           float dotProduct =
00898             ((lineSeg1.center.i - intersectionPoint.i)*(lineSeg2.center.i - intersectionPoint.i)) +
00899             ((lineSeg1.center.j - intersectionPoint.j)*(lineSeg2.center.j - intersectionPoint.j));
00900           float crossProduct =
00901             ((lineSeg1.center.i - intersectionPoint.i)*(lineSeg2.center.j - intersectionPoint.j)) +
00902             ((lineSeg1.center.j - intersectionPoint.j)*(lineSeg2.center.i - intersectionPoint.i));
00903 
00904           float ang = atan2(crossProduct, dotProduct);
00905 
00906           float ori1 = atan2((intersectionPoint.j - lineSeg1.center.j),
00907                             (lineSeg1.center.i - intersectionPoint.i));
00908           float ori2 = atan2((intersectionPoint.j - lineSeg2.center.j),
00909                             (lineSeg2.center.i - intersectionPoint.i));
00910 
00911           //Find width direction the angle bisector is facing and set that as the orinetation
00912           if (ori1 < 0 )
00913             ori1 += 2*M_PI;
00914           if (ori2 < 0 )
00915             ori2 += 2*M_PI;
00916 
00917           float ori = (ori2 - ori1);
00918 
00919           if ( (fabs(ori) > M_PI && ori < 0 ) ||
00920                (fabs(ori) < M_PI && ori > 0 ) )
00921             ori = ori1 + fabs(ang/2);
00922           else
00923             ori = ori1 - fabs(ang/2);
00924 
00925           //Dont add any sharp or flat corners
00926           if (fabs(ang) < 170*M_PI/180 && fabs(ang) > 5*M_PI/180)
00927           {
00928             CornerState corner(intersectionPoint,
00929                 ori,
00930                 ang);
00931             corner.lineSeg1 = ls1Idx;
00932             corner.lineSeg2 = ls2Idx;
00933 
00934 
00935             //Find which end points are furthest from the corner
00936             if (lineSeg1.p1.distance(intersectionPoint) < lineSeg1.p2.distance(intersectionPoint))
00937               corner.endPoint1 = lineSeg1.p2;
00938             else
00939               corner.endPoint1 = lineSeg1.p1;
00940 
00941             if (lineSeg2.p1.distance(intersectionPoint) < lineSeg2.p2.distance(intersectionPoint))
00942               corner.endPoint2 = lineSeg2.p2;
00943             else
00944               corner.endPoint2 = lineSeg2.p1;
00945 
00946             itsCornersState.push_back(corner);
00947           }
00948 
00949         } else {
00950           Image<PixRGB<byte> > tmp(320,240, ZEROS);
00951           if (!tmp.coordsOk(intersectionPoint))
00952           {
00953             float L1 = lineSeg1.length;
00954             float L2 = lineSeg2.length;
00955 
00956             //float xVL = ( (lineSeg1.center.i * L1) + (lineSeg2.center.i * L2) ) / (L1 + L2);
00957             //float yVL = ( (lineSeg1.center.j * L1) + (lineSeg2.center.j * L2) ) / (L1 + L2);
00958 
00959             float xG = ((L1 *(x1 + x2) ) + (L2*(x3 + x4)))/(2*(L1+L2));
00960             float yG = ((L1 *(y1 + y2) ) + (L2*(y3 + y4)))/(2*(L1+L2));
00961 
00962             float ori1 = lineSeg1.ori;
00963             float ori2 = lineSeg2.ori;
00964 
00965             float ang = 0;
00966             if ( fabs(ori1 - ori2) <= M_PI/2)
00967               ang = ( (ori1 * L1) + (ori2 * L2) ) / (L1 + L2);
00968             else
00969               ang = ( (ori1 * L1) + ((ori2 - (M_PI*ori2/fabs(ori2))) * L2) ) / (L1 + L2);
00970 
00971 
00972             Point2D<float> p1Proj((((y1-yG)*sin(ang)) + ( (x1-xG)*cos(ang))),
00973                                   (((y1-yG)*cos(ang)) - ( (x1-xG)*sin(ang))));
00974             //Point2D<float> p1Proj( (x1-xG), (y1-yG));
00975 
00976             //Convert P1Proj back to 0 0 origin
00977             //Point2D<float> p1Disp((((p1Proj.j+yG)*sin(M_PI+ang)) + ( (p1Proj.i+xG)*cos(M_PI+ang))),
00978             //                      (((p1Proj.j+yG)*cos(M_PI+ang)) - ( (p1Proj.i+xG)*sin(M_PI+ang))));
00979             //LINFO("POint %fx%f proj %fx%f \n point=(%f,%f)",
00980             //    x1, y1,
00981             //    p1Proj.i, p1Proj.j,
00982             //    p1Disp.i, p1Disp.j);
00983 
00984             Point2D<float> p2Proj(((y2-yG)*sin(ang)) + ( (x2-xG)*cos(ang)),
00985                                   ((y2-yG)*cos(ang)) - ( (x2-xG)*sin(ang)));
00986             Point2D<float> p3Proj(((y3-yG)*sin(ang)) + ( (x3-xG)*cos(ang)),
00987                                   ((y3-yG)*cos(ang)) - ( (x3-xG)*sin(ang)));
00988             Point2D<float> p4Proj(((y4-yG)*sin(ang)) + ( (x4-xG)*cos(ang)),
00989                                   ((y4-yG)*cos(ang)) - ( (x4-xG)*sin(ang)));
00990 
00991             float points[4] = {p1Proj.i, p2Proj.i, p3Proj.i, p4Proj.i};
00992 
00993             float min = points[0];
00994             float max = points[0];
00995 
00996             for(int i=1; i<4; i++)
00997             {
00998               if (points[i] > max)
00999                 max = points[i];
01000               if (points[i] < min)
01001                 min = points[i];
01002             }
01003 
01004             //LINFO("POints %f %f %f %f",
01005             //    points[0], points[1], points[2], points[3]);
01006             //LINFO("Max %f min %f", max, min);
01007 
01008             float totalLength = fabs(max-min);
01009             //LINFO("Distance %f  totalLength %f",
01010             //    totalLength, L1+L2);
01011 
01012             //Do we have overlap with some noise
01013             if (totalLength < L1+L2 + 10)
01014             {
01015               SymmetryState  symState;
01016               symState.lineSeg1 = ls1Idx;
01017               symState.lineSeg2 = ls2Idx;
01018               symState.center = Point2D<float>(xG,yG);
01019               symState.ang = ang;
01020               symState.length = totalLength;
01021 
01022               itsSymmetries.push_back(symState);
01023 
01024 
01025              // Point2D<int> center((int)xG, (int)yG);
01026 
01027              // //drawCircle(tmp, (Point2D<int>)p1Disp, 3, PixRGB<byte>(0,255,0), 2);
01028              // //drawCircle(tmp, (Point2D<int>)p2Proj, 3, PixRGB<byte>(0,255,0), 2);
01029              // //drawCircle(tmp, (Point2D<int>)p3Proj, 3, PixRGB<byte>(0,255,0), 2);
01030              // //drawCircle(tmp, (Point2D<int>)p4Proj, 3, PixRGB<byte>(0,255,0), 2);
01031 
01032              // drawCircle(tmp, center, 3, PixRGB<byte>(0,255,255), 2);
01033              // drawLine(tmp, center, ang, 3000.0F, PixRGB<byte>(255,0,0));
01034              // drawLine(tmp, (Point2D<int>)lineSeg1.p1, (Point2D<int>)lineSeg1.p2, PixRGB<byte>(255,0,0));
01035              // drawLine(tmp, (Point2D<int>)lineSeg2.p1, (Point2D<int>)lineSeg2.p2, PixRGB<byte>(0,255,0));
01036              // SHOWIMG(tmp);
01037 
01038              // drawLine(tmp, (Point2D<int>)lineSeg1.center, lineSeg1.ori, 3000.0F, PixRGB<byte>(255,0,0));
01039              // drawLine(tmp, (Point2D<int>)lineSeg2.center, lineSeg2.ori, 3000.0F, PixRGB<byte>(0,255,0));
01040              // SHOWIMG(tmp);
01041             }
01042           }
01043         }
01044       }
01045 
01046 
01047 
01048       //LINFO("Intersection %fx%f", x, y);
01049 
01050 
01051       //if (!tmpImg.coordsOk(intersectionPoint) &&
01052       //    fabs(lineSeg1.length - lineSeg2.length) < 10.0F && false)
01053       //{
01054       //  Image<PixRGB<byte> > tmp = tmpImg;
01055       //  drawLine(tmp, (Point2D<int>)lineSeg1.p1, (Point2D<int>)lineSeg1.p2, PixRGB<byte>(255,0,0));
01056       //  drawLine(tmp, (Point2D<int>)lineSeg2.p1, (Point2D<int>)lineSeg2.p2, PixRGB<byte>(0,255,0));
01057       //  SHOWIMG(tmp);
01058 
01059       //  drawLine(tmp, (Point2D<int>)lineSeg1.center, lineSeg1.ori, 3000.0F, PixRGB<byte>(255,0,0));
01060       //  drawLine(tmp, (Point2D<int>)lineSeg2.center, lineSeg2.ori, 3000.0F, PixRGB<byte>(0,255,0));
01061       //  drawCircle(tmp, (Point2D<int>)intersectionPoint, 6, PixRGB<byte>(0,255,255));
01062       //  SHOWIMG(tmp);
01063       //}
01064 
01065 
01066     }
01067   }
01068 
01069 }
01070 
01071 
01072 
01073 
01074 
01075 void V2::findLines(const Image<float> &mag, const Image<float>& ori, Image<float>& retMag, Image<float>& retOri)
01076 {
01077   retMag = Image<float>(mag.getDims()/2, ZEROS);
01078   retOri = Image<float>(ori.getDims()/2, ZEROS);
01079 
01080   Dims win(3,3);
01081   for(int y=0; y<mag.getHeight()-win.h()-1; y += 2)
01082     for(int x=0; x<mag.getWidth()-win.w()-1; x += 2)
01083     {
01084       double sumSin = 0, sumCos = 0;
01085       float numElem = 0;
01086       float totalWeight = 0;
01087 
01088       double meanLocX = 0, meanLocY = 0;
01089       Image<float> tt(win, ZEROS);
01090 
01091       //Add the angles within the window into the histogram
01092       float hist[360];
01093       for(int wy=0; wy<win.h(); wy++)
01094         for(int wx=0; wx<win.w(); wx++)
01095         {
01096           float val = mag.getVal(x+wx,y+wy);
01097 
01098           if (val > 0)
01099           {
01100             float ang = ori.getVal(x+wx,y+wy) + M_PI/2;
01101             meanLocX += wx;
01102             meanLocY += wy;
01103             sumSin += sin(ang); //*mag;
01104             sumCos += cos(ang); //*mag;
01105             numElem++;
01106             totalWeight += 1; //mag;
01107 
01108             //Add to histogram
01109             int angI = (int)(ang*180.0/M_PI);
01110             if (angI < 0) angI += 360;
01111             if (angI > 360) angI -= 360;
01112             hist[angI] += 1; //mag;
01113             //tt.setVal(wx,wy,mag);
01114           }
01115         }
01116       if (numElem > 0)
01117       {
01118         double xMean = sumSin/totalWeight;
01119         double yMean = sumCos/totalWeight;
01120         double sum = sqrt( xMean*xMean + yMean*yMean);
01121         float ang = atan2(xMean, yMean);
01122 
01123         if (sum > 0.99)
01124         {
01125           //This must be an edge, calculate the angle from the mean
01126           //drawLine(LTmp, Point2D<int>(x+(int)(meanLocX/numElem), y+(int)(meanLocY/numElem)), (float)ang, win.w(), 255.0F); // (float)ang);
01127           //V1::EdgeState edgeState;
01128           //edgeState.pos = Point2D<int>(x+(int)(meanLocX/numElem), y+(int)(meanLocY/numElem));
01129           //edgeState.ori = ang;
01130           //edgeState.var = (10*M_PI/180)*(10*M_PI/180); //10
01131           //edgeState.prob = sum;
01132           //itsEdgesState.push_back(edgeState);
01133 
01134           retMag.setVal(Point2D<int>(x/2+(int)(meanLocX/numElem), y/2+(int)(meanLocY/numElem)), 255.0);
01135           retOri.setVal(Point2D<int>(x/2+(int)(meanLocX/numElem), y/2+(int)(meanLocY/numElem)), ang-M_PI/2);
01136           //nLines++;
01137         } else {
01138           //We have a corner
01139         }
01140       } else {
01141         //Stmp.setVal(x,y,0.0);
01142       }
01143     }
01144 
01145 }
01146 
01147 void V2::evolve(Image<PixRGB<byte> >& img)
01148 {
01149 
01150   Image<float> lum = luminance(img);
01151   SHOWIMG(lum);
01152   inplaceNormalize(lum, 0.0F, 255.0F);
01153 
01154   std::vector<LineSegment> lines = lineSegmentDetection(lum);
01155 
01156   Image<PixRGB<byte> > edgesImg(lum.getDims(), ZEROS);
01157   for(uint i=0; i<lines.size(); i++)
01158   {
01159     LineSegment& ls = lines[i];
01160     drawLine(edgesImg, (Point2D<int>)ls.p1, (Point2D<int>)ls.p2, PixRGB<byte>(255,0,0), 1); //(int)ls.width);
01161   }
01162 
01163   SHOWIMG(edgesImg);
01164 
01165 }
01166 
01167 void V2::evolve(Image<float>& img)
01168 {
01169 
01170   //SHOWIMG(img);
01171   inplaceNormalize(img, 0.0F, 255.0F);
01172 
01173   itsLines = lineSegmentDetection(img);
01174 
01175   //Image<PixRGB<byte> > edgesImg(.getDims(), ZEROS);
01176   //for(uint i=0; i<lines.size(); i++)
01177   //{
01178   //  LineSegment& ls = lines[i];
01179   //  drawLine(edgesImg, (Point2D<int>)ls.p1, (Point2D<int>)ls.p2, PixRGB<byte>(255,0,0), 1); //(int)ls.width);
01180   //}
01181 
01182   //SHOWIMG(edgesImg);
01183 
01184 }
01185 
01186 
01187 void V2::evolve(TensorField& tensorField)
01188 {
01189   nonMaxSurp(tensorField);
01190 
01191   LINFO("Get LInes");
01192   std::vector<LineSegment> lines = lineSegmentDetection(tensorField);
01193   LINFO("Show %i Lines", (uint)lines.size());
01194 
01195   Image<PixRGB<byte> > edgesImg(tensorField.t1.getDims(), ZEROS);
01196   for(uint i=0; i<lines.size(); i++)
01197   {
01198     LineSegment& ls = lines[i];
01199     drawLine(edgesImg, (Point2D<int>)ls.p1, (Point2D<int>)ls.p2, PixRGB<byte>(255,0,0), 1); //(int)ls.width);
01200   }
01201 
01202   //SHOWIMG(edgesImg);
01203 
01204 }
01205 
01206 Layout<PixRGB<byte> > V2::getDebugImage()
01207 {
01208   Layout<PixRGB<byte> > outDisp;
01209 
01210   Image<float> input = itsLGNInput[0];
01211   //input = rescale(input, 320, 240);
01212   Image<PixRGB<byte> > linesLumImg = input;
01213   Image<PixRGB<byte> > linesImg(input.getDims(), ZEROS);
01214   for(uint i=0; i<itsLines.size(); i++)
01215   {
01216     LineSegment& ls = itsLines[i];
01217     if (ls.strength > 0)
01218     {
01219       PixRGB<byte> color;
01220       switch(ls.color)
01221       {
01222         case 0: color = PixRGB<byte>(255,0,0); break;
01223         case 1: color = PixRGB<byte>(0,255,0); break;
01224         case 2: color = PixRGB<byte>(0,0,255); break;
01225       }
01226 
01227       drawLine(linesLumImg, (Point2D<int>)ls.p1, (Point2D<int>)ls.p2,color, 1); //(int)ls.width);
01228       drawLine(linesImg, (Point2D<int>)ls.p1, (Point2D<int>)ls.p2, PixRGB<byte>(255,0,0)); 
01229     }
01230   }
01231   outDisp = hcat(linesLumImg, linesImg);
01232   EigenSpace eigen = getTensorEigen(itsMaxTF);
01233   Image<float> maxTf = eigen.l1-eigen.l2;
01234   inplaceNormalize(maxTf, 0.0F, 255.0F);
01235   Image<PixRGB<byte> > maxEdges = toRGB(maxTf);
01236   outDisp = hcat(outDisp, maxEdges);
01237 
01238   Layout<PixRGB<byte> > tensorDisp;
01239   Image<PixRGB<byte> > lumEdges = toRGB(itsLumTV.getTokensMag(true));
01240   Image<PixRGB<byte> > rgEdges = toRGB(itsRGTV.getTokensMag(true));
01241   Image<PixRGB<byte> > byEdges = toRGB(itsBYTV.getTokensMag(true));
01242 
01243   tensorDisp = hcat(lumEdges, rgEdges);
01244   tensorDisp = hcat(tensorDisp, byEdges);
01245 
01246   outDisp = vcat(outDisp, tensorDisp);
01247 
01248   return outDisp;
01249 
01250 }
01251 
01252 
01253 
01254 ///////////////////////////////////////////////////////////////////////// LSD computations ////////////////////////////////////////////////////
01255 /*----------------------------------------------------------------------------*/
01256 /*------------------------------ Gradient Angle ------------------------------*/
01257 /*----------------------------------------------------------------------------*/
01258 
01259 /*----------------------------------------------------------------------------*/
01260 /*
01261    compute the direction of the level line at each point.
01262    it returns:
01263 
01264    - an image_float with the angle at each pixel or NOTDEF.
01265    - the image_float 'modgrad' (a pointer is passed as argument)
01266      with the gradient magnitude at each point.
01267    - a list of pixels 'list_p' roughly ordered by gradient magnitude.
01268      (the order is made by classing points into bins by gradient magnitude.
01269       the parameters 'n_bins' and 'max_grad' specify the number of
01270       bins and the gradient modulus at the highest bin.)
01271    - a pointer 'mem_p' to the memory used by 'list_p' to be able to
01272      free the memory.
01273  */
01274 Image<float> V2::ll_angle(Image<float>& in, float threshold,
01275                              std::vector<Point2D<int> > &list_p, void ** mem_p,
01276                              Image<float>& modgrad, int n_bins, int max_grad )
01277 {
01278   Image<float> grad(in.getWidth(), in.getHeight(), ZEROS);
01279   int n,p,adr,i;
01280   float com1,com2,gx,gy,norm2;
01281   /* variables used in pseudo-ordering of gradient magnitude */
01282   float f_n_bins = (float) n_bins;
01283   float f_max_grad = (float) max_grad;
01284   int list_count = 0;
01285   struct coorlist * list;
01286   struct coorlist ** range_l_s;
01287   struct coorlist ** range_l_e;
01288   struct coorlist * start;
01289   struct coorlist * end;
01290 
01291 
01292   threshold *= 4.0 * threshold;
01293 
01294   n = in.getHeight();
01295   p = in.getWidth();
01296 
01297   /* get memory for the image of gradient modulus */
01298   modgrad = Image<float>(in.getWidth(),in.getHeight(), ZEROS);
01299 
01300   /* get memory for "ordered" coordinate list */
01301   list = (struct coorlist *) calloc(n*p,sizeof(struct coorlist));
01302   *mem_p = (void *) list;
01303   range_l_s = (struct coorlist **) calloc(n_bins,sizeof(struct coorlist *));
01304   range_l_e = (struct coorlist **) calloc(n_bins,sizeof(struct coorlist *));
01305   if( !list || !range_l_s || !range_l_e ) LFATAL("Not enough memory.");
01306   for(i=0;i<n_bins;i++) range_l_s[i] = range_l_e[i] = NULL;
01307 
01308   /* undefined on downright boundary */
01309   for(int x=0;x<p;x++) grad[(n-1)*p+x] = NOTDEF;
01310   for(int y=0;y<n;y++) grad[p*y+p-1]   = NOTDEF;
01311 
01312   /*** remaining part ***/
01313   for(int x=0;x<p-1;x++)
01314     for(int y=0;y<n-1;y++)
01315       {
01316         adr = y*p+x;
01317 
01318         /* norm 2 computation */
01319         com1 = in[adr+p+1] - in[adr];
01320         com2 = in[adr+1]   - in[adr+p];
01321         gx = com1+com2;
01322         gy = com1-com2;
01323         norm2 = gx*gx+gy*gy;
01324 
01325         modgrad[adr] = (float) sqrt( (double) norm2 / 4.0 );
01326 
01327         if(norm2 <= threshold) /* norm too small, gradient no defined */
01328           grad[adr] = NOTDEF;
01329         else
01330           {
01331             /* angle computation */
01332             grad[adr] = (float) atan2(gx,-gy);
01333 
01334             /* store the point in the right bin,
01335                according to its norm */
01336             i = (int) (norm2 * f_n_bins / f_max_grad);
01337             if(i>=n_bins) i = n_bins-1;
01338             if( range_l_e[i]==NULL )
01339               range_l_s[i] = range_l_e[i] = list+list_count++;
01340             else
01341               {
01342                 range_l_e[i]->next = list+list_count;
01343                 range_l_e[i] = list+list_count++;
01344               }
01345             range_l_e[i]->x = x;
01346             range_l_e[i]->y = y;
01347             range_l_e[i]->next = NULL;
01348           }
01349       }
01350 
01351   /* make the list of points "ordered" by norm value */
01352   for(i=n_bins-1; i>0 && range_l_s[i]==NULL; i--);
01353   start = range_l_s[i];
01354   end = range_l_e[i];
01355   if(start!=NULL)
01356     for(i--;i>0; i--)
01357       if( range_l_s[i] != NULL )
01358         {
01359           end->next = range_l_s[i];
01360           end = range_l_e[i];
01361         }
01362 
01363   struct coorlist * lp = start;
01364 
01365   for(;lp; lp = lp->next )
01366     list_p.push_back(Point2D<int>(lp->x, lp->y));
01367 
01368 
01369   /* free memory */
01370   free(range_l_s);
01371   free(range_l_e);
01372 
01373   return grad;
01374 }
01375 
01376 /*----------------------------------------------------------------------------*/
01377 /*------------------------------ Gradient Angle ------------------------------*/
01378 /*----------------------------------------------------------------------------*/
01379 
01380 /*----------------------------------------------------------------------------*/
01381 /*
01382    compute the direction of the level line at each point.
01383    it returns:
01384 
01385    - an image_float with the angle at each pixel or NOTDEF.
01386    - the image_float 'modgrad' (a pointer is passed as argument)
01387      with the gradient magnitude at each point.
01388    - a list of pixels 'list_p' roughly ordered by gradient magnitude.
01389      (the order is made by classing points into bins by gradient magnitude.
01390       the parameters 'n_bins' and 'max_grad' specify the number of
01391       bins and the gradient modulus at the highest bin.)
01392    - a pointer 'mem_p' to the memory used by 'list_p' to be able to
01393      free the memory.
01394  */
01395 Image<float> V2::ll_angle(const TensorField& tensorField, float threshold,
01396                              std::vector<Point2D<int> > &list_p,
01397                              Image<float>& modgrad, int n_bins, int max_grad )
01398 {
01399   Image<float> grad(tensorField.t1.getWidth(), tensorField.t1.getHeight(), ZEROS);
01400   int n,p,i;
01401   //float com1,com2,gx,gy,norm2;
01402   /* variables used in pseudo-ordering of gradient magnitude */
01403   float f_n_bins = (float) n_bins;
01404   float f_max_grad = (float) max_grad;
01405   int list_count = 0;
01406   struct coorlist * list;
01407   struct coorlist ** range_l_s;
01408   struct coorlist ** range_l_e;
01409   struct coorlist * start;
01410   struct coorlist * end;
01411 
01412 
01413   n = tensorField.t1.getHeight();
01414   p = tensorField.t1.getWidth();
01415 
01416   /* get memory for the image of gradient modulus */
01417   modgrad = Image<float>(tensorField.t1.getWidth(),tensorField.t1.getHeight(), ZEROS);
01418 
01419   /* get memory for "ordered" coordinate list */
01420   list = (struct coorlist *) calloc(n*p,sizeof(struct coorlist));
01421   range_l_s = (struct coorlist **) calloc(n_bins,sizeof(struct coorlist *));
01422   range_l_e = (struct coorlist **) calloc(n_bins,sizeof(struct coorlist *));
01423   if( !list || !range_l_s || !range_l_e ) LFATAL("Not enough memory.");
01424 
01425   for(i=0;i<n_bins;i++)
01426     range_l_s[i] = range_l_e[i] = NULL;
01427 
01428   EigenSpace eigen = getTensorEigen(tensorField);
01429   Image<float> features = eigen.l1-eigen.l2;
01430   inplaceNormalize(features, 0.0F, f_max_grad);
01431 
01432   for(int y=0; y<features.getHeight(); y++)
01433     for(int x=0; x<features.getWidth(); x++)
01434     {
01435       /* norm 2 computation */
01436       //double norm2 = tensorField.t1.getVal(x,y) + tensorField.t4.getVal(x,y);
01437       //modgrad.setVal(x,y, (float) sqrt( (double) norm2 / 4.0 ));
01438       //float norm2 = eigen.l1.getVal(x,y) - eigen.l2.getVal(x,y);
01439       float val = features.getVal(x,y);
01440       modgrad.setVal(x,y, val);
01441 
01442       if(val > threshold) /* norm too small, gradient no defined */
01443       {
01444         /* angle computation */
01445 
01446         //Get the direction of the vote from e1, while the weight is l1-l2
01447         float u = eigen.e1[1].getVal(x,y);
01448         float v = eigen.e1[0].getVal(x,y);
01449         grad.setVal(x,y, atan(-u/v));
01450 
01451         /* store the point in the right bin,
01452            according to its norm */
01453         i = (int) (val * f_n_bins / f_max_grad);
01454         if(i>=n_bins) i = n_bins-1;
01455         if( range_l_e[i]==NULL )
01456           range_l_s[i] = range_l_e[i] = list+list_count++;
01457         else
01458         {
01459           range_l_e[i]->next = list+list_count;
01460           range_l_e[i] = list+list_count++;
01461         }
01462         range_l_e[i]->x = x;
01463         range_l_e[i]->y = y;
01464         range_l_e[i]->next = NULL;
01465       } else {
01466         grad.setVal(x,y,NOTDEF);
01467       }
01468   }
01469 
01470   /* make the list of points "ordered" by norm value */
01471   for(i=n_bins-1; i>0 && range_l_s[i]==NULL; i--);
01472   start = range_l_s[i];
01473   end = range_l_e[i];
01474   if(start!=NULL)
01475     for(i--;i>0; i--)
01476       if( range_l_s[i] != NULL )
01477         {
01478           end->next = range_l_s[i];
01479           end = range_l_e[i];
01480         }
01481 
01482   struct coorlist * lp = start;
01483 
01484   for(;lp; lp = lp->next )
01485     list_p.push_back(Point2D<int>(lp->x, lp->y));
01486 
01487   /* free memory */
01488   free(range_l_s);
01489   free(range_l_e);
01490   free(list);
01491 
01492   return grad;
01493 }
01494 
01495 /*----------------------------------------------------------------------------*/
01496 /*
01497    find if the point x,y in angles have angle theta up to precision prec
01498  */
01499 bool V2::isaligned(Point2D<int> loc,const Image<float>& angles,
01500                    float theta, float prec)
01501 {
01502   if (!angles.coordsOk(loc)) return false;
01503 
01504   float a = angles.getVal(loc);
01505 
01506   if( a == NOTDEF ) return false;
01507 
01508   /* it is assumed that theta and a are in the range [-pi,pi] */
01509   theta -= a;
01510   if( theta < 0.0 ) theta = -theta;
01511   if( theta > M_3_2_PI )
01512     {
01513       theta -= M_2__PI;
01514       if( theta < 0.0 ) theta = -theta;
01515     }
01516 
01517   //LINFO("Theta %f < %f", theta, prec);
01518   return theta < prec;
01519 }
01520 
01521 /*----------------------------------------------------------------------------*/
01522 float V2::angle_diff(float a, float b)
01523 {
01524   a -= b;
01525   while( a <= -M_PI ) a += 2.0*M_PI;
01526   while( a >   M_PI ) a -= 2.0*M_PI;
01527   if( a < 0.0 ) a = -a;
01528   return a;
01529 }
01530 
01531 
01532 
01533 /*----------------------------------------------------------------------------*/
01534 /*----------------------------- NFA computation ------------------------------*/
01535 /*----------------------------------------------------------------------------*/
01536 
01537 /*----------------------------------------------------------------------------*/
01538 /*
01539    Calculates the natural logarithm of the absolute value of
01540    the gamma function of x using the Lanczos approximation,
01541    see http://www.rskey.org/gamma.htm.
01542 
01543    The formula used is
01544      \Gamma(x) = \frac{ \sum_{n=0}^{N} q_n x^n }{ \Pi_{n=0}^{N} (x+n) }
01545                  (x+5.5)^(x+0.5) e^{-(x+5.5)}
01546    so
01547      \log\Gamma(x) = \log( \sum_{n=0}^{N} q_n x^n ) + (x+0.5) \log(x+5.5)
01548                      - (x+5.5) - \sum_{n=0}^{N} \log(x+n)
01549    and
01550      q0 = 75122.6331530
01551      q1 = 80916.6278952
01552      q2 = 36308.2951477
01553      q3 = 8687.24529705
01554      q4 = 1168.92649479
01555      q5 = 83.8676043424
01556      q6 = 2.50662827511
01557  */
01558 double V2::log_gamma_lanczos(double x)
01559 {
01560   static double q[7] = { 75122.6331530, 80916.6278952, 36308.2951477,
01561                          8687.24529705, 1168.92649479, 83.8676043424,
01562                          2.50662827511 };
01563   double a = (x+0.5) * log(x+5.5) - (x+5.5);
01564   double b = 0.0;
01565   int n;
01566 
01567   for(n=0;n<7;n++)
01568     {
01569       a -= log( x + (double) n );
01570       b += q[n] * pow( x, (double) n );
01571     }
01572   return a + log(b);
01573 }
01574 
01575 /*----------------------------------------------------------------------------*/
01576 /*
01577    Calculates the natural logarithm of the absolute value of
01578    the gamma function of x using Robert H. Windschitl method,
01579    see http://www.rskey.org/gamma.htm.
01580 
01581    The formula used is
01582      \Gamma(x) = \sqrt(\frac{2\pi}{x}) ( \frac{x}{e}
01583                    \sqrt{ x\sinh(1/x) + \frac{1}{810x^6} } )^x
01584    so
01585      \log\Gamma(x) = 0.5\log(2\pi) + (x-0.5)\log(x) - x
01586                      + 0.5x\log( x\sinh(1/x) + \frac{1}{810x^6} ).
01587 
01588    This formula is good approximation when x > 15.
01589  */
01590 double V2::log_gamma_windschitl(double x)
01591 {
01592   return 0.918938533204673 + (x-0.5)*log(x) - x
01593          + 0.5*x*log( x*sinh(1/x) + 1/(810.0*pow(x,6.0)) );
01594 }
01595 
01596 /*----------------------------------------------------------------------------*/
01597 /*
01598    Calculates the natural logarithm of the absolute value of
01599    the gamma function of x. When x>15 use log_gamma_windschitl(),
01600    otherwise use log_gamma_lanczos().
01601  */
01602 #define log_gamma(x) ((x)>15.0?log_gamma_windschitl(x):log_gamma_lanczos(x))
01603 
01604 /*----------------------------------------------------------------------------*/
01605 /*
01606    Computes the logarithm of NFA to base 10.
01607 
01608    NFA = NT.b(n,k,p)
01609    the return value is log10(NFA)
01610 
01611    n,k,p - binomial parameters.
01612    logNT - logarithm of Number of Tests
01613  */
01614 #define TABSIZE 100000
01615 double V2::nfa(int n, int k, double p, double logNT)
01616 {
01617   static double inv[TABSIZE];   /* table to keep computed inverse values */
01618   double tolerance = 0.1;       /* an error of 10% in the result is accepted */
01619   double log1term,term,bin_term,mult_term,bin_tail,err;
01620   double p_term = p / (1.0-p);
01621   int i;
01622 
01623   if( n<0 || k<0 || k>n || p<0.0 || p>1.0 )
01624     LFATAL("Wrong n=%i, k=%i or p=%f values in nfa()", n, k, p);
01625 
01626   if( n==0 || k==0 ) return -logNT;
01627   if( n==k ) return -logNT - (double) n * log10(p);
01628 
01629   log1term = log_gamma((double)n+1.0) - log_gamma((double)k+1.0)
01630            - log_gamma((double)(n-k)+1.0)
01631            + (double) k * log(p) + (double) (n-k) * log(1.0-p);
01632 
01633   term = exp(log1term);
01634   if( double_equal(term,0.0) )              /* the first term is almost zero */
01635     {
01636       if( (double) k > (double) n * p )    /* at begin or end of the tail? */
01637         return -log1term / M_LN10 - logNT; /* end: use just the first term */
01638       else
01639         return -logNT;                     /* begin: the tail is roughly 1 */
01640     }
01641 
01642   bin_tail = term;
01643   for(i=k+1;i<=n;i++)
01644     {
01645       bin_term = (double) (n-i+1) * ( i<TABSIZE ?
01646                    ( inv[i] != 0.0 ? inv[i] : (inv[i]=1.0/(double)i))
01647                    : 1.0/(double)i );
01648       mult_term = bin_term * p_term;
01649       term *= mult_term;
01650       bin_tail += term;
01651       if(bin_term<1.0)
01652         {
01653           /* when bin_term<1 then mult_term_j<mult_term_i for j>i.
01654              then, the error on the binomial tail when truncated at
01655              the i term can be bounded by a geometric series of form
01656              term_i * sum mult_term_i^j.                            */
01657           err = term * ( ( 1.0 - pow( mult_term, (double) (n-i+1) ) ) /
01658                          (1.0-mult_term) - 1.0 );
01659 
01660           /* one wants an error at most of tolerance*final_result, or:
01661              tolerance * abs(-log10(bin_tail)-logNT).
01662              now, the error that can be accepted on bin_tail is
01663              given by tolerance*final_result divided by the derivative
01664              of -log10(x) when x=bin_tail. that is:
01665              tolerance * abs(-log10(bin_tail)-logNT) / (1/bin_tail)
01666              finally, we truncate the tail if the error is less than:
01667              tolerance * abs(-log10(bin_tail)-logNT) * bin_tail        */
01668           if( err < tolerance * fabs(-log10(bin_tail)-logNT) * bin_tail ) break;
01669         }
01670     }
01671   return -log10(bin_tail) - logNT;
01672 }
01673 
01674 
01675 
01676 //double V2::nfa(int n, int k, double p, double logNT)
01677 //{
01678 //  double N1[2] = {1.0337965773779e-06,   -0.00215083485137987};
01679 //  double N2[2] = {-8.53870284101796e-06,  0.0273185078224109};
01680 //  double N3[2] = {0.000230591970586356,  -0.828902881766958};
01681 //  double N4[2] = {-0.000233656573018064,  0.719832739194112};
01682 //
01683 //  double F1 = N1[1]*n + N1[0];
01684 //  double F2 = N2[1]*n + N2[0];
01685 //  double F3 = N3[1]*n + N3[0];
01686 //  double F4 = N4[1]*n + N4[0];
01687 //
01688 //
01689 //  double prob = F1*k*k*k + F2*k*k + F3*k + F4;
01690 //
01691 //  return -log10(exp(prob)) - logNT;
01692 //}
01693 
01694 
01695 
01696 /*----------------------------------------------------------------------------*/
01697 void V2::rect_copy(struct rect * in, struct rect * out)
01698 {
01699   out->x1 = in->x1;
01700   out->y1 = in->y1;
01701   out->x2 = in->x2;
01702   out->y2 = in->y2;
01703   out->width = in->width;
01704   out->x = in->x;
01705   out->y = in->y;
01706   out->theta = in->theta;
01707   out->dx = in->dx;
01708   out->dy = in->dy;
01709   out->prec = in->prec;
01710   out->p = in->p;
01711 }
01712 
01713 
01714 
01715 /*----------------------------------------------------------------------------*/
01716 float V2::inter_low(float x, float x1, float y1, float x2, float y2)
01717 {
01718   if( x1 > x2 || x < x1 || x > x2 )
01719     {
01720       LFATAL("inter_low: x %g x1 %g x2 %g.\n",x,x1,x2);
01721       LFATAL("Impossible situation.");
01722     }
01723   if( x1 == x2 && y1<y2 ) return y1;
01724   if( x1 == x2 && y1>y2 ) return y2;
01725   return y1 + (x-x1) * (y2-y1) / (x2-x1);
01726 }
01727 
01728 /*----------------------------------------------------------------------------*/
01729 float V2::inter_hi(float x, float x1, float y1, float x2, float y2)
01730 {
01731   if( x1 > x2 || x < x1 || x > x2 )
01732     {
01733       LFATAL("inter_hi: x %g x1 %g x2 %g.\n",x,x1,x2);
01734       LFATAL("Impossible situation.");
01735     }
01736   if( x1 == x2 && y1<y2 ) return y2;
01737   if( x1 == x2 && y1>y2 ) return y1;
01738   return y1 + (x-x1) * (y2-y1) / (x2-x1);
01739 }
01740 
01741 /*----------------------------------------------------------------------------*/
01742 void V2::ri_del(rect_iter * iter)
01743 {
01744   free(iter);
01745 }
01746 
01747 /*----------------------------------------------------------------------------*/
01748 int V2::ri_end(rect_iter * i)
01749 {
01750   return (float)(i->x) > i->vx[2];
01751 }
01752 
01753 int V2::ri_end(rect_iter& itr)
01754 {
01755   return (float)(itr.x) > itr.vx[2];
01756 }
01757 
01758 /*----------------------------------------------------------------------------*/
01759 void V2::ri_inc(rect_iter * i)
01760 {
01761   if( (float) (i->x) <= i->vx[2] ) i->y++;
01762 
01763   while( (float) (i->y) > i->ye && (float) (i->x) <= i->vx[2] )
01764     {
01765       /* new x */
01766       i->x++;
01767 
01768       if( (float) (i->x) > i->vx[2] ) return; /* end of iteration */
01769 
01770       /* update lower y limit for the line */
01771       if( (float) i->x < i->vx[3] )
01772         i->ys = inter_low((float)i->x,i->vx[0],i->vy[0],i->vx[3],i->vy[3]);
01773       else i->ys = inter_low((float)i->x,i->vx[3],i->vy[3],i->vx[2],i->vy[2]);
01774 
01775       /* update upper y limit for the line */
01776       if( (float)i->x < i->vx[1] )
01777         i->ye = inter_hi((float)i->x,i->vx[0],i->vy[0],i->vx[1],i->vy[1]);
01778       else i->ye = inter_hi( (float)i->x,i->vx[1],i->vy[1],i->vx[2],i->vy[2]);
01779 
01780       /* new y */
01781       i->y = (int)((float) ceil( (double) i->ys ));
01782     }
01783 }
01784 
01785 /*----------------------------------------------------------------------------*/
01786 void V2::ri_inc(rect_iter& itr)
01787 {
01788   if( (float) (itr.x) <= itr.vx[2] ) itr.y++;
01789 
01790   while( (float) (itr.y) > itr.ye && (float) (itr.x) <= itr.vx[2] )
01791     {
01792       /* new x */
01793       itr.x++;
01794 
01795       if( (float) (itr.x) > itr.vx[2] ) return; /* end of iteration */
01796 
01797       /* update lower y limit for the line */
01798       if( (float) itr.x < itr.vx[3] )
01799         itr.ys = inter_low((float)itr.x,itr.vx[0],itr.vy[0],itr.vx[3],itr.vy[3]);
01800       else itr.ys = inter_low((float)itr.x,itr.vx[3],itr.vy[3],itr.vx[2],itr.vy[2]);
01801 
01802       /* update upper y limit for the line */
01803       if( (float)itr.x < itr.vx[1] )
01804         itr.ye = inter_hi((float)itr.x,itr.vx[0],itr.vy[0],itr.vx[1],itr.vy[1]);
01805       else itr.ye = inter_hi( (float)itr.x,itr.vx[1],itr.vy[1],itr.vx[2],itr.vy[2]);
01806 
01807       /* new y */
01808       itr.y = (int)((float) ceil( (double) itr.ys ));
01809     }
01810 }
01811 
01812 
01813 /*----------------------------------------------------------------------------*/
01814 V2::rect_iter * V2::ri_ini(struct rect * r)
01815 {
01816   float vx[4],vy[4];
01817   int n,offset;
01818   rect_iter * i;
01819 
01820   i = (rect_iter *) malloc(sizeof(rect_iter));
01821   if(!i) LFATAL("ri_ini: Not enough memory.");
01822 
01823   vx[0] = r->x1 - r->dy * r->width / 2.0;
01824   vy[0] = r->y1 + r->dx * r->width / 2.0;
01825   vx[1] = r->x2 - r->dy * r->width / 2.0;
01826   vy[1] = r->y2 + r->dx * r->width / 2.0;
01827   vx[2] = r->x2 + r->dy * r->width / 2.0;
01828   vy[2] = r->y2 - r->dx * r->width / 2.0;
01829   vx[3] = r->x1 + r->dy * r->width / 2.0;
01830   vy[3] = r->y1 - r->dx * r->width / 2.0;
01831 
01832   if( r->x1 < r->x2 && r->y1 <= r->y2 ) offset = 0;
01833   else if( r->x1 >= r->x2 && r->y1 < r->y2 ) offset = 1;
01834   else if( r->x1 > r->x2 && r->y1 >= r->y2 ) offset = 2;
01835   else offset = 3;
01836   /* else if( r->x1 <= r->x2 && r->y1 > r->y2 ) offset = 3; */
01837 
01838   for(n=0; n<4; n++)
01839     {
01840       i->vx[n] = vx[(offset+n)%4];
01841       i->vy[n] = vy[(offset+n)%4];
01842     }
01843 
01844   /* starting point */
01845   i->x = (int)(ceil( (double) (i->vx[0]) ) - 1);
01846   i->y = (int)(ceil( (double) (i->vy[0]) ));
01847   i->ys = i->ye = -BIG_NUMBER;
01848 
01849   /* advance to the first point */
01850   ri_inc(i);
01851 
01852   return i;
01853 }
01854 
01855 /*----------------------------------------------------------------------------*/
01856 void V2::ri_ini(struct rect * r, rect_iter& itr)
01857 {
01858   float vx[4],vy[4];
01859   int n,offset;
01860 
01861   vx[0] = r->x1 - r->dy * r->width / 2.0;
01862   vy[0] = r->y1 + r->dx * r->width / 2.0;
01863   vx[1] = r->x2 - r->dy * r->width / 2.0;
01864   vy[1] = r->y2 + r->dx * r->width / 2.0;
01865   vx[2] = r->x2 + r->dy * r->width / 2.0;
01866   vy[2] = r->y2 - r->dx * r->width / 2.0;
01867   vx[3] = r->x1 + r->dy * r->width / 2.0;
01868   vy[3] = r->y1 - r->dx * r->width / 2.0;
01869 
01870   if( r->x1 < r->x2 && r->y1 <= r->y2 ) offset = 0;
01871   else if( r->x1 >= r->x2 && r->y1 < r->y2 ) offset = 1;
01872   else if( r->x1 > r->x2 && r->y1 >= r->y2 ) offset = 2;
01873   else offset = 3;
01874   /* else if( r->x1 <= r->x2 && r->y1 > r->y2 ) offset = 3; */
01875 
01876   for(n=0; n<4; n++)
01877     {
01878       itr.vx[n] = vx[(offset+n)%4];
01879       itr.vy[n] = vy[(offset+n)%4];
01880     }
01881 
01882   /* starting point */
01883   itr.x = (int)(ceil( (double) (itr.vx[0]) ) - 1);
01884   itr.y = (int)(ceil( (double) (itr.vy[0]) ));
01885   itr.ys = itr.ye = -BIG_NUMBER;
01886 
01887   /* advance to the first point */
01888   ri_inc(itr);
01889 }
01890 
01891 /*----------------------------------------------------------------------------*/
01892 double V2::rect_nfa(struct rect * rec, Image<float>& angles, double logNT)
01893 {
01894   rect_iter * i;
01895   int pts = 0;
01896   int alg = 0;
01897   double nfa_val;
01898 
01899   for(i=ri_ini(rec); !ri_end(i); ri_inc(i))
01900     if( i->x>=0 && i->y>=0 && i->x<angles.getWidth() && i->y<angles.getHeight() )
01901     {
01902       if(itsLSDVerbose) LINFO("| %d %d ",i->x,i->y);
01903       ++pts;
01904       if( isaligned(Point2D<int>(i->x,i->y),angles,rec->theta,rec->prec) )
01905         ++alg;
01906     }
01907   ri_del(i);
01908 
01909   nfa_val = nfa(pts,alg,rec->p,logNT);
01910   if(itsLSDVerbose) LINFO("\npts %d alg %d p %g nfa %g\n",
01911                       pts,alg,rec->p,nfa_val);
01912 
01913   return nfa_val;
01914 }
01915 
01916 
01917 /*----------------------------------------------------------------------------*/
01918 /*---------------------------------- REGIONS ---------------------------------*/
01919 /*----------------------------------------------------------------------------*/
01920 
01921 /*----------------------------------------------------------------------------*/
01922 float V2::get_theta( struct point * reg, int reg_size, float x, float y,
01923                         Image<float>& modgrad, float reg_angle, float prec,
01924                         float * elongation )
01925 {
01926   int i;
01927   float Ixx = 0.0;
01928   float Iyy = 0.0;
01929   float Ixy = 0.0;
01930   float lambda1,lambda2,tmp;
01931   float theta;
01932   float weight,sum;
01933 
01934   if(reg_size <= 1) LFATAL("get_theta: region size <= 1.");
01935 
01936 
01937   /*----------- theta ---------------------------------------------------*/
01938   /*
01939       Region inertia matrix A:
01940          Ixx Ixy
01941          Ixy Iyy
01942       where
01943         Ixx = \sum_i y_i^2
01944         Iyy = \sum_i x_i^2
01945         Ixy = -\sum_i x_i y_i
01946 
01947       lambda1 and lambda2 are the eigenvalues, with lambda1 >= lambda2.
01948       They are found by solving the characteristic polynomial
01949       det(\lambda I - A) = 0.
01950 
01951       To get the line segment direction we want to get the eigenvector of
01952       the smaller eigenvalue. We have to solve a,b in:
01953         a.Ixx + b.Ixy = a.lambda2
01954         a.Ixy + b.Iyy = b.lambda2
01955       We want the angle theta = atan(b/a). I can be computed with
01956       any of the two equations:
01957         theta = atan( (lambda2-Ixx) / Ixy )
01958       or
01959         theta = atan( Ixy / (lambda2-Iyy) )
01960 
01961       When |Ixx| > |Iyy| we use the first, otherwise the second
01962       (just to get better numeric precision).
01963    */
01964   sum = 0.0;
01965   for(i=0; i<reg_size; i++)
01966     {
01967       weight = modgrad[ reg[i].x + reg[i].y * modgrad.getWidth() ];
01968       Ixx += ((float)reg[i].y - y) * ((float)reg[i].y - y) * weight;
01969       Iyy += ((float)reg[i].x - x) * ((float)reg[i].x - x) * weight;
01970       Ixy -= ((float)reg[i].x - x) * ((float)reg[i].y - y) * weight;
01971       sum += weight;
01972     }
01973   if( sum <= 0.0 ) LFATAL("get_theta: weights sum less or equal to zero.");
01974   Ixx /= sum;
01975   Iyy /= sum;
01976   Ixy /= sum;
01977   lambda1 = ( Ixx + Iyy + (float) sqrt( (double) (Ixx - Iyy) * (Ixx - Iyy)
01978                                         + 4.0 * Ixy * Ixy ) ) / 2.0;
01979   lambda2 = ( Ixx + Iyy - (float) sqrt( (double) (Ixx - Iyy) * (Ixx - Iyy)
01980                                         + 4.0 * Ixy * Ixy ) ) / 2.0;
01981   if( fabs(lambda1) < fabs(lambda2) )
01982     {
01983       fprintf(stderr,"Ixx %g Iyy %g Ixy %g lamb1 %g lamb2 %g - lamb1 < lamb2\n",
01984                       Ixx,Iyy,Ixy,lambda1,lambda2);
01985       tmp = lambda1;
01986       lambda1 = lambda2;
01987       lambda2 = tmp;
01988     }
01989   if(itsLSDVerbose) LINFO("Ixx %g Iyy %g Ixy %g lamb1 %g lamb2 %g\n",
01990                       Ixx,Iyy,Ixy,lambda1,lambda2);
01991 
01992   *elongation = lambda1/lambda2;
01993 
01994   if( fabs(Ixx) > fabs(Iyy) )
01995     theta = (float) atan2( (double) lambda2 - Ixx, (double) Ixy );
01996   else
01997     theta = (float) atan2( (double) Ixy, (double) lambda2 - Iyy );
01998 
01999   /* the previous procedure don't cares orientations,
02000      so it could be wrong by 180 degrees.
02001      here is corrected if necessary */
02002   if( angle_diff(theta,reg_angle) > prec ) theta += M_PI;
02003 
02004   return theta;
02005 }
02006 
02007 /*----------------------------------------------------------------------------*/
02008 float V2::region2rect( struct point * reg, int reg_size,
02009                           Image<float>& modgrad, float reg_angle,
02010                           float prec, double p, struct rect * rec,
02011                           float* sum_l, float* sum_w, int sum_offset, int sum_res)
02012 {
02013   float x,y,dx,dy,l,w,lf,lb,wl,wr,theta,weight,sum,sum_th,s,elongation;
02014   int i,n;
02015   int l_min,l_max,w_min,w_max;
02016 
02017   /* center */
02018   x = y = sum = 0.0;
02019   for(i=0; i<reg_size; i++)
02020     {
02021       weight = modgrad[ reg[i].x + reg[i].y * modgrad.getWidth() ];
02022       x += (float) reg[i].x * weight;
02023       y += (float) reg[i].y * weight;
02024       sum += weight;
02025     }
02026   if( sum <= 0.0 ) LFATAL("region2rect: weights sum equal to zero.");
02027   x /= sum;
02028   y /= sum;
02029   if(itsLSDVerbose) LINFO("center x %g y %g\n",x,y);
02030 
02031   /* theta */
02032   theta = get_theta(reg,reg_size,x,y,modgrad,reg_angle,prec,&elongation);
02033   if(itsLSDVerbose) LINFO("theta %g\n",theta);
02034 
02035   /* length and width */
02036   lf = lb = wl = wr = 0.5;
02037   l_min = l_max = w_min = w_max = 0;
02038   dx = (float) cos( (double) theta );
02039   dy = (float) sin( (double) theta );
02040   for(i=0; i<reg_size; i++)
02041     {
02042       l =  ((float)reg[i].x - x) * dx + ((float)reg[i].y - y) * dy;
02043       w = -((float)reg[i].x - x) * dy + ((float)reg[i].y - y) * dx;
02044       weight = modgrad[ reg[i].x + reg[i].y * modgrad.getWidth() ];
02045 
02046       n = (int) MY_ROUND( l * (float) sum_res );
02047       if(n<l_min) l_min = n;
02048       if(n>l_max) l_max = n;
02049       sum_l[sum_offset + n] += weight;
02050 
02051       n = (int) MY_ROUND( w * (float) sum_res );
02052       if(n<w_min) w_min = n;
02053       if(n>w_max) w_max = n;
02054       sum_w[sum_offset + n] += weight;
02055     }
02056 
02057   sum_th = 0.01 * sum; /* weight threshold for selecting region */
02058   for(s=0.0,i=l_min; s<sum_th && i<=l_max; i++) s += sum_l[sum_offset + i];
02059   lb = ( (float) (i-1) - 0.5 ) / (float) sum_res;
02060   for(s=0.0,i=l_max; s<sum_th && i>=l_min; i--) s += sum_l[sum_offset + i];
02061   lf = ( (float) (i+1) + 0.5 ) / (float) sum_res;
02062 
02063   sum_th = 0.01 * sum; /* weight threshold for selecting region */
02064   for(s=0.0,i=w_min; s<sum_th && i<=w_max; i++) s += sum_w[sum_offset + i];
02065   wr = ( (float) (i-1) - 0.5 ) / (float) sum_res;
02066   for(s=0.0,i=w_max; s<sum_th && i>=w_min; i--) s += sum_w[sum_offset + i];
02067   wl = ( (float) (i+1) + 0.5 ) / (float) sum_res;
02068 
02069   if(itsLSDVerbose) LINFO("lb %g lf %g wr %g wl %g\n",lb,lf,wr,wl);
02070 
02071   /* free vector */
02072   for(i=l_min; i<=l_max; i++) sum_l[sum_offset + i] = 0.0;
02073   for(i=w_min; i<=w_max; i++) sum_w[sum_offset + i] = 0.0;
02074 
02075   rec->x1 = x + lb * dx;
02076   rec->y1 = y + lb * dy;
02077   rec->x2 = x + lf * dx;
02078   rec->y2 = y + lf * dy;
02079   rec->width = wl - wr;
02080   rec->x = x;
02081   rec->y = y;
02082   rec->theta = theta;
02083   rec->dx = dx;
02084   rec->dy = dy;
02085   rec->prec = prec;
02086   rec->p = p;
02087   rec->sum = sum;
02088 
02089   if( rec->width < 1.0 ) rec->width = 1.0;
02090 
02091   return elongation;
02092 }
02093 
02094 /*----------------------------------------------------------------------------*/
02095 void V2::region_grow(Point2D<int> loc, Image<float>& angles, struct point * reg,
02096                          int * reg_size, float * reg_angle, Image<byte>& used,
02097                          float prec, int radius,
02098                          Image<float> modgrad, double p, int min_reg_size )
02099 {
02100   float sumdx,sumdy;
02101   int xx,yy,i;
02102 
02103   /* first point of the region */
02104   *reg_size = 1;
02105   reg[0].x = loc.i;
02106   reg[0].y = loc.j;
02107   *reg_angle = angles.getVal(loc);
02108   sumdx = (float) cos( (double) (*reg_angle) );
02109   sumdy = (float) sin( (double) (*reg_angle) );
02110   used.setVal(loc, USED);
02111 
02112   /* try neighbors as new region points */
02113   //LINFO("Grow point %ix%i", loc.i, loc.j);
02114   //Image<PixRGB<byte> > tmp = modgrad;
02115 
02116   for(i=0; i<*reg_size; i++)
02117   {
02118     for(xx=reg[i].x-radius; xx<=reg[i].x+radius; xx++)
02119       for(yy=reg[i].y-radius; yy<=reg[i].y+radius; yy++)
02120       {
02121         if( xx>=0 && yy>=0 && xx<used.getWidth() && yy<used.getHeight() &&
02122             used[xx+yy*used.getWidth()] != USED)
02123         {
02124           //LINFO("Aligned %f %f = %i", *reg_angle, prec,
02125           //    isaligned(Point2D<int>(xx,yy),angles,*reg_angle,prec) );
02126           if ( isaligned(Point2D<int>(xx,yy),angles,*reg_angle,prec) )
02127           {
02128             /* add point */
02129 
02130             //tmp.setVal(xx,yy, PixRGB<byte>(255, 0,0));
02131             //SHOWIMG(tmp);
02132 
02133             used[xx+yy*used.getWidth()] = USED;
02134             reg[*reg_size].x = xx;
02135             reg[*reg_size].y = yy;
02136             ++(*reg_size);
02137 
02138             /* update reg_angle */
02139             sumdx += (float) cos( (double) angles[xx+yy*angles.getWidth()] );
02140             sumdy += (float) sin( (double) angles[xx+yy*angles.getWidth()] );
02141             *reg_angle = (float) atan2( (double) sumdy, (double) sumdx );
02142           }
02143         }
02144       }
02145   }
02146   //if (*reg_size > 5)
02147   //  SHOWIMG(tmp);
02148 
02149   if(itsLSDVerbose) /* print region points */
02150     {
02151       LINFO("region found: %d points\n",*reg_size);
02152       for(i=0; i<*reg_size; i++) fprintf(stderr,"| %d %d ",reg[i].x,reg[i].y);
02153       fprintf(stderr,"\n");
02154     }
02155 }
02156 
02157 /*----------------------------------------------------------------------------*/
02158 double V2::rect_improve( struct rect * rec, Image<float>& angles,
02159                             double logNT, double eps )
02160 {
02161   struct rect r;
02162   double nfa_val,nfa_new;
02163   float delta = 0.5;
02164   float delta_2 = delta / 2.0;
02165   int n;
02166 
02167   nfa_val = rect_nfa(rec,angles,logNT);
02168 
02169   if( nfa_val > eps ) return nfa_val;
02170 
02171   rect_copy(rec,&r);
02172   for(n=0; n<5; n++)
02173     {
02174       r.p /= 2.0;
02175       r.prec = M_PI * r.p;
02176       nfa_new = rect_nfa(&r,angles,logNT);
02177       if( nfa_new > nfa_val )
02178         {
02179           nfa_val = nfa_new;
02180           rect_copy(&r,rec);
02181         }
02182     }
02183 
02184   if( nfa_val > eps ) return nfa_val;
02185 
02186   rect_copy(rec,&r);
02187   for(n=0; n<5; n++)
02188     {
02189       if( (r.width - delta) >= 0.5 )
02190         {
02191           r.width -= delta;
02192           nfa_new = rect_nfa(&r,angles,logNT);
02193           if( nfa_new > nfa_val )
02194             {
02195               rect_copy(&r,rec);
02196               nfa_val = nfa_new;
02197             }
02198         }
02199     }
02200 
02201   if( nfa_val > eps ) return nfa_val;
02202 
02203   rect_copy(rec,&r);
02204   for(n=0; n<5; n++)
02205     {
02206       if( (r.width - delta) >= 0.5 )
02207         {
02208           r.x1 += -r.dy * delta_2;
02209           r.y1 +=  r.dx * delta_2;
02210           r.x2 += -r.dy * delta_2;
02211           r.y2 +=  r.dx * delta_2;
02212           r.width -= delta;
02213           nfa_new = rect_nfa(&r,angles,logNT);
02214           if( nfa_new > nfa_val )
02215             {
02216               rect_copy(&r,rec);
02217               nfa_val = nfa_new;
02218             }
02219         }
02220     }
02221 
02222   if( nfa_val > eps ) return nfa_val;
02223 
02224   rect_copy(rec,&r);
02225   for(n=0; n<5; n++)
02226     {
02227       if( (r.width - delta) >= 0.5 )
02228         {
02229           r.x1 -= -r.dy * delta_2;
02230           r.y1 -=  r.dx * delta_2;
02231           r.x2 -= -r.dy * delta_2;
02232           r.y2 -=  r.dx * delta_2;
02233           r.width -= delta;
02234           nfa_new = rect_nfa(&r,angles,logNT);
02235           if( nfa_new > nfa_val )
02236             {
02237               rect_copy(&r,rec);
02238               nfa_val = nfa_new;
02239             }
02240         }
02241     }
02242 
02243   if( nfa_val > eps ) return nfa_val;
02244 
02245   rect_copy(rec,&r);
02246   for(n=0; n<5; n++)
02247     {
02248       r.p /= 2.0;
02249       r.prec = M_PI * r.p;
02250       nfa_new = rect_nfa(&r,angles,logNT);
02251       if( nfa_new > nfa_val )
02252         {
02253           nfa_val = nfa_new;
02254           rect_copy(&r,rec);
02255         }
02256     }
02257 
02258   return nfa_val;
02259 }
02260 
02261 
02262 /*----------------------------------------------------------------------------*/
02263 /*-------------------------- LINE SEGMENT DETECTION --------------------------*/
02264 /*----------------------------------------------------------------------------*/
02265 
02266 /*----------------------------------------------------------------------------*/
02267 std::vector<V2::LineSegment> V2::lineSegmentDetection(Image<float>& img, float q, float d, double eps,
02268                                   int n_bins, int max_grad, float scale, float sigma_scale )
02269 {
02270 
02271   float rho = q / (float) sin( M_PI / (double) d );   /* gradient threshold */
02272   std::vector<LineSegment> lines;
02273 
02274   /* scale (if necesary) and angles computation */
02275   Image<float> in = img;
02276   //if( scale != 1.0 )
02277   //  in = gaussian_sampler( img, scale, sigma_scale );
02278 
02279   //struct coorlist * list_p;
02280   std::vector<Point2D<int> > list_p;
02281   void * mem_p;
02282   Image<float> modgrad;
02283   if (itsLSDVerbose) LINFO("Get Angles");
02284   Image<float> angles = ll_angle(in,rho,list_p,&mem_p,modgrad,n_bins,max_grad);
02285 
02286 
02287   int xsize = in.getWidth();
02288   int ysize = in.getHeight();
02289 
02290   double logNT = 5.0 * ( log10( (double) xsize ) + log10( (double) ysize ) ) / 2.0;
02291   double p = 1.0 / (double) d;
02292   int min_reg_size = 5; //(int)(-logNT/log10(p)); /* minimal number of point that can
02293                           //                      give a meaningful event */
02294 
02295   Image<byte> used(xsize, ysize, ZEROS);
02296   struct point * reg = (struct point *) calloc(xsize * ysize, sizeof(struct point));
02297 
02298   int sum_res = 1;
02299   int sum_offset =(int)( sum_res * ceil( sqrt( (double) xsize * xsize + (double) ysize * ysize) ) + 2);
02300   float* sum_l = (float *) calloc(2*sum_offset,sizeof(float));
02301   float* sum_w = (float *) calloc(2*sum_offset,sizeof(float));
02302   if( !reg || !sum_l || !sum_w ) LFATAL("Not enough memory!\n");
02303   for(int i=0;i<2*sum_offset;i++) sum_l[i] = sum_w[i] = 0;
02304 
02305   /* just start at point x,y option */
02306   //if( x && y && *x > 0 && *y > 0 && *x < (xsize-1) && *y < (ysize-1) )
02307   //  {
02308   //    if(itsLSDVerbose) fprintf(stderr,"starting only at point %d,%d.\n",*x,*y);
02309   //    list_p = (struct coorlist *) mem_p;
02310   //    list_p->x = *x;
02311   //    list_p->y = *y;
02312   //    list_p->next = NULL;
02313   //  }
02314 
02315   if (itsLSDVerbose) LINFO("Search for line segments");
02316   /* search for line segments */
02317   int segnum = 0;
02318   for(uint pIdx = 0; pIdx < list_p.size(); pIdx++)
02319     if( ( used[ list_p[pIdx].i + list_p[pIdx].j * used.getWidth() ] == NOTUSED &&
02320           angles[ list_p[pIdx].i + list_p[pIdx].j * angles.getWidth() ] != NOTDEF)  )
02321       {
02322           if (itsLSDVerbose) LINFO("try to find a line segment starting on %d,%d.\n",
02323                   list_p[pIdx].i,list_p[pIdx].j);
02324 
02325           /* find the region of connected point and ~equal angle */
02326           int reg_size;
02327           float reg_angle;
02328           float prec = M_PI / d;
02329           int radius = 1;
02330           region_grow( list_p[pIdx], angles, reg, &reg_size,
02331               &reg_angle, used, prec, radius,
02332               modgrad, p, min_reg_size );
02333 
02334         /* just process regions with a minimum number of points */
02335         if( reg_size < min_reg_size )
02336           {
02337            // LINFO("Region too small %i %i", reg_size, min_reg_size);
02338             if(itsLSDVerbose) LINFO("region too small, discarded.\n");
02339             for(int i=0; i<reg_size; i++)
02340               used[reg[i].x+reg[i].y*used.getWidth()] = NOTINI;
02341             continue;
02342           }
02343 
02344         if(itsLSDVerbose) LINFO("rectangular approximation of region.\n");
02345         struct rect rec;
02346         region2rect(reg,reg_size,modgrad,reg_angle,prec,p,&rec, sum_l, sum_w, sum_offset, sum_res);
02347 
02348         if(itsLSDVerbose) LINFO("improve rectangular approximation.\n");
02349         double nfa_val = rect_improve(&rec,angles,logNT,eps);
02350 
02351         LINFO("nfa_val %f", nfa_val);
02352         if( nfa_val > eps )
02353         {
02354           if(itsLSDVerbose) LINFO("line segment found! num %d nfa %g\n",
02355               segnum,nfa_val);
02356 
02357           /*
02358              0.5 must be added to compensate that the gradient was
02359              computed using a 2x2 window, so the computed gradient
02360              is valid at a point with offset (0.5,0.5). The coordinates
02361              origin is at the center of pixel 0,0.
02362              */
02363           rec.x1 += 0.5; rec.y1 += 0.5;
02364           rec.x2 += 0.5; rec.y2 += 0.5;
02365 
02366           if( scale != 1.0 )
02367           {
02368             rec.x1 /= scale;
02369             rec.y1 /= scale;
02370             rec.x2 /= scale;
02371             rec.y2 /= scale;
02372             rec.width /= scale;
02373           }
02374 
02375           LineSegment ls;
02376           ls.p1.i = rec.x1;
02377           ls.p1.j = rec.y1;
02378           ls.p2.i = rec.x2;
02379           ls.p2.j = rec.y2;
02380           ls.width = rec.width;
02381           ls.length = sqrt( squareOf(rec.x1 - rec.x2) + squareOf(rec.y1 - rec.y2));
02382           ls.center.i = rec.x;
02383           ls.center.j = rec.y;
02384           ls.ori = atan2(rec.y1-rec.y2,rec.x2-rec.x1);
02385           ls.strength = 1;
02386 
02387           //Find the color on etiher size of the line
02388           //float len = 7;
02389           //int x1 = int(cos(ls.ori-(M_PI/2))*len/2);
02390           //int y1 = int(sin(ls.ori-(M_PI/2))*len/2);
02391 
02392           //Point2D<int> p1((int)ls.center.i-x1, (int)ls.center.j+y1);
02393           //Point2D<int> p2((int)ls.center.i+x1, (int)ls.center.j-y1);
02394           //if (img.coordsOk(p1))
02395           //{
02396           //  ls.side1Color.clear();
02397           //  ls.side1Color.push_back(itsLGNInput[0].getVal(p1));
02398           //  ls.side1Color.push_back(itsLGNInput[1].getVal(p1));
02399           //  ls.side1Color.push_back(itsLGNInput[2].getVal(p1));
02400           //}
02401 
02402           //if (img.coordsOk(p2))
02403           //{
02404           //  ls.side2Color.clear();
02405           //  ls.side2Color.push_back(itsLGNInput[0].getVal(p2));
02406           //  ls.side2Color.push_back(itsLGNInput[1].getVal(p2));
02407           //  ls.side2Color.push_back(itsLGNInput[2].getVal(p2));
02408           //}
02409 
02410           lines.push_back(ls);
02411 
02412 
02413           //Show regions
02414 
02415           //fprintf(arout,"region %d:",segnum);
02416           //for(i=0; i<reg_size; i++)
02417           //  fprintf(arout," %d,%d;",reg[i].x,reg[i].y);
02418           //fprintf(arout,"\n");
02419 
02420           ++segnum;
02421         }
02422         else
02423           for(int i=0; i<reg_size; i++)
02424             used[reg[i].x+reg[i].y*used.getWidth()] = NOTINI;
02425       }
02426 
02427 
02428 //  getchar();
02429 
02430   return lines;
02431 }
02432 
02433 std::vector<V2::LineSegment> V2::lineSegmentDetection(const TensorField& tensorField,
02434     float q, float d, double eps,
02435     int n_bins, int max_grad )
02436 {
02437   //float rho = q / (float) sin( M_PI / (double) d );   /* gradient threshold */
02438   std::vector<LineSegment> lines;
02439 
02440   //struct coorlist * list_p;
02441   std::vector<Point2D<int> > list_p;
02442   Image<float> modgrad;
02443   if (itsLSDVerbose) LINFO("Get Angles");
02444   Image<float> angles = ll_angle(tensorField,max_grad*0.10,list_p,modgrad,n_bins,max_grad);
02445 
02446   int xsize = tensorField.t1.getWidth();
02447   int ysize = tensorField.t1.getHeight();
02448 
02449   double logNT = 5.0 * ( log10( (double) xsize ) + log10( (double) ysize ) ) / 2.0;
02450   double p = 1.0 / (double) d;
02451   int min_reg_size = 5; //(int)(-logNT/log10(p)); /* minimal number of point that can
02452                          //                       give a meaningful event */
02453 
02454   Image<byte> used(xsize, ysize, ZEROS);
02455   struct point * reg = (struct point *) calloc(xsize * ysize, sizeof(struct point));
02456 
02457   int sum_res = 1;
02458   int sum_offset =(int)( sum_res * ceil( sqrt( (double) xsize * xsize + (double) ysize * ysize) ) + 2);
02459   float* sum_l = (float *) calloc(2*sum_offset,sizeof(float));
02460   float* sum_w = (float *) calloc(2*sum_offset,sizeof(float));
02461   if( !reg || !sum_l || !sum_w ) LFATAL("Not enough memory!\n");
02462   for(int i=0;i<2*sum_offset;i++) sum_l[i] = sum_w[i] = 0;
02463 
02464   if (itsLSDVerbose) LINFO("Search for line segments");
02465   /* search for line segments */
02466   int segnum = 0;
02467   for(uint pIdx = 0; pIdx < list_p.size(); pIdx++)
02468     if( ( used[ list_p[pIdx].i + list_p[pIdx].j * used.getWidth() ] == NOTUSED &&
02469           angles[ list_p[pIdx].i + list_p[pIdx].j * angles.getWidth() ] != NOTDEF)  )
02470       {
02471           if (itsLSDVerbose) LINFO("try to find a line segment starting on %d,%d.\n",
02472                   list_p[pIdx].i,list_p[pIdx].j);
02473 
02474           /* find the region of connected point and ~equal angle */
02475           int reg_size;
02476           float reg_angle;
02477           float prec = M_PI / d;
02478           int radius = 2;
02479           region_grow( list_p[pIdx], angles, reg, &reg_size,
02480               &reg_angle, used,
02481               prec, radius,
02482               modgrad, p, min_reg_size );
02483 
02484         /* just process regions with a minimum number of points */
02485         if( reg_size < min_reg_size )
02486           {
02487             if(itsLSDVerbose) LINFO("region too small, discarded.\n");
02488             for(int i=0; i<reg_size; i++)
02489               used[reg[i].x+reg[i].y*used.getWidth()] = NOTINI;
02490             continue;
02491           }
02492 
02493         if(itsLSDVerbose) LINFO("rectangular approximation of region.\n");
02494         struct rect rec;
02495         region2rect(reg,reg_size,modgrad,reg_angle,prec,p,&rec, sum_l, sum_w, sum_offset, sum_res);
02496 
02497         if(itsLSDVerbose) LINFO("improve rectangular approximation.\n");
02498         double nfa_val = rect_improve(&rec,angles,logNT,eps);
02499 
02500         if ( fabs(nfa_val) > eps ) 
02501         {
02502           if(itsLSDVerbose) LINFO("line segment found! num %d nfa %g\n",
02503               segnum,nfa_val);
02504 
02505           /*
02506              0.5 must be added to compensate that the gradient was
02507              computed using a 2x2 window, so the computed gradient
02508              is valid at a point with offset (0.5,0.5). The coordinates
02509              origin is at the center of pixel 0,0.
02510              */
02511           rec.x1 += 0.5; rec.y1 += 0.5;
02512           rec.x2 += 0.5; rec.y2 += 0.5;
02513 
02514           if (rec.x1 >= xsize) rec.x1 = xsize-1;
02515           if (rec.y1 >= ysize) rec.y1 = ysize-1;
02516 
02517           if (rec.x2 >= xsize) rec.x2 = xsize-1;
02518           if (rec.y2 >= ysize) rec.y2 = ysize-1;
02519 
02520           LineSegment ls;
02521           ls.p1.i = rec.x1;
02522           ls.p1.j = rec.y1;
02523           ls.p2.i = rec.x2;
02524           ls.p2.j = rec.y2;
02525           ls.width = rec.width;
02526           ls.length = sqrt( squareOf(rec.x1 - rec.x2) + squareOf(rec.y1 - rec.y2));
02527           ls.center.i = rec.x;
02528           ls.center.j = rec.y;
02529           ls.ori = atan2(rec.y1-rec.y2,rec.x2-rec.x1);
02530           ls.prob = rec.sum;
02531 
02532           if (ls.ori < 0) ls.ori += M_PI;
02533           if (ls.ori >= M_PI) ls.ori -= M_PI;
02534 
02535           ls.strength = 1;
02536 
02537           //Find the color on etiher size of the line
02538           //float len = 7;
02539           //int x1 = int(cos(ls.ori-(M_PI/2))*len/2);
02540           //int y1 = int(sin(ls.ori-(M_PI/2))*len/2);
02541 
02542           //Point2D<int> p1((int)ls.center.i-x1, (int)ls.center.j+y1);
02543           //Point2D<int> p2((int)ls.center.i+x1, (int)ls.center.j-y1);
02544           //if (img.coordsOk(p1))
02545           //{
02546           //  ls.side1Color.clear();
02547           //  ls.side1Color.push_back(itsLGNInput[0].getVal(p1));
02548           //  ls.side1Color.push_back(itsLGNInput[1].getVal(p1));
02549           //  ls.side1Color.push_back(itsLGNInput[2].getVal(p1));
02550           //}
02551 
02552           //if (img.coordsOk(p2))
02553           //{
02554           //  ls.side2Color.clear();
02555           //  ls.side2Color.push_back(itsLGNInput[0].getVal(p2));
02556           //  ls.side2Color.push_back(itsLGNInput[1].getVal(p2));
02557           //  ls.side2Color.push_back(itsLGNInput[2].getVal(p2));
02558           //}
02559 
02560           lines.push_back(ls);
02561 
02562 
02563           //Show regions
02564 
02565           //fprintf(arout,"region %d:",segnum);
02566           //for(i=0; i<reg_size; i++)
02567           //  fprintf(arout," %d,%d;",reg[i].x,reg[i].y);
02568           //fprintf(arout,"\n");
02569 
02570           ++segnum;
02571         }
02572         else
02573           for(int i=0; i<reg_size; i++)
02574             used[reg[i].x+reg[i].y*used.getWidth()] = NOTINI;
02575       }
02576 
02577 
02578 //  getchar();
02579 
02580   free(reg);
02581   free(sum_l);
02582   free(sum_w);
02583 
02584   return lines;
02585 }
02586 
02587 
02588 // ######################################################################
02589 /* So things look consistent in everyone's emacs... */
02590 /* Local Variables: */
02591 /* indent-tabs-mode: nil */
02592 /* End: */
02593 
02594 #endif
02595 
Generated on Sun May 8 08:05:32 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3