00001 /*!@file BeoSub/BeoSubBin.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/BeoSubBin.C $ 00034 // $Id: BeoSubBin.C 12782 2010-02-05 22:14:30Z irock $ 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/BeoSubBin.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 BeoSubBin::BeoSubBin() 00074 { 00075 imageAngles.resize(0); 00076 imageLines.resize(0); 00077 binAngles.resize(0); 00078 binLines.resize(0); 00079 binCenter = *(new Point2D<int>(-1, -1)); 00080 00081 } 00082 00083 // ###################################################################### 00084 BeoSubBin::~BeoSubBin() 00085 { } 00086 00087 00088 00089 // ###################################################################### 00090 float BeoSubBin::getBinSceneMass(Image< PixRGB<byte> > &cameraImage, Image< PixRGB<byte> > &outputImage, Point2D<int>& center) { 00091 #ifndef HAVE_OPENCV 00092 LFATAL("OpenCV must be installed in order to use this function"); 00093 return 0; 00094 #else 00095 IplImage *edge = cvCreateImage( cvGetSize(img2ipl(cameraImage)), 8, 1 ); 00096 IplImage *out = cvCreateImage( cvGetSize(img2ipl(cameraImage)), 8, 1 ); 00097 IplImage *edge2 = cvCreateImage( cvGetSize(img2ipl(cameraImage)), 8, 1); 00098 00099 ////////// image manipulation /////////////// 00100 cvThreshold(img2ipl(luminance(cameraImage)), edge, 170, 255, CV_THRESH_TOZERO); 00101 00102 IplConvKernel* dilation = cvCreateStructuringElementEx(8, 8, 0, 0, CV_SHAPE_RECT); 00103 cvErode(edge, edge2, dilation, 1); 00104 cvDilate(edge2, edge, dilation, 1); 00105 cvThreshold(edge, out, 200, 255, CV_THRESH_TOZERO); 00106 00107 00108 int mass=-1, x=0, y=0; 00109 Image<byte> isoWhite = luminance(ipl2gray(out)); 00110 //////FIXME mass = isolateWhite(isoWhite, isoWhite, x, y); 00111 00112 outputImage = toRGB(isoWhite); 00113 00114 center.i = x; 00115 center.j = y; 00116 00117 cvReleaseImage(&edge); 00118 cvReleaseImage(&edge2); 00119 // cvReleaseImage(&out); 00120 cvReleaseStructuringElement(&dilation); 00121 return mass; 00122 #endif 00123 } 00124 00125 00126 std::vector<LineSegment2D> BeoSubBin::getHoughLines(Image< PixRGB <byte> > &cameraImage, Image< PixRGB <byte> > &preHough, 00127 Image< PixRGB <byte> > &outputImage) 00128 { 00129 std::vector <LineSegment2D> lines; 00130 00131 #ifndef HAVE_OPENCV 00132 LFATAL("OpenCV must be installed in order to use this function"); 00133 #else 00134 00135 // inplacePaste(dispImage, toRGB(edgeImage), Point2D<int>(0,h)); 00136 IplImage *edge = cvCreateImage( cvGetSize(img2ipl(cameraImage)), 8, 1 ); 00137 IplImage *out = cvCreateImage( cvGetSize(img2ipl(cameraImage)), 8, 1 ); 00138 IplImage *edge2 = cvCreateImage( cvGetSize(img2ipl(cameraImage)), 8, 1 ); 00139 //cvSobel(img2ipl(luminance(cameraImage)), edge, 0, 1, 3); 00140 00141 00142 00143 00144 00145 /////////////////////// steps for bottom camera which only uses rectangulation /////////////// 00146 00147 //////////////// image manipulation, may need tweaking ///////////////////// 00148 // need to up contrast 00149 cvEqualizeHist(img2ipl(luminance(cameraImage)), edge); 00150 cvThreshold(img2ipl(luminance(cameraImage)), edge, 170, 255, CV_THRESH_TOZERO ); 00151 00152 cvThreshold(edge, edge2, 170, 255, CV_THRESH_TOZERO); 00153 IplConvKernel* dilation = cvCreateStructuringElementEx(8, 8, 0, 0, CV_SHAPE_RECT); 00154 out = edge; 00155 cvErode(edge, edge2, dilation, 1); 00156 cvDilate(edge2, edge, dilation, 1 ); 00157 cvThreshold(edge, edge2, 200, 255, CV_THRESH_TOZERO ); 00158 00159 ///////////////////////////////////////////////////////// 00160 00161 00162 cvCanny(edge, out, 100, 150, 3 );//150,200,3 00163 preHough = ipl2gray(edge); 00164 00165 00166 CvMemStorage* storage = cvCreateMemStorage(0); 00167 00168 outputImage.clear(); 00169 outputImage = toRGB( ipl2gray( out ) ); 00170 00171 CvSeq* cvlines = cvHoughLines2(out, storage, CV_HOUGH_STANDARD, 1, CV_PI/180, 10, 10, 10); 00172 00173 for(int i = 0; i < MIN(cvlines->total,10); i++ ) 00174 { 00175 float* line = (float*)cvGetSeqElem(cvlines,i); 00176 float rho = line[0]; 00177 float theta = line[1]; 00178 CvPoint pt1, pt2; 00179 double a = cos(theta), b = sin(theta); 00180 double x0 = a*rho, y0 = b*rho; 00181 pt1.x = cvRound(x0 + 1000*(-b)); 00182 pt1.y = cvRound(y0 + 1000*(a)); 00183 pt2.x = cvRound(x0 - 1000*(-b)); 00184 pt2.y = cvRound(y0 - 1000*(a)); 00185 lines.push_back(LineSegment2D(Point2D<int>(pt1.x,pt1.y),Point2D<int>(pt2.x,pt2.y))); 00186 drawLine(outputImage, Point2D<int>(pt1.x,pt1.y), Point2D<int>(pt2.x, pt2.y), PixRGB<byte>(255,0,0)); 00187 } 00188 /////////////////////////////////////////////////////////////////////////////////// 00189 00190 00191 00192 00193 ///////////// NOTE:::: will need to create overlap function that will remove orange, replace it with black /////// 00194 ////////////////// before any bin recognition is done ///////////////////////// 00195 00196 00197 cvReleaseImage(&edge); 00198 cvReleaseImage(&edge2); 00199 //cvReleaseImage(&out); 00200 cvReleaseStructuringElement(&dilation); 00201 00202 00203 #endif // HAVE_OPENCV 00204 return lines; 00205 } 00206 00207 // ###################################################################### 00208 void BeoSubBin::pruneLines(std::vector<LineSegment2D>& lines, std::vector<LineSegment2D> &pruned, Image< PixRGB<byte> >* img ) { 00209 00210 00211 std::vector<LineSegment2D> nonSimilarLines; 00212 std::vector<LineSegment2D>::iterator iter; 00213 00214 // add the first line to the nonSimilarLine vector 00215 // erase if from the input line vector we are checking 00216 if(lines.size() > 0) { 00217 nonSimilarLines.push_back(lines[0]); 00218 lines.erase(lines.begin()); 00219 iter = lines.begin(); 00220 } 00221 else 00222 LDEBUG("*** NO LINES ***"); 00223 00224 00225 double x, y; 00226 00227 00228 00229 //top border of image 00230 LineSegment2D border1 ( *(new Point2D<int>(0, 0)), *(new Point2D<int>(img->getWidth(), 0) ) ); 00231 // left border of image 00232 LineSegment2D border2 ( *(new Point2D<int>(0, 0)), *(new Point2D<int>(0, img->getHeight()) ) ); 00233 // right border of image 00234 LineSegment2D border3 ( *(new Point2D<int>(img->getWidth(), 0)), *(new Point2D<int>(img->getWidth(), img->getHeight()) ) ); 00235 //bottom border of image 00236 LineSegment2D border4 ( *(new Point2D<int>(0, img->getHeight())), *(new Point2D<int>(img->getWidth(), img->getHeight()) ) ); 00237 00238 // check for similar lines 00239 for(uint i = 0; i < nonSimilarLines.size(); i++) { 00240 00241 while(iter != lines.end()) { 00242 00243 double angle = nonSimilarLines[i].angleBetween(*iter); 00244 angle *= 180/PI; 00245 double intersect = nonSimilarLines[i].intersects((*iter), x, y); 00246 00247 // if the lines do not intersect in the image, possibly parallel 00248 if(!intersect) { 00249 00250 double x2, y2; 00251 // if the parallel lines intersect the top and bottom images 00252 // at similar points, remove line from unpruned line list 00253 if((nonSimilarLines[i].intersects(border1, x, y) && (*iter).intersects(border1, x2, y2)) || 00254 (nonSimilarLines[i].intersects(border4, x, y) && (*iter).intersects(border4, x2, y2))) { 00255 00256 00257 if(fabs(x - x2) < 5.0) { 00258 // drawLine(*img, (*iter).point1(), (*iter).point2(), PixRGB<byte>(255, 150, 0)); 00259 lines.erase(iter); 00260 } 00261 00262 } 00263 // if the parallel lines intersect the left and right images 00264 // at similar points, remove one of them 00265 else if((nonSimilarLines[i].intersects(border2, x, y) && (*iter).intersects(border2, x2, y2)) || 00266 (nonSimilarLines[i].intersects(border3, x, y) && (*iter).intersects(border3, x2, y2))) { 00267 00268 if(fabs(y - y2) < 5.0) { 00269 //drawLine(*img, (*iter).point1(), (*iter).point2(), PixRGB<byte>(255, 150, 0)); 00270 lines.erase(iter); 00271 } 00272 00273 } 00274 00275 } 00276 // else if lines are not parallel, 00277 // if they intersect in the image at a very small angle 00278 // remove one of them 00279 else if(intersect && img->coordsOk((int)x, (int)y) && (fabs(angle) < 2.5 || fabs(angle) > 178.5)) { 00280 //drawLine(*img, (*iter).point1(), (*iter).point2(), PixRGB<byte>(255, 0, 150)); 00281 lines.erase(iter); 00282 } 00283 00284 if(iter != lines.end()) 00285 iter++; 00286 } 00287 00288 iter = lines.begin(); 00289 // once all unpruned lines have been compared to current nonSimilarLine, 00290 // in which any similar lines have been removed. 00291 // add next unpruned line to nonSimilarLines vector 00292 // reiterate and see if any unpruned lines are similar to that one 00293 if(lines.size() > 0) { 00294 nonSimilarLines.push_back(*iter); 00295 lines.erase(iter); 00296 } 00297 00298 00299 } 00300 00301 pruned = nonSimilarLines; 00302 // lines are now pruned 00303 binAngles.clear(); 00304 00305 // now remove similar angles at similar intersections 00306 pruneAngles(nonSimilarLines, binAngles, img); 00307 00308 00309 /// drawing //////////////// 00310 for(uint i = 0; i < nonSimilarLines.size(); i++) 00311 drawLine(*img, nonSimilarLines[i].point1(), nonSimilarLines[i].point2(), PixRGB<byte>(255,0,0)); 00312 00313 // for(uint i = 0; i < binAngles.size(); i++) { 00314 // //printf("x: %d, y: %d, angle: %f\n", binAngles[i].pos.i, binAngles[i].pos.j, binAngles[i].angle); 00315 // drawCircle(*img, binAngles[i].pos, 5, PixRGB<byte>(0, 255, 0)); 00316 // } 00317 00318 drawCircle(*img, *(new Point2D<int>(160, 120)), 5, PixRGB<byte>(200, 255, 0)); 00319 00320 /// we also want to return angles with their respective positions. 00321 //// which will require a struct that associates angle, with an x and a y; 00322 00323 } 00324 00325 00326 void BeoSubBin::pruneAngles(std::vector<LineSegment2D>& lines, std::vector<BinAngles>& angles, Image< PixRGB< byte > >* img) { 00327 00328 00329 for(uint i = 0; i < lines.size(); i++) { 00330 00331 for(uint j = i+1; j < lines.size(); j++) { 00332 00333 double angle = lines[i].angleBetween(lines[j]); 00334 angle *= 180/PI; 00335 00336 double x, y; 00337 lines[i].intersects(lines[j], x, y); 00338 00339 // look through list of angles added so far, 00340 // if the angle we are currently looking at is 00341 // a similar angle, and it has a similar intersection 00342 // do not add it to angles vector 00343 bool add = true; 00344 for(uint k = 0; k < angles.size(); k++) { 00345 if(fabs(angles[k].angle - angle) < 5.0 && 00346 (abs(angles[k].pos.i - (int)x) <= 2.0 && abs(angles[k].pos.j - (int)y) <= 2.0)) { 00347 add = false; 00348 break; 00349 } 00350 } 00351 00352 // add angle if there no similar angles at intersections 00353 // in angles vector 00354 if(add && img->coordsOk((int)x, (int)y)) { 00355 BinAngles b; 00356 b.pos = *(new Point2D<int>((int)x, (int)y)); 00357 b.angle = angle; 00358 angles.push_back(b); 00359 } 00360 00361 } 00362 } 00363 00364 } 00365 00366 void BeoSubBin::removeOrangePipe(Image< PixRGB<byte> >& img) { 00367 00368 // Image<byte> orange(img.getWidth(), img.getHeight(), ZEROS); 00369 00370 // float mass = isolateOrange(img, orange); 00371 00372 00373 // if(mass > 0) { 00374 00375 // for(int i = 0; i < img.getWidth(); i++) { 00376 // for(int j = 0; j < img.getHeight(); j++) { 00377 00378 // if(orange.coordsOk(i, j) && orange.getVal(i, j) == 255) 00379 // img.setVal(i, j, 0); 00380 00381 // } 00382 // } 00383 00384 // } 00385 00386 00387 } 00388 00389 void BeoSubBin::getWeightedBinMass(std::vector<BinAngles>& angles, Point2D<int> & center, bool cropWindow, Image<PixRGB<byte> > *img) { 00390 00391 // find closest 00392 float DIST = 1; 00393 00394 float avgY = 0; 00395 00396 if(angles.size() > 0) { 00397 DIST = center.distance(angles[0].pos); 00398 avgY = angles[0].pos.j; 00399 } 00400 00401 00402 for(uint i = 1; i < angles.size(); i++) { 00403 float closer = center.distance(angles[i].pos); 00404 00405 avgY += angles[i].pos.j; 00406 00407 if(closer < DIST) //&& angles[i].pos.j > 100) //&& angles[i].angle < 80 && angles[i].angle > 40) 00408 DIST = closer; 00409 00410 } 00411 00412 avgY /= angles.size(); 00413 avgY = 120 - avgY; 00414 00415 float topCap = 0, bottomCap = 240; 00416 00417 if(cropWindow && avgY < 0) 00418 bottomCap = 240 - avgY; 00419 else if(cropWindow) 00420 topCap = avgY; 00421 00422 if(cropWindow) { 00423 LINFO("avgY: %f", avgY); 00424 drawLine(*img, Point2D<int>(0, (int)avgY), Point2D<int>(320, (int)avgY), PixRGB<byte>(255, 0, 0)); 00425 drawLine(*img, Point2D<int>(0, (int)topCap), Point2D<int>(320, (int)topCap), PixRGB<byte>(255,0,0)); 00426 drawLine(*img, Point2D<int>(0, (int)bottomCap), Point2D<int>(320, (int)bottomCap), PixRGB<byte>(255,0,0)); 00427 } 00428 00429 Point2D<int> weightedCenter = center; 00430 /// setup weighting system 00431 //// ORIGINAL DISTANCE / (WEIGHT)^2 from CLOSEST DISTANCE * WEIGHT = ORIGINAL DISTANCE 00432 00433 printf("closest dist: %f\n", DIST); 00434 00435 for(uint i = 0; i < angles.size(); i++) { 00436 00437 if(angles[i].pos.j < bottomCap && angles[i].pos.j > topCap) { 00438 float currentDist = weightedCenter.distance(angles[i].pos); 00439 printf("current dist: %f, x: %d, y: %d\n", currentDist, angles[i].pos.i, angles[i].pos.j); 00440 float weight = 1 / (currentDist/DIST ); // * currentDist/DIST); 00441 printf("weight: %f\n", weight); 00442 float cx = (angles[i].pos.i - weightedCenter.i) * weight + weightedCenter.i; 00443 float cy = (angles[i].pos.j - weightedCenter.j) * weight + weightedCenter.j; 00444 00445 Point2D<int> weightPoint((int)cx, (int)cy); 00446 printf("new point, x: %d, y: %d\n", weightPoint.i, weightPoint.j); 00447 center += weightPoint; 00448 center /= 2; 00449 } 00450 } 00451 00452 } 00453 00454 // THIS FUNCTION IS ONLY USED FOR FRONT CAMERA 00455 void BeoSubBin::getParallelIntersections(std::vector<LineSegment2D>& lines, std::vector<LineSegment2D>& frontLines, 00456 Image< PixRGB<byte> >& img) { 00457 00458 printf("size of lines: %d\n", (int)lines.size()); 00459 00460 bool moreThanOne; 00461 00462 frontLines.clear(); 00463 std::vector<LineSegment2D> tmp = lines; 00464 std::vector<LineSegment2D>::iterator iter2 = tmp.begin(); 00465 00466 // left border of image 00467 LineSegment2D border2 ( *(new Point2D<int>(0, 0)), *(new Point2D<int>(0, img.getHeight()) ) ); 00468 // right border of image 00469 LineSegment2D border3 ( *(new Point2D<int>(img.getWidth(), 0)), *(new Point2D<int>(img.getWidth(), img.getHeight()) ) ); 00470 00471 // iterate through set of lines 00472 for(uint i = 0; i < tmp.size(); i++) { 00473 00474 moreThanOne = false; 00475 // check current line with other lines in the set 00476 iter2 = tmp.begin() + i + 1; 00477 while(tmp.size() > i+1 && iter2 != tmp.end()) { 00478 00479 double x, y; 00480 x = y = -1; 00481 // if both lines do not intersect each other in the image 00482 // and current lines are not in a horizontal direction, add to output vector 00483 if((!lines[i].intersects(*iter2, x, y) && !img.coordsOk((int)x, (int)y)) && 00484 lines[i].intersects(border2, x, y) && lines[i].intersects(border3, x, y)) { 00485 00486 drawLine(img, (*iter2).point1(), (*iter2).point2(), PixRGB<byte>(0,255,0)); 00487 frontLines.push_back(*iter2); 00488 tmp.erase(iter2); 00489 moreThanOne = true; 00490 00491 00492 } 00493 else 00494 iter2++; 00495 } 00496 00497 // if we found parallel lines, 00498 // make sure we add the line we were checking against 00499 if(moreThanOne && tmp.size() > i) { 00500 iter2 = tmp.begin() + i; 00501 drawLine(img, (*iter2).point1(), (*iter2).point2(), PixRGB<byte>(0,255,200)); 00502 frontLines.push_back(*iter2); 00503 tmp.erase(iter2); 00504 } 00505 } 00506 00507 // get intersections 00508 printf("size of frontLines before adding intersections: %d\n", (int)frontLines.size()); 00509 uint size = frontLines.size(); 00510 iter2 = tmp.begin(); 00511 for(uint i = 0; i < size; i++) { 00512 iter2 = tmp.begin(); 00513 while(tmp.size() > 0 && iter2 != tmp.end()) { 00514 00515 double x, y; 00516 x = y = -1; 00517 if(frontLines[i].intersects(*iter2, x, y) && img.coordsOk((int)x, (int)y)) { 00518 frontLines.push_back(*iter2); 00519 tmp.erase(iter2); 00520 } 00521 else 00522 iter2++; 00523 } 00524 } 00525 00526 00527 printf("size of frontLines: %d\n", (int)frontLines.size()); 00528 } 00529 00530 void BeoSubBin::getBinCenter(std::vector<BinAngles>& angles, Point2D<int>& center) { 00531 00532 for(uint i = 0; i < angles.size(); i++) 00533 center += angles[i].pos; 00534 00535 center /= angles.size(); 00536 } 00537 00538 // ###################################################################### 00539 /* So things look consistent in everyone's emacs... */ 00540 /* Local Variables: */ 00541 /* indent-tabs-mode: nil */ 00542 /* End: */