00001 /*!@file SeaBee/PipeRecognizer.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/SeaBee/CrossRecognizer.C $ 00034 // $Id: CrossRecognizer.C 10794 2009-02-08 06:21:09Z itti $ 00035 00036 #include "SeaBee/CrossRecognizer.H" 00037 00038 00039 // ###################################################################### 00040 CrossRecognizer::CrossRecognizer() 00041 { 00042 //default values for hough transform 00043 houghThreshold = 40; 00044 minThreshold = 10; 00045 maxThreshold = 50; 00046 sigma = 1.1; 00047 tlow = 0.3; 00048 thigh = 1.1; 00049 linescale = 80; 00050 avgCrossCenterX = 0; 00051 avgCrossCenterY = 0; 00052 avgCrossAngle = 0.0; 00053 stdDevCrossX = 0.0; 00054 stdDevCrossY = 0.0; 00055 stdDevCrossAngle = 0.0; 00056 00057 stdDevAngleCount = 0; 00058 stdDevCenterCount = 0; 00059 00060 foundCount = 0; 00061 00062 itsSetupOrangeTracker = false; 00063 } 00064 00065 // ###################################################################### 00066 CrossRecognizer::~CrossRecognizer() 00067 { } 00068 00069 // ###################################################################### 00070 void CrossRecognizer::getCrossLocation(rutz::shared_ptr<Image<byte> > colorSegmentedImage, 00071 rutz::shared_ptr<Image<PixRGB <byte> > > outputImage, 00072 CrossRecognizeMethod method, 00073 rutz::shared_ptr<Point2D<int> > crossCenterPoint, 00074 rutz::shared_ptr<float> crossAngle, 00075 rutz::shared_ptr<uint> stalePointCount 00076 ) 00077 { 00078 switch(method) 00079 { 00080 case HOUGH: 00081 calculateHoughTransform(colorSegmentedImage, outputImage, crossCenterPoint, crossAngle, stalePointCount); 00082 break; 00083 00084 default: 00085 LERROR("Invalid pipe recognizer method specified"); 00086 } 00087 00088 } 00089 00090 // ###################################################################### 00091 00092 void CrossRecognizer::calculateHoughTransform(rutz::shared_ptr<Image<byte> > colorSegmentedImage, 00093 rutz::shared_ptr<Image<PixRGB <byte> > > outputImage, 00094 rutz::shared_ptr<Point2D<int> > crossCenterPoint, 00095 rutz::shared_ptr<float> crossAngle, 00096 rutz::shared_ptr<uint> stalePointCount 00097 ) 00098 { 00099 std::vector<LineSegment2D> lines = getHoughLines(colorSegmentedImage, outputImage); 00100 std::vector<LineSegment2D> centerPointLines; 00101 *crossCenterPoint = getCrossCenter(lines, centerPointLines, stalePointCount); 00102 00103 LDEBUG("Center Point X: %d, Y: %d", crossCenterPoint->i, crossCenterPoint->j); 00104 00105 *crossAngle = getCrossDir(centerPointLines); 00106 } 00107 00108 // ###################################################################### 00109 00110 std::vector<LineSegment2D> CrossRecognizer::pruneLines (std::vector<LineSegment2D> lines) 00111 { 00112 uint nLines = lines.size(); 00113 // get the mean 00114 float sumLength = 0.0; float meanLength = 0.0; 00115 for (uint i = 0; i < nLines; i++) sumLength += lines[i].length(); 00116 meanLength = sumLength / nLines; 00117 00118 // get the standard deviation 00119 float sumsqr = 0.0; 00120 for (uint i = 0; i < nLines; i++) 00121 sumsqr += pow((float)(lines[i].length()) - meanLength, 2.0); 00122 float stdevLength = sqrt(sumsqr / (nLines-1)); 00123 00124 // kick out lines that aren't within the stddev of the mean length 00125 LDEBUG ("Mean: %f StdDev: %f", meanLength, stdevLength); 00126 std::vector<LineSegment2D> nlines; 00127 for(uint i = 0; i < nLines; i++) 00128 { 00129 if (lines[i].length() > (meanLength - stdevLength) && 00130 lines[i].length() < (meanLength + stdevLength) ) 00131 nlines.push_back(lines[i]); 00132 } 00133 00134 if (nlines.size() == 0) 00135 { LDEBUG("*** NO LINE LENGTH WITHIN STD DEV ***"); return lines; } 00136 00137 std::vector<LineSegment2D> flines = nlines; 00138 LDEBUG("\n\n\n\nSum the Average..."); 00139 double sumAngle = 0; 00140 std::vector<LineSegment2D>::iterator itr = flines.begin(); 00141 while(itr < flines.end()) 00142 { 00143 float angle = (*itr).angle(); 00144 LDEBUG("Line Angle[%4d,%4d][%4d,%4d]: %f", 00145 (*itr).point1().i, (*itr).point1().j, 00146 (*itr).point2().i, (*itr).point2().j, 00147 angle * 180/M_PI); 00148 00149 // eliminate lines that are close to vertical 00150 if(!isnan(angle)) { sumAngle += angle; itr++; } 00151 else 00152 { 00153 sumAngle += 90.0; 00154 // itr = flines.erase(itr); 00155 LDEBUG("Drop a line"); 00156 } 00157 } 00158 if (flines.size() == 0) return lines; 00159 00160 // also drop off angles that do not fall 00161 // within a standard deviation of the average angle 00162 float meanAngle = sumAngle / flines.size(); 00163 float stdAngleSum = 0.0; 00164 float stdAngleSqr = 0.0; 00165 for(uint i = 0; i < flines.size(); i++) 00166 { 00167 float angle = flines[i].angle(); 00168 stdAngleSum = angle - meanAngle; 00169 stdAngleSqr += (stdAngleSum * stdAngleSum); 00170 } 00171 float stdevAngle = stdAngleSqr / flines.size(); 00172 double stdtemp = sqrt((double)stdevAngle); 00173 stdevAngle = (float)stdtemp; 00174 00175 // throw out angles that do not fit within stdev of the angle 00176 sumAngle = 0.0; itr = flines.begin(); 00177 while(itr < flines.end()) 00178 { 00179 float angle = (*itr).angle(); 00180 if(angle >= (meanAngle - stdevAngle) && 00181 angle <= (meanAngle + stdevAngle)) 00182 { sumAngle += angle; itr++; } 00183 else itr = flines.erase(itr); 00184 } 00185 00186 return flines; 00187 } 00188 00189 // ###################################################################### 00190 00191 Point2D<int> CrossRecognizer::getCrossCenter (const std::vector<LineSegment2D> lines, 00192 std::vector<LineSegment2D> ¢erPointLines, 00193 rutz::shared_ptr<uint> stalePointCount) 00194 { 00195 00196 Point2D<int> avgCrossCenterPoint = Point2D<int>(avgCrossCenterX,avgCrossCenterY); 00197 00198 uint nLines = lines.size(); 00199 if(nLines == 0) 00200 { 00201 LDEBUG("*** NO LINES ***"); 00202 ++(*stalePointCount); 00203 return avgCrossCenterPoint; 00204 } 00205 00206 std::vector<LineSegment2D> posAngleLines, negAngleLines; 00207 00208 for(uint i = 0; i < nLines; i++) 00209 { 00210 if(lines[i].angle() >= 0) 00211 { 00212 posAngleLines.push_back(lines[i]); 00213 } 00214 else 00215 { 00216 negAngleLines.push_back(lines[i]); 00217 } 00218 } 00219 00220 std::vector<LineSegment2D> fPosAngleLines = posAngleLines;//pruneLines(posAngleLines); 00221 std::vector<LineSegment2D> fNegAngleLines = negAngleLines;//pruneLines(negAngleLines); 00222 00223 std::vector<LineSegment2D> flines; 00224 00225 for(uint i = 0; i < fPosAngleLines.size(); i++) 00226 { 00227 flines.push_back(fPosAngleLines[i]); 00228 } 00229 00230 for(uint i = 0; i < fNegAngleLines.size(); i++) 00231 { 00232 flines.push_back(fNegAngleLines[i]); 00233 } 00234 00235 00236 std::vector<std::vector<Point2D<int> > > intersectPts; 00237 00238 //Go through all the remaining lines 00239 for(uint r = 0; r < flines.size(); r++) 00240 { 00241 for(uint s = 0; s < flines.size(); s++) 00242 { 00243 if(r != s) 00244 { 00245 double xIntersect, yIntersect = 0.0; 00246 //if two lines intersect 00247 if(flines[r].intersects(flines[s],xIntersect,yIntersect) 00248 && (fabs(flines[r].angleBetween(flines[s])) >= 0.95 * M_PI/2)//convert to radians 00249 && (fabs(flines[r].angleBetween(flines[s])) <= 1.05 * M_PI/2))//convert to radians 00250 { 00251 int ptIndex = -1; 00252 00253 centerPointLines.push_back(flines[r]); 00254 centerPointLines.push_back(flines[s]); 00255 00256 00257 //check to see if the point at which they intersect fits into a pre-existing bucket 00258 for(uint c = 0; c < intersectPts.size(); c++) 00259 { 00260 if(xIntersect < intersectPts[c][0].i + 5 && 00261 xIntersect > intersectPts[c][0].i - 5 && 00262 yIntersect < intersectPts[c][0].j + 5 && 00263 yIntersect > intersectPts[c][0].j - 5 ) 00264 { 00265 ptIndex = c; 00266 } 00267 00268 } 00269 00270 //if the point fits into a pre-existing bucket, add it to the bucket 00271 if(ptIndex > 0) 00272 { 00273 int x = (int)(xIntersect); 00274 int y = (int)(yIntersect); 00275 00276 intersectPts[ptIndex].push_back(Point2D<int>(x,y)); 00277 //average the old bucket's value with the new point added 00278 //so as to create a moving bucket 00279 intersectPts[ptIndex][0].i += x; 00280 intersectPts[ptIndex][0].i /= 2; 00281 intersectPts[ptIndex][0].j += y; 00282 intersectPts[ptIndex][0].j /= 2; 00283 00284 } 00285 //otherwise, create a new bucket 00286 else 00287 { 00288 int x = (int)(xIntersect); 00289 int y = (int)(yIntersect); 00290 00291 std::vector<Point2D<int> > newIntPts; 00292 newIntPts.push_back(Point2D<int>(x,y)); 00293 intersectPts.push_back(newIntPts); 00294 } 00295 } 00296 } 00297 } 00298 } 00299 00300 if(intersectPts.size() == 0) 00301 { 00302 LDEBUG("*** NO INTERSECT POINTS FOUND ***"); 00303 ++(*stalePointCount); 00304 return avgCrossCenterPoint; 00305 } 00306 00307 uint maxPts = intersectPts[0].size(); 00308 uint maxIndex = 0; 00309 00310 for(uint i = 0; i < intersectPts.size(); i++) 00311 { 00312 if(intersectPts[i].size() > maxPts) 00313 { 00314 maxPts = intersectPts[i].size(); 00315 maxIndex = i; 00316 } 00317 } 00318 00319 Point2D<int> finalPoint = intersectPts[maxIndex][0]; 00320 00321 00322 // Smooth out the center points being displayed by averaging the position of the 00323 // last 30 center points. 00324 00325 bool isWithinStdDev = false; 00326 // Check if center point is within std dev 00327 if(centerPointBuff.size() < 2 00328 || (abs(finalPoint.i - avgCrossCenterX) <= stdDevCrossX 00329 && abs(finalPoint.j - avgCrossCenterY) <= stdDevCrossY) 00330 ) 00331 { 00332 stdDevCenterCount = 0; 00333 isWithinStdDev = true; 00334 } 00335 else 00336 { 00337 stdDevCenterCount++; 00338 00339 LINFO("Current X: %d Y: %d",finalPoint.i, finalPoint.j); 00340 LINFO("AVG X: %d Y: %d",avgCrossCenterX, avgCrossCenterY); 00341 LINFO("STDDEV CROSS (X,Y):(%f,%f)",stdDevCrossX, stdDevCrossY); 00342 00343 } 00344 00345 *stalePointCount = 0; 00346 00347 uint centerBuffSize = centerPointBuff.size(); 00348 00349 if(stdDevCenterCount > 5) 00350 { 00351 isWithinStdDev = true; 00352 centerPointBuff.clear(); 00353 } 00354 00355 if(isWithinStdDev) 00356 { 00357 if(centerBuffSize >= 30) 00358 { 00359 centerPointBuff.pop_front(); 00360 } 00361 00362 centerPointBuff.push_back(finalPoint); 00363 00364 centerBuffSize = centerPointBuff.size(); 00365 } 00366 00367 if(centerBuffSize > 0) 00368 { 00369 int sumX = 0, sumY = 0; 00370 std::list<Point2D<int> >::iterator it; 00371 00372 for(it = centerPointBuff.begin(); it != centerPointBuff.end(); ++it) 00373 { 00374 sumX += (*it).i; 00375 sumY += (*it).j; 00376 } 00377 00378 avgCrossCenterX = sumX / centerBuffSize; 00379 avgCrossCenterY = sumY / centerBuffSize; 00380 00381 avgCrossCenterPoint = Point2D<int>(avgCrossCenterX,avgCrossCenterY); 00382 00383 float sqrStdCenterX = 0.0; 00384 float sqrStdCenterY = 0.0; 00385 00386 00387 for(it = centerPointBuff.begin(); it != centerPointBuff.end(); ++it) 00388 { 00389 sqrStdCenterX += (((*it).i - avgCrossCenterX) * ((*it).i - avgCrossCenterX)); 00390 sqrStdCenterY += (((*it).j - avgCrossCenterY) * ((*it).j - avgCrossCenterY)); 00391 } 00392 00393 float stdevCenterX = sqrStdCenterX / centerBuffSize; 00394 float stdevCenterY = sqrStdCenterY / centerBuffSize; 00395 double stdTempCenterX = sqrt((double)stdevCenterX); 00396 double stdTempCenterY = sqrt((double)stdevCenterY); 00397 stdDevCrossX = (float)stdTempCenterX; 00398 stdDevCrossY = (float)stdTempCenterY; 00399 } 00400 else 00401 { 00402 avgCrossCenterPoint = finalPoint; 00403 } 00404 // stalePointCount++; 00405 return avgCrossCenterPoint; 00406 } 00407 00408 00409 // ###################################################################### 00410 float CrossRecognizer::getCrossDir(const std::vector<LineSegment2D> lines) 00411 { 00412 uint nLines = lines.size(); 00413 if(nLines == 0) { LDEBUG("*** NO LINES ***"); return avgCrossAngle;} 00414 00415 //separate lines into positive and negative angles 00416 std::vector<LineSegment2D> posAngleLines, negAngleLines; 00417 00418 for(uint i = 0; i < nLines; i++) 00419 { 00420 if(lines[i].angle() >= 0) 00421 { 00422 posAngleLines.push_back(lines[i]); 00423 } 00424 else 00425 { 00426 negAngleLines.push_back(lines[i]); 00427 } 00428 } 00429 00430 std::vector<LineSegment2D> fPosAngleLines = posAngleLines;//pruneLines(posAngleLines); 00431 std::vector<LineSegment2D> fNegAngleLines = negAngleLines;//pruneLines(negAngleLines); 00432 00433 double avgPosAngle, avgNegAngle; 00434 00435 // Find average of positive angles 00436 // LINFO("\n\n\n\nSum the Average..."); 00437 double sumPosAngle = 0; 00438 std::vector<LineSegment2D>::iterator itr = fPosAngleLines.begin(); 00439 while(itr < fPosAngleLines.end()) 00440 { 00441 float angle = (*itr).angle(); 00442 LDEBUG("Line Angle[%4d,%4d][%4d,%4d]: %f", 00443 (*itr).point1().i, (*itr).point1().j, 00444 (*itr).point2().i, (*itr).point2().j, 00445 angle * 180/M_PI); 00446 00447 // eliminate lines that are close to vertical 00448 if(!isnan(angle)) { sumPosAngle += angle; itr++; } 00449 else 00450 { sumPosAngle += 90.0; 00451 //itr = fPosAngleLines.erase(itr); 00452 LDEBUG("Drop a line"); 00453 } 00454 } 00455 00456 if (fPosAngleLines.size() == 0) 00457 { 00458 return avgCrossAngle; 00459 } 00460 else 00461 { 00462 avgPosAngle = sumPosAngle / fPosAngleLines.size(); 00463 } 00464 00465 // Find average of negative angles 00466 double sumNegAngle = 0; 00467 itr = fNegAngleLines.begin(); 00468 while(itr < fNegAngleLines.end()) 00469 { 00470 float angle = (*itr).angle(); 00471 LDEBUG("Line Angle[%4d,%4d][%4d,%4d]: %f", 00472 (*itr).point1().i, (*itr).point1().j, 00473 (*itr).point2().i, (*itr).point2().j, 00474 angle * 180/M_PI); 00475 00476 // eliminate lines that are close to vertical 00477 if(!isnan(angle)) { sumNegAngle += angle; itr++; } 00478 else 00479 { sumNegAngle += 90.0; 00480 00481 // itr = fNegAngleLines.erase(itr); 00482 LDEBUG("Drop a line"); 00483 } 00484 } 00485 00486 00487 if (fNegAngleLines.size() == 0) 00488 { 00489 return avgCrossAngle; 00490 } 00491 else 00492 { 00493 avgNegAngle = sumNegAngle / fNegAngleLines.size(); 00494 } 00495 00496 //Get the distance that the avg pos and neg angles are away from 90 00497 int posAngleDistance = abs(90 - (int)avgPosAngle); 00498 int negAngleDistance = abs(90 - abs((int)avgNegAngle)); 00499 00500 float meanAngle = 0.0; 00501 float sumAngle = 0.0; 00502 std::vector<LineSegment2D> flines; 00503 00504 if(posAngleDistance <= negAngleDistance) 00505 { 00506 flines = fPosAngleLines; 00507 meanAngle = avgPosAngle; 00508 sumAngle = sumPosAngle; 00509 } 00510 else 00511 { 00512 flines = fNegAngleLines; 00513 meanAngle = avgNegAngle; 00514 sumAngle = sumNegAngle; 00515 } 00516 00517 // // also drop off angles that do not fall 00518 // // within a standard deviation of the average angle 00519 // float stdAngleSum = 0.0; 00520 // float stdAngleSqr = 0.0; 00521 // for(uint i = 0; i < flines.size(); i++) 00522 // { 00523 // float angle = flines[i].angle(); 00524 // stdAngleSum = angle - meanAngle; 00525 // stdAngleSqr += (stdAngleSum * stdAngleSum); 00526 // } 00527 // float stdevAngle = stdAngleSqr / flines.size(); 00528 // double stdtemp = sqrt((double)stdevAngle); 00529 // stdevAngle = (float)stdtemp; 00530 00531 // // throw out angles that do not fit within stdev of the angle 00532 // sumAngle = 0.0; itr = flines.begin(); 00533 // while(itr < flines.end()) 00534 // { 00535 // float angle = (*itr).angle(); 00536 // if(angle >= (meanAngle - stdevAngle) && 00537 // angle <= (meanAngle + stdevAngle)) 00538 // { sumAngle += angle; itr++; } 00539 // else itr = flines.erase(itr); 00540 // } 00541 00542 float avgAngle = 0.0; 00543 00544 if (flines.size() != 0) 00545 { 00546 avgAngle = sumAngle / flines.size(); 00547 } 00548 else 00549 { 00550 return avgCrossAngle; 00551 } 00552 00553 if (avgAngle > 0) avgAngle -= M_PI; 00554 00555 00556 // Smooth out the angles being displayed by averaging the position of the last 30 angles 00557 uint angleBuffSize = angleBuff.size(); 00558 00559 bool isWithinStdDev = false; 00560 // Check if angle is within std dev 00561 if(angleBuff.size() < 2 00562 || (fabs(avgAngle - avgCrossAngle) <= stdDevCrossAngle )) 00563 { 00564 stdDevAngleCount = 0; 00565 isWithinStdDev = true; 00566 } 00567 else 00568 { 00569 stdDevAngleCount++; 00570 } 00571 00572 if(stdDevAngleCount > 10) 00573 { 00574 angleBuff.clear(); 00575 isWithinStdDev = true; 00576 } 00577 00578 if(isWithinStdDev) 00579 { 00580 if(angleBuffSize >= 50) 00581 { 00582 angleBuff.pop_front(); 00583 } 00584 00585 angleBuff.push_back(avgAngle); 00586 00587 angleBuffSize = angleBuff.size(); 00588 } 00589 00590 if(angleBuffSize > 0) 00591 { 00592 float sumBuffAngle = 0.0; 00593 std::list<float>::iterator it; 00594 00595 for(it = angleBuff.begin(); it != angleBuff.end(); ++it) 00596 { 00597 sumBuffAngle += (*it); 00598 } 00599 00600 avgCrossAngle = sumBuffAngle / angleBuffSize; 00601 00602 // LINFO("AVG Cross Angle: %f",avgCrossAngle); 00603 00604 00605 float sqrStdDevAngle = 0.0; 00606 for(it = angleBuff.begin(); it != angleBuff.end(); ++it) 00607 { 00608 sqrStdDevAngle = ((*it - avgCrossAngle) * (*it - avgCrossAngle)); 00609 } 00610 00611 float stdevAngle = sqrStdDevAngle / angleBuffSize; 00612 double stdTempAngle = sqrt((double)stdevAngle); 00613 stdDevCrossAngle = (float)stdTempAngle; 00614 } 00615 else 00616 { 00617 avgCrossAngle = avgAngle; 00618 } 00619 00620 return avgCrossAngle; 00621 } 00622 00623 00624 // ###################################################################### 00625 std::vector<LineSegment2D> CrossRecognizer::getHoughLines 00626 (rutz::shared_ptr< Image< byte > > colorSegmentedImage, 00627 rutz::shared_ptr< Image< PixRGB <byte> > > outputImage) 00628 { 00629 00630 #ifndef HAVE_OPENCV 00631 LFATAL("OpenCV must be installed in order to use this function"); 00632 #else 00633 00634 //find edges of segmented image using canny 00635 IplImage *edge = cvCreateImage( cvGetSize(img2ipl(*colorSegmentedImage)), 8, 1 ); 00636 cvCanny( img2ipl(luminance(*colorSegmentedImage)), edge, 100, 150, 3 );//150,200,3 00637 00638 //clear output image and set it equal to canny edge image 00639 outputImage->clear(); 00640 *outputImage = toRGB(ipl2gray(edge)); 00641 00642 //storage for use in hough transform 00643 CvMemStorage* storage = cvCreateMemStorage(0); 00644 00645 //perform hough transform and store hough lines 00646 CvSeq* cvLines = cvHoughLines2(edge, storage, CV_HOUGH_PROBABILISTIC, 1, CV_PI/180, 30, 20, 10); 00647 00648 LINFO("cvLines %d",cvLines->total); 00649 00650 //storage for hough line segments 00651 std::vector <LineSegment2D> lineSegments; 00652 00653 //loop through hough lines, store them as line segments, and draw lines in output image 00654 for(int i = 0; i < cvLines->total; i++ ) 00655 { 00656 //get a line 00657 CvPoint* line = (CvPoint*)cvGetSeqElem(cvLines,i); 00658 //get line end points 00659 Point2D<int> pt1 = Point2D<int>(line[0].x,line[0].y); 00660 Point2D<int> pt2 = Point2D<int>(line[1].x,line[1].y); 00661 00662 00663 //create line segment from endpoints and store 00664 lineSegments.push_back(LineSegment2D(pt1,pt2)); 00665 00666 //draw line segment in output image 00667 drawLine(*outputImage, pt1, pt2, PixRGB<byte>(255,0,0)); 00668 } 00669 00670 //clean up pointers 00671 // delete edge; 00672 // delete storage; 00673 // delete cvLines; 00674 00675 00676 00677 #endif // HAVE_OPENCV 00678 00679 00680 00681 00682 00683 00684 00685 00686 00687 00688 std::vector <LineSegment2D> lines; 00689 00690 #ifndef HAVE_OPENCV 00691 LFATAL("OpenCV must be installed in order to use this function"); 00692 #else 00693 00694 IplImage *edge = cvCreateImage( cvGetSize(img2ipl(cameraImage)), 8, 1 ); 00695 cvCanny( img2ipl(luminance(cameraImage)), edge, 100, 150, 3 );//150,200,3 00696 00697 // inplacePaste(dispImage, toRGB(edgeImage), Point2D<int>(0,h)); 00698 00699 // tim.reset(); 00700 // rutz::shared_ptr<CvMemStorage*> storage; 00701 // *storage = cvCreateMemStorage(0); 00702 00703 CvMemStorage* storage = cvCreateMemStorage(0); 00704 00705 //outputImage.clear(); 00706 00707 outputImage = ipl2gray(edge); 00708 00709 CvSeq* cvlines = cvHoughLines2(edge, storage, CV_HOUGH_STANDARD, 00710 1, CV_PI/180, 40 , 0, 0); 00711 // t = tim.get(); 00712 // LDEBUG("houghTransform takes: %f ms", (float)t/1000.0); 00713 00714 for(int i = 0; i < MIN(cvlines->total,10); i++ ) 00715 { 00716 float* line = (float*)cvGetSeqElem(cvlines,i); 00717 float rho = line[0]; 00718 float theta = line[1]; 00719 CvPoint pt1, pt2; 00720 double a = cos(theta), b = sin(theta); 00721 double x0 = a*rho, y0 = b*rho; 00722 pt1.x = cvRound(x0 + 1000*(-b)); 00723 pt1.y = cvRound(y0 + 1000*(a)); 00724 pt2.x = cvRound(x0 - 1000*(-b)); 00725 pt2.y = cvRound(y0 - 1000*(a)); 00726 lines.push_back(LineSegment2D(Point2D<int>(pt1.x,pt1.y), 00727 Point2D<int>(pt2.x,pt2.y))); 00728 drawLine(outputImage, Point2D<int>(pt1.x,pt1.y), 00729 Point2D<int>(pt2.x, pt2.y), PixRGB<byte>(255,0,0)); 00730 } 00731 00732 cvReleaseMemStorage(&storage); 00733 cvReleaseImage(&edge); 00734 //cvReleaseSeq(&cvlines); 00735 00736 // delete edge; 00737 // delete cvlines; 00738 00739 #endif // HAVE_OPENCV 00740 00741 return lines; 00742 } 00743 00744 00745 00746 00747 // ######################################################################