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> ¢erPointLines, 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: */