BeoSubCross.C

Go to the documentation of this file.
00001 /*!@file BeoSub/BeoSubCross.C find pipe                                 */
00002 // //////////////////////////////////////////////////////////////////// //
00003 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2001 by the //
00004 // University of Southern California (USC) and the iLab at USC.         //
00005 // See http://iLab.usc.edu for information about this project.          //
00006 // //////////////////////////////////////////////////////////////////// //
00007 // Major portions of the iLab Neuromorphic Vision Toolkit are protected //
00008 // under the U.S. patent ``Computation of Intrinsic Perceptual Saliency //
00009 // in Visual Environments, and Applications'' by Christof Koch and      //
00010 // Laurent Itti, California Institute of Technology, 2001 (patent       //
00011 // pending; application number 09/912,225 filed July 23, 2001; see      //
00012 // http://pair.uspto.gov/cgi-bin/final/home.pl for current status).     //
00013 // //////////////////////////////////////////////////////////////////// //
00014 // This file is part of the iLab Neuromorphic Vision C++ Toolkit.       //
00015 //                                                                      //
00016 // The iLab Neuromorphic Vision C++ Toolkit is free software; you can   //
00017 // redistribute it and/or modify it under the terms of the GNU General  //
00018 // Public License as published by the Free Software Foundation; either  //
00019 // version 2 of the License, or (at your option) any later version.     //
00020 //                                                                      //
00021 // The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope  //
00022 // that it will be useful, but WITHOUT ANY WARRANTY; without even the   //
00023 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR      //
00024 // PURPOSE.  See the GNU General Public License for more details.       //
00025 //                                                                      //
00026 // You should have received a copy of the GNU General Public License    //
00027 // along with the iLab Neuromorphic Vision C++ Toolkit; if not, write   //
00028 // to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,   //
00029 // Boston, MA 02111-1307 USA.                                           //
00030 // //////////////////////////////////////////////////////////////////// //
00031 //
00032 // Primary maintainer for this file: Michael Montalbo <montalbo@usc.edu>
00033 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/BeoSub/BeoSubCross.C $
00034 // $Id: BeoSubCross.C 14376 2011-01-11 02:44:34Z pez $
00035 
00036 #include "Image/OpenCVUtil.H"  // must be first to avoid conflicting defs of int64, uint64
00037 
00038 #include "GUI/XWinManaged.H"
00039 
00040 #include "Image/Pixels.H"
00041 #include "Raster/Raster.H"
00042 
00043 #include "Util/Timer.H"
00044 #include "Util/Types.H"
00045 #include "Util/log.H"
00046 
00047 #include "Image/ColorOps.H"
00048 #include "Image/CutPaste.H"
00049 #include "Image/MathOps.H"
00050 #include "Image/DrawOps.H"
00051 #include "Image/FilterOps.H"
00052 #include "Image/Transforms.H"
00053 
00054 #include "BeoSub/hysteresis.H"
00055 #include "VFAT/segmentImageTrackMC.H"
00056 #include "BeoSub/HoughTransform.H"
00057 #include "BeoSub/ColorTracker.H"
00058 #include "BeoSub/CannyEdge.H"
00059 #include "BeoSub/IsolateColor.H"
00060 #include "rutz/compat_cmath.h" // for isnan()
00061 
00062 #include "BeoSub/BeoSubCross.H"
00063 
00064 #include <cstdio>
00065 #include <cstdlib>
00066 #include <cstring>
00067 #include <iostream> //needed for segmentImageTrackMC!
00068 #include <math.h>
00069 #include <vector>
00070 #include <cmath>
00071 
00072 // ######################################################################
00073 BeoSubCross::BeoSubCross()
00074 {
00075   houghThreshold = 40;
00076   minThreshold = 10;
00077   maxThreshold = 50;
00078   sigma = 1.1;
00079   tlow = 0.3;
00080   thigh = 1.1;
00081   linescale = 80;
00082   avgCrossCenterX = 0;
00083   avgCrossCenterY = 0;
00084   avgCrossAngle = 0.0;
00085   stdDevCrossX = 0.0;
00086   stdDevCrossY = 0.0;
00087   stdDevCrossAngle = 0.0;
00088 
00089   stdDevAngleCount = 0;
00090   stdDevCenterCount = 0;
00091 
00092   color.resize(4,0.0F);
00093   std.resize(4,0.0F);
00094   norm.resize(4,0.0F);
00095   adapt.resize(4,0.0F);
00096   lowerBound.resize(4,0.0F);
00097   upperBound.resize(4,0.0F);
00098 
00099   // number of consecutive times that a line was found (going up to 8)
00100   foundCount = 0;
00101 
00102   itsSetupOrangeTracker = false;
00103 
00104   //  setupOrangeTracker();
00105 }
00106 
00107 // ######################################################################
00108 BeoSubCross::~BeoSubCross()
00109 { }
00110 
00111 // ######################################################################
00112 void BeoSubCross::setupOrangeTracker()
00113 {
00114   //  int width = 180;
00115   //int height = 120;
00116   int width = 360;
00117   int height = 240;
00118 
00119   segmenter = new segmentImageTrackMC<float,unsigned int, 4> (width*height);
00120 
00121   int wi = width/4;
00122   int hi = height/4;
00123 
00124   segmenter->SITsetFrame(&wi,&hi);
00125 
00126   segmenter->SITsetCircleColor(0,255,0);
00127   segmenter->SITsetBoxColor(255,255,0,0,255,255);
00128   segmenter->SITsetUseSmoothing(false,10);
00129 
00130 
00131   segmenter->SITtoggleCandidateBandPass(false);
00132   segmenter->SITtoggleColorAdaptation(true);
00133 
00134   //  std::cout<<"BECORE OPEN FILE"<<std::endl;
00135   colorConf.openFile("colortrack.conf", true);
00136   //  std::cout<<"AFTER OPEN FILE"<<std::endl;
00137 
00138   PixRGB<float> P1(colorConf.getItemValueF("ORNG_R"),
00139                    colorConf.getItemValueF("ORNG_G"),
00140                    colorConf.getItemValueF("ORNG_B"));
00141 
00142   PixH2SV1<float> ORNG(P1);
00143   //  std::cout<<"BEFORE H1 THING"<<std::endl;
00144   color[0] = ORNG.H1(); color[1] = ORNG.H2(); color[2] = ORNG.S(); color[3] = ORNG.V();
00145 
00146   printf("h1: %f, h2: %f, sat: %f, value: %f", color[0], color[1], color[2], color[3]);
00147 
00148   //! +/- tollerance value on mean for track
00149   std[0] = colorConf.getItemValueF("ORNG_std0");
00150   std[1] = colorConf.getItemValueF("ORNG_std1");
00151   std[2] = colorConf.getItemValueF("ORNG_std2");
00152   std[3] = colorConf.getItemValueF("ORNG_std3");
00153 
00154   //! normalizer over color values (highest value possible)
00155   norm[0] = colorConf.getItemValueF("ORNG_norm0");
00156   norm[1] = colorConf.getItemValueF("ORNG_norm1");
00157   norm[2] = colorConf.getItemValueF("ORNG_norm2");
00158   norm[3] = colorConf.getItemValueF("ORNG_norm3");
00159 
00160   //! how many standard deviations out to adapt, higher means less bias
00161   adapt[0] = colorConf.getItemValueF("ORNG_adapt0");
00162   adapt[1] = colorConf.getItemValueF("ORNG_adapt1");
00163   adapt[2] = colorConf.getItemValueF("ORNG_adapt2");
00164   adapt[3] = colorConf.getItemValueF("ORNG_adapt3");
00165 
00166   //! highest value for color adaptation possible (hard boundry)
00167   upperBound[0] = color[0] + colorConf.getItemValueF("ORNG_up0");
00168   upperBound[1] = color[1] + colorConf.getItemValueF("ORNG_up1");
00169   upperBound[2] = color[2] + colorConf.getItemValueF("ORNG_up2");
00170   upperBound[3] = color[3] + colorConf.getItemValueF("ORNG_up3");
00171 
00172   //! lowest value for color adaptation possible (hard boundry)
00173   lowerBound[0] = color[0] - colorConf.getItemValueF("ORNG_lb0");
00174   lowerBound[1] = color[1] - colorConf.getItemValueF("ORNG_lb1");
00175   lowerBound[2] = color[2] - colorConf.getItemValueF("ORNG_lb2");
00176   lowerBound[3] = color[3] - colorConf.getItemValueF("ORNG_lb3");
00177 
00178   //  std::cout<<"AFTER ARRAY STUFF"<<std::endl;
00179   segmenter->SITsetTrackColor(&color,&std,&norm,&adapt,&upperBound,&lowerBound);
00180   //  std::cout<<"AFTER SITsetTrackColor"<<std::endl;
00181 }
00182 // ######################################################################
00183 int BeoSubCross::getOrangeMass(Image< PixRGB<byte> > image,
00184                                Image< PixRGB<byte> > &display)
00185 {
00186   Image<PixRGB<byte> > Aux;
00187   Aux.resize(100,450,true);
00188 
00189   Image< PixH2SV2<float> > H2SVimage(image);
00190 
00191   segmenter->SITtrackImageAny(H2SVimage,&display,&Aux,true);
00192 
00193   int mass;
00194   segmenter->SITgetBlobWeight(mass);
00195   return mass;
00196 }
00197 
00198 // ######################################################################
00199 
00200 
00201 std::vector<LineSegment2D> BeoSubCross::pruneLines (std::vector<LineSegment2D> lines)
00202 {
00203   uint nLines = lines.size();
00204   // get the mean
00205   float sumLength = 0.0;  float meanLength = 0.0;
00206   for (uint i = 0; i < nLines; i++) sumLength += lines[i].length();
00207   meanLength = sumLength / nLines;
00208 
00209   // get the standard deviation
00210   float sumsqr = 0.0;
00211   for (uint i = 0; i < nLines; i++)
00212     sumsqr += pow((float)(lines[i].length()) - meanLength, 2.0);
00213   float stdevLength = sqrt(sumsqr / (nLines-1));
00214 
00215   // kick out lines that aren't within the stddev of the mean length
00216   LDEBUG ("Mean: %f   StdDev: %f", meanLength, stdevLength);
00217   std::vector<LineSegment2D> nlines;
00218   for(uint i = 0; i < nLines; i++)
00219     {
00220       if (lines[i].length() > (meanLength - stdevLength) &&
00221           lines[i].length() < (meanLength + stdevLength)   )
00222         nlines.push_back(lines[i]);
00223     }
00224 
00225   if (nlines.size() == 0)
00226     { LDEBUG("*** NO LINE LENGTH WITHIN STD DEV ***"); return lines; }
00227 
00228   std::vector<LineSegment2D> flines = nlines;
00229   LDEBUG("\n\n\n\nSum the Average...");
00230   double sumAngle = 0;
00231   std::vector<LineSegment2D>::iterator itr  = flines.begin();
00232   while(itr < flines.end())
00233     {
00234       float angle = (*itr).angle();
00235       LDEBUG("Line Angle[%4d,%4d][%4d,%4d]: %f",
00236             (*itr).point1().i, (*itr).point1().j,
00237             (*itr).point2().i, (*itr).point2().j,
00238             angle * 180/M_PI);
00239 
00240       // eliminate lines that are close to vertical
00241       if(!isnan(angle)) { sumAngle += angle; itr++; }
00242       else
00243         {
00244           sumAngle += 90.0;
00245           //          itr = flines.erase(itr);
00246           LDEBUG("Drop a line");
00247         }
00248     }
00249   if (flines.size() == 0) return lines;
00250 
00251   // also drop off angles that do not fall
00252   // within a standard deviation of the average angle
00253   float meanAngle = sumAngle / flines.size();
00254   float stdAngleSum = 0.0;
00255   float stdAngleSqr = 0.0;
00256   for(uint i = 0; i < flines.size(); i++)
00257     {
00258       float angle = flines[i].angle();
00259       stdAngleSum = angle - meanAngle;
00260       stdAngleSqr += (stdAngleSum * stdAngleSum);
00261     }
00262   float stdevAngle = stdAngleSqr / flines.size();
00263   double stdtemp = sqrt((double)stdevAngle);
00264   stdevAngle = (float)stdtemp;
00265 
00266   // throw out angles that do not fit within stdev of the angle
00267   sumAngle = 0.0;  itr  = flines.begin();
00268   while(itr < flines.end())
00269     {
00270       float angle = (*itr).angle();
00271       if(angle >= (meanAngle - stdevAngle) &&
00272          angle <= (meanAngle + stdevAngle))
00273         { sumAngle += angle; itr++; }
00274       else itr = flines.erase(itr);
00275     }
00276 
00277   return flines;
00278 }
00279 
00280 // ######################################################################
00281 
00282 std::vector<LineSegment2D> BeoSubCross::getHoughLines
00283 (Image< PixRGB <byte> > &cameraImage,
00284  Image< PixRGB <byte> > &outputImage)
00285 {
00286   std::vector <LineSegment2D> lines;
00287 
00288 #ifndef HAVE_OPENCV
00289   LFATAL("OpenCV must be installed in order to use this function");
00290 #else
00291 
00292   IplImage *edge = cvCreateImage( cvGetSize(img2ipl(cameraImage)), 8, 1 );
00293   cvCanny( img2ipl(luminance(cameraImage)), edge, 100, 150, 3 );//150,200,3
00294 
00295   //  inplacePaste(dispImage, toRGB(edgeImage), Point2D<int>(0,h));
00296 
00297   //  tim.reset();
00298 //   rutz::shared_ptr<CvMemStorage*> storage;
00299 //   *storage = cvCreateMemStorage(0);
00300 
00301   CvMemStorage* storage = cvCreateMemStorage(0);
00302 
00303   //outputImage.clear();
00304 
00305   outputImage = ipl2gray(edge);
00306 
00307   CvSeq* cvlines = cvHoughLines2(edge, storage, CV_HOUGH_STANDARD,
00308                                  1, CV_PI/180, 40 , 0, 0);
00309   //  t = tim.get();
00310   //  LDEBUG("houghTransform takes: %f ms", (float)t/1000.0);
00311 
00312     for(int i = 0; i < MIN(cvlines->total,10); i++ )
00313     {
00314       float* line = (float*)cvGetSeqElem(cvlines,i);
00315       float rho = line[0];
00316       float theta = line[1];
00317       CvPoint pt1, pt2;
00318       double a = cos(theta), b = sin(theta);
00319       double x0 = a*rho, y0 = b*rho;
00320       pt1.x = cvRound(x0 + 1000*(-b));
00321       pt1.y = cvRound(y0 + 1000*(a));
00322       pt2.x = cvRound(x0 - 1000*(-b));
00323       pt2.y = cvRound(y0 - 1000*(a));
00324       lines.push_back(LineSegment2D(Point2D<int>(pt1.x,pt1.y),
00325                                     Point2D<int>(pt2.x,pt2.y)));
00326       drawLine(outputImage, Point2D<int>(pt1.x,pt1.y),
00327                Point2D<int>(pt2.x, pt2.y), PixRGB<byte>(255,0,0));
00328     }
00329 
00330      cvReleaseMemStorage(&storage);
00331      cvReleaseImage(&edge);
00332      //cvReleaseSeq(&cvlines);
00333 
00334     //    delete edge;
00335     //    delete cvlines;
00336 
00337 #endif // HAVE_OPENCV
00338 
00339     return lines;
00340 }
00341 
00342 // ######################################################################
00343 
00344 Point2D<int> BeoSubCross::getCrossCenter (const std::vector<LineSegment2D> lines,
00345                                      std::vector<LineSegment2D> &centerPointLines,
00346                                      uint& stalePointCount)
00347 {
00348 
00349   Point2D<int> avgCrossCenterPoint = Point2D<int>(avgCrossCenterX,avgCrossCenterY);
00350 
00351   uint nLines = lines.size();
00352   if(nLines == 0)
00353     {
00354       LDEBUG("*** NO LINES ***");
00355       stalePointCount++;
00356       return avgCrossCenterPoint;
00357     }
00358 
00359   std::vector<LineSegment2D> posAngleLines, negAngleLines;
00360 
00361   for(uint i = 0; i < nLines; i++)
00362     {
00363       if(lines[i].angle() >= 0)
00364         {
00365           posAngleLines.push_back(lines[i]);
00366         }
00367       else
00368         {
00369           negAngleLines.push_back(lines[i]);
00370         }
00371     }
00372 
00373   std::vector<LineSegment2D> fPosAngleLines = posAngleLines;//pruneLines(posAngleLines);
00374   std::vector<LineSegment2D> fNegAngleLines = negAngleLines;//pruneLines(negAngleLines);
00375 
00376   std::vector<LineSegment2D> flines;
00377 
00378   for(uint i = 0; i < fPosAngleLines.size(); i++)
00379   {
00380     flines.push_back(fPosAngleLines[i]);
00381   }
00382 
00383   for(uint i = 0; i < fNegAngleLines.size(); i++)
00384   {
00385     flines.push_back(fNegAngleLines[i]);
00386   }
00387 
00388 
00389   std::vector<std::vector<Point2D<int> > > intersectPts;
00390 
00391   //Go through all the remaining lines
00392   for(uint r = 0; r < flines.size(); r++)
00393     {
00394       for(uint s = 0; s < flines.size(); s++)
00395         {
00396           if(r != s)
00397             {
00398               double xIntersect, yIntersect = 0.0;
00399               //if two lines intersect
00400               if(flines[r].intersects(flines[s],xIntersect,yIntersect)
00401                  && (fabs(flines[r].angleBetween(flines[s])) >= 0.95 * M_PI/2)//convert to radians
00402                  && (fabs(flines[r].angleBetween(flines[s])) <= 1.05 * M_PI/2))//convert to radians
00403                 {
00404                   int ptIndex = -1;
00405 
00406                   centerPointLines.push_back(flines[r]);
00407                   centerPointLines.push_back(flines[s]);
00408 
00409 
00410                   //check to see if the point at which they intersect fits into a pre-existing bucket
00411                   for(uint c = 0; c < intersectPts.size(); c++)
00412                     {
00413                       if(xIntersect < intersectPts[c][0].i + 5 &&
00414                          xIntersect > intersectPts[c][0].i - 5 &&
00415                          yIntersect < intersectPts[c][0].j + 5 &&
00416                          yIntersect > intersectPts[c][0].j - 5 )
00417                         {
00418                           ptIndex = c;
00419                         }
00420 
00421                     }
00422 
00423                   //if the point fits into a pre-existing bucket, add it to the bucket
00424                   if(ptIndex > 0)
00425                     {
00426                       int x = (int)(xIntersect);
00427                       int y = (int)(yIntersect);
00428 
00429                       intersectPts[ptIndex].push_back(Point2D<int>(x,y));
00430                       //average the old bucket's value with the new point added
00431                       //so as to create a moving bucket
00432                        intersectPts[ptIndex][0].i += x;
00433                        intersectPts[ptIndex][0].i /= 2;
00434                        intersectPts[ptIndex][0].j += y;
00435                        intersectPts[ptIndex][0].j /= 2;
00436 
00437                     }
00438                   //otherwise, create a new bucket
00439                   else
00440                     {
00441                       int x = (int)(xIntersect);
00442                       int y = (int)(yIntersect);
00443 
00444                       std::vector<Point2D<int> > newIntPts;
00445                       newIntPts.push_back(Point2D<int>(x,y));
00446                       intersectPts.push_back(newIntPts);
00447                     }
00448                 }
00449             }
00450         }
00451     }
00452 
00453   if(intersectPts.size() == 0)
00454     {
00455       LDEBUG("*** NO INTERSECT POINTS FOUND ***");
00456       stalePointCount++;
00457       return avgCrossCenterPoint;
00458     }
00459 
00460   uint maxPts = intersectPts[0].size();
00461   uint maxIndex = 0;
00462 
00463   for(uint i = 0; i < intersectPts.size(); i++)
00464     {
00465       if(intersectPts[i].size() > maxPts)
00466         {
00467           maxPts = intersectPts[i].size();
00468           maxIndex = i;
00469         }
00470     }
00471 
00472   Point2D<int> finalPoint = intersectPts[maxIndex][0];
00473 
00474 
00475   // Smooth out the center points being displayed by averaging the position of the
00476   // last 30 center points.
00477 
00478   bool isWithinStdDev = false;
00479   // Check if center point is within std dev
00480   if(centerPointBuff.size() < 2
00481      || (abs(finalPoint.i - avgCrossCenterX) <= stdDevCrossX
00482          && abs(finalPoint.j - avgCrossCenterY) <= stdDevCrossY)
00483      )
00484     {
00485       stdDevCenterCount = 0;
00486       isWithinStdDev = true;
00487     }
00488   else
00489     {
00490       stdDevCenterCount++;
00491 
00492       LINFO("Current X: %d Y: %d",finalPoint.i, finalPoint.j);
00493       LINFO("AVG X: %d Y: %d",avgCrossCenterX, avgCrossCenterY);
00494       LINFO("STDDEV CROSS (X,Y):(%f,%f)",stdDevCrossX, stdDevCrossY);
00495 
00496     }
00497 
00498   stalePointCount = 0;
00499 
00500   uint centerBuffSize = centerPointBuff.size();
00501 
00502   if(stdDevCenterCount > 5)
00503     {
00504       isWithinStdDev = true;
00505       centerPointBuff.clear();
00506     }
00507 
00508   if(isWithinStdDev)
00509     {
00510       if(centerBuffSize >= 30)
00511         {
00512           centerPointBuff.pop_front();
00513         }
00514 
00515       centerPointBuff.push_back(finalPoint);
00516 
00517       centerBuffSize = centerPointBuff.size();
00518     }
00519 
00520   if(centerBuffSize > 0)
00521     {
00522       int sumX = 0, sumY = 0;
00523       std::list<Point2D<int> >::iterator it;
00524 
00525       for(it = centerPointBuff.begin(); it != centerPointBuff.end(); ++it)
00526         {
00527           sumX += (*it).i;
00528           sumY += (*it).j;
00529         }
00530 
00531       avgCrossCenterX = sumX / centerBuffSize;
00532       avgCrossCenterY = sumY / centerBuffSize;
00533 
00534       avgCrossCenterPoint = Point2D<int>(avgCrossCenterX,avgCrossCenterY);
00535 
00536       float sqrStdCenterX = 0.0;
00537       float sqrStdCenterY = 0.0;
00538 
00539 
00540       for(it = centerPointBuff.begin(); it != centerPointBuff.end(); ++it)
00541       {
00542         sqrStdCenterX += (((*it).i - avgCrossCenterX) * ((*it).i - avgCrossCenterX));
00543         sqrStdCenterY += (((*it).j - avgCrossCenterY) * ((*it).j - avgCrossCenterY));
00544       }
00545 
00546       float stdevCenterX = sqrStdCenterX / centerBuffSize;
00547       float stdevCenterY = sqrStdCenterY / centerBuffSize;
00548       double stdTempCenterX = sqrt((double)stdevCenterX);
00549       double stdTempCenterY = sqrt((double)stdevCenterY);
00550       stdDevCrossX = (float)stdTempCenterX;
00551       stdDevCrossY = (float)stdTempCenterY;
00552     }
00553   else
00554     {
00555       avgCrossCenterPoint = finalPoint;
00556     }
00557   //         stalePointCount++;
00558   return avgCrossCenterPoint;
00559 }
00560 
00561 
00562 // ######################################################################
00563 float BeoSubCross::getCrossDir
00564 (const std::vector<LineSegment2D> lines)
00565 {
00566   uint nLines = lines.size();
00567   if(nLines == 0) { LDEBUG("*** NO LINES ***"); return avgCrossAngle;}
00568 
00569   //separate lines into positive and negative angles
00570   std::vector<LineSegment2D> posAngleLines, negAngleLines;
00571 
00572   for(uint i = 0; i < nLines; i++)
00573     {
00574       if(lines[i].angle() >= 0)
00575         {
00576           posAngleLines.push_back(lines[i]);
00577         }
00578       else
00579         {
00580           negAngleLines.push_back(lines[i]);
00581         }
00582     }
00583 
00584   std::vector<LineSegment2D> fPosAngleLines = posAngleLines;//pruneLines(posAngleLines);
00585   std::vector<LineSegment2D> fNegAngleLines = negAngleLines;//pruneLines(negAngleLines);
00586 
00587   double avgPosAngle, avgNegAngle;
00588 
00589   // Find average of positive angles
00590   //  LINFO("\n\n\n\nSum the Average...");
00591   double sumPosAngle = 0;
00592   std::vector<LineSegment2D>::iterator itr  = fPosAngleLines.begin();
00593   while(itr < fPosAngleLines.end())
00594     {
00595       float angle = (*itr).angle();
00596       LDEBUG("Line Angle[%4d,%4d][%4d,%4d]: %f",
00597             (*itr).point1().i, (*itr).point1().j,
00598             (*itr).point2().i, (*itr).point2().j,
00599             angle * 180/M_PI);
00600 
00601       // eliminate lines that are close to vertical
00602       if(!isnan(angle)) { sumPosAngle += angle; itr++; }
00603       else
00604         { sumPosAngle += 90.0;
00605           //itr = fPosAngleLines.erase(itr);
00606           LDEBUG("Drop a line");
00607         }
00608     }
00609 
00610   if (fPosAngleLines.size() == 0)
00611     {
00612       return avgCrossAngle;
00613     }
00614   else
00615     {
00616       avgPosAngle = sumPosAngle / fPosAngleLines.size();
00617     }
00618 
00619   // Find average of negative angles
00620   double sumNegAngle = 0;
00621   itr  = fNegAngleLines.begin();
00622   while(itr < fNegAngleLines.end())
00623     {
00624       float angle = (*itr).angle();
00625       LDEBUG("Line Angle[%4d,%4d][%4d,%4d]: %f",
00626             (*itr).point1().i, (*itr).point1().j,
00627             (*itr).point2().i, (*itr).point2().j,
00628             angle * 180/M_PI);
00629 
00630       // eliminate lines that are close to vertical
00631       if(!isnan(angle)) { sumNegAngle += angle; itr++; }
00632       else
00633         { sumNegAngle += 90.0;
00634 
00635         //        itr = fNegAngleLines.erase(itr);
00636         LDEBUG("Drop a line");
00637       }
00638     }
00639 
00640 
00641   if (fNegAngleLines.size() == 0)
00642     {
00643       return avgCrossAngle;
00644     }
00645   else
00646     {
00647       avgNegAngle = sumNegAngle / fNegAngleLines.size();
00648     }
00649 
00650   //Get the distance that the avg pos and neg angles are away from 90
00651   int posAngleDistance = abs(90 - (int)avgPosAngle);
00652   int negAngleDistance = abs(90 - abs((int)avgNegAngle));
00653 
00654   float sumAngle = 0.0;
00655   std::vector<LineSegment2D> flines;
00656 
00657   if(posAngleDistance <= negAngleDistance)
00658     {
00659       flines = fPosAngleLines;
00660       sumAngle = sumPosAngle;
00661     }
00662   else
00663     {
00664       flines = fNegAngleLines;
00665       sumAngle = sumNegAngle;
00666     }
00667 
00668 //   // also drop off angles that do not fall
00669 //   // within a standard deviation of the average angle
00670 //   float stdAngleSum = 0.0;
00671 //   float stdAngleSqr = 0.0;
00672 //   for(uint i = 0; i < flines.size(); i++)
00673 //     {
00674 //       float angle = flines[i].angle();
00675 //       stdAngleSum = angle - meanAngle;
00676 //       stdAngleSqr += (stdAngleSum * stdAngleSum);
00677 //     }
00678 //   float stdevAngle = stdAngleSqr / flines.size();
00679 //   double stdtemp = sqrt((double)stdevAngle);
00680 //   stdevAngle = (float)stdtemp;
00681 
00682 //   // throw out angles that do not fit within stdev of the angle
00683 //   sumAngle = 0.0;  itr  = flines.begin();
00684 //   while(itr < flines.end())
00685 //     {
00686 //       float angle = (*itr).angle();
00687 //       if(angle >= (meanAngle - stdevAngle) &&
00688 //          angle <= (meanAngle + stdevAngle))
00689 //         { sumAngle += angle; itr++; }
00690 //       else itr = flines.erase(itr);
00691 //     }
00692 
00693   float avgAngle = 0.0;
00694 
00695   if (flines.size() != 0)
00696     {
00697       avgAngle = sumAngle / flines.size();
00698     }
00699   else
00700     {
00701       return avgCrossAngle;
00702     }
00703 
00704   if (avgAngle > 0) avgAngle -= M_PI;
00705 
00706 
00707   // Smooth out the angles being displayed by averaging the position of the last 30 angles
00708   uint angleBuffSize = angleBuff.size();
00709 
00710   bool isWithinStdDev = false;
00711   // Check if angle is within std dev
00712   if(angleBuff.size() < 2
00713      || (fabs(avgAngle - avgCrossAngle) <= stdDevCrossAngle ))
00714     {
00715       stdDevAngleCount = 0;
00716       isWithinStdDev = true;
00717     }
00718   else
00719     {
00720       stdDevAngleCount++;
00721     }
00722 
00723   if(stdDevAngleCount > 10)
00724     {
00725       angleBuff.clear();
00726       isWithinStdDev = true;
00727     }
00728 
00729   if(isWithinStdDev)
00730     {
00731       if(angleBuffSize >= 50)
00732         {
00733           angleBuff.pop_front();
00734         }
00735 
00736       angleBuff.push_back(avgAngle);
00737 
00738       angleBuffSize = angleBuff.size();
00739     }
00740 
00741   if(angleBuffSize > 0)
00742     {
00743       float sumBuffAngle = 0.0;
00744       std::list<float>::iterator it;
00745 
00746       for(it = angleBuff.begin(); it != angleBuff.end(); ++it)
00747         {
00748           sumBuffAngle += (*it);
00749         }
00750 
00751       avgCrossAngle = sumBuffAngle / angleBuffSize;
00752 
00753       //      LINFO("AVG Cross Angle: %f",avgCrossAngle);
00754 
00755 
00756       float sqrStdDevAngle = 0.0;
00757       for(it = angleBuff.begin(); it != angleBuff.end(); ++it)
00758       {
00759         sqrStdDevAngle = ((*it - avgCrossAngle) * (*it - avgCrossAngle));
00760       }
00761 
00762       float stdevAngle = sqrStdDevAngle / angleBuffSize;
00763       double stdTempAngle = sqrt((double)stdevAngle);
00764       stdDevCrossAngle = (float)stdTempAngle;
00765     }
00766   else
00767     {
00768       avgCrossAngle = avgAngle;
00769     }
00770 
00771   return avgCrossAngle;
00772 }
00773 
00774 // ######################################################################
00775 /* So things look consistent in everyone's emacs... */
00776 /* Local Variables: */
00777 /* indent-tabs-mode: nil */
00778 /* End: */
Generated on Sun May 8 08:40:19 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3