00001 /*! @file ObjRec/test-envObjRec.C test various obj rec alg */ 00002 00003 // //////////////////////////////////////////////////////////////////// // 00004 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2000-2005 // 00005 // by the University of Southern California (USC) and the iLab at USC. // 00006 // See http://iLab.usc.edu for information about this project. // 00007 // //////////////////////////////////////////////////////////////////// // 00008 // Major portions of the iLab Neuromorphic Vision Toolkit are protected // 00009 // under the U.S. patent ``Computation of Intrinsic Perceptual Saliency // 00010 // in Visual Environments, and Applications'' by Christof Koch and // 00011 // Laurent Itti, California Institute of Technology, 2001 (patent // 00012 // pending; application number 09/912,225 filed July 23, 2001; see // 00013 // http://pair.uspto.gov/cgi-bin/final/home.pl for current status). // 00014 // //////////////////////////////////////////////////////////////////// // 00015 // This file is part of the iLab Neuromorphic Vision C++ Toolkit. // 00016 // // 00017 // The iLab Neuromorphic Vision C++ Toolkit is free software; you can // 00018 // redistribute it and/or modify it under the terms of the GNU General // 00019 // Public License as published by the Free Software Foundation; either // 00020 // version 2 of the License, or (at your option) any later version. // 00021 // // 00022 // The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope // 00023 // that it will be useful, but WITHOUT ANY WARRANTY; without even the // 00024 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // 00025 // PURPOSE. See the GNU General Public License for more details. // 00026 // // 00027 // You should have received a copy of the GNU General Public License // 00028 // along with the iLab Neuromorphic Vision C++ Toolkit; if not, write // 00029 // to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, // 00030 // Boston, MA 02111-1307 USA. // 00031 // //////////////////////////////////////////////////////////////////// // 00032 // 00033 // Primary maintainer for this file: Lior Elazary <elazary@usc.edu> 00034 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/ObjRec/test-envObjRec.C $ 00035 // $Id: test-envObjRec.C 13716 2010-07-28 22:07:03Z itti $ 00036 // 00037 00038 00039 #include "Image/OpenCVUtil.H" 00040 #include "Component/ModelManager.H" 00041 #include "Image/Image.H" 00042 #include "Image/ImageSet.H" 00043 #include "Image/ShapeOps.H" 00044 #include "Image/CutPaste.H" 00045 #include "Image/DrawOps.H" 00046 #include "Image/FilterOps.H" 00047 #include "Image/ColorOps.H" 00048 #include "Image/Transforms.H" 00049 #include "Image/MathOps.H" 00050 #include "Image/fancynorm.H" 00051 #include "Transport/FrameInfo.H" 00052 #include "Raster/Raster.H" 00053 #include "Raster/GenericFrame.H" 00054 #include "GUI/DebugWin.H" 00055 #include "Neuro/EnvVisualCortex.H" 00056 #include "Media/FrameSeries.H" 00057 #include "Util/Timer.H" 00058 00059 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 00060 #define OPENCV_HOUGH 1 // opencv hough transform 00061 //#define SALIENCY_HOUGH 1 // opencv hough transform 00062 #define ORI_QUE 1 //use orientation que 00063 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 00064 ModelManager *mgr; 00065 00066 bool debug = 0; 00067 Timer timer; 00068 int smap_level = 0; 00069 00070 #define halfPi ((float)(CV_PI*0.5)) 00071 #define Pi ((float)CV_PI) 00072 #define a0 0 /*-4.172325e-7f*/ /*(-(float)0x7)/((float)0x1000000); */ 00073 #define a1 1.000025f /*((float)0x1922253)/((float)0x1000000)*2/Pi; */ 00074 #define a2 -2.652905e-4f /*(-(float)0x2ae6)/((float)0x1000000)*4/(Pi*Pi); */ 00075 #define a3 -0.165624f /*(-(float)0xa45511)/((float)0x1000000)*8/(Pi*Pi*Pi); */ 00076 #define a4 -1.964532e-3f /*(-(float)0x30fd3)/((float)0x1000000)*16/(Pi*Pi*Pi*Pi); */ 00077 #define a5 1.02575e-2f /*((float)0x191cac)/((float)0x1000000)*32/(Pi*Pi*Pi*Pi*Pi); */ 00078 #define a6 -9.580378e-4f /*(-(float)0x3af27)/((float)0x1000000)*64/(Pi*Pi*Pi*Pi*Pi*Pi); */ 00079 00080 #define _sin(x) ((((((a6*(x) + a5)*(x) + a4)*(x) + a3)*(x) + a2)*(x) + a1)*(x) + a0) 00081 #define _cos(x) _sin(halfPi - (x)) 00082 #define NUMANGLE 180 00083 float tabSin[NUMANGLE]; 00084 float tabCos[NUMANGLE]; 00085 00086 00087 void display(Image<PixRGB<byte> > &leftImg, 00088 const Image<PixRGB<byte> > &leftSmap, 00089 const Image<PixRGB<byte> > &hough, 00090 const Point2D<int> &leftWinner, 00091 const byte maxVal, 00092 const Point2D<int> &targetLoc, 00093 nub::ref<OutputFrameSeries> ofs); 00094 00095 00096 int biasProc(const char *tagName, 00097 env_size_t clev, 00098 env_size_t slev, 00099 struct env_image *cmap, 00100 const struct env_image *center, 00101 const struct env_image *surround) 00102 { 00103 //intg32* src = cmap->pixels; 00104 00105 ENV_SHOWIMG(cmap, 512, 512); 00106 00107 //uint foveaWidth = (FSIZE >> smap_level)/2; 00108 //uint foveaHeight = (FSIZE >> smap_level)/2; 00109 00110 //struct env_image *outImg = new struct env_image; 00111 // env_img_init(outImg, cmap->dims); 00112 //intg32* outSrc = outImg->pixels; 00113 00114 return 0; 00115 } 00116 00117 void putLine(Image<PixRGB<byte> > &img, float r, float m) 00118 { 00119 double a = cos(m), b = sin(m); 00120 double x0 = a*r, y0 = b*r; 00121 Point2D<int> p1(cvRound(x0 + 1000*(-b)), cvRound(y0 + 1000*(a))); 00122 Point2D<int> p2(cvRound(x0 - 1000*(-b)), cvRound(y0 - 1000*(a))); 00123 00124 drawLine(img, p1, p2, PixRGB<byte>(255,0,0)); 00125 00126 } 00127 00128 Image<float> houghTrans(const Image<float> &edge, const Image<float> &ori, 00129 const Image<float> &smap) 00130 { 00131 00132 int w = edge.getWidth(); 00133 int h = edge.getHeight(); 00134 float theta = CV_PI/180; 00135 int rho = 1; 00136 int numangle = int(CV_PI/theta); 00137 int numrho = int(((w+h)*2 +1) / rho); 00138 00139 Image<float> acc(numrho+2,numangle+2,ZEROS); //the accumulator 00140 00141 00142 Image<float>::const_iterator magPtr = edge.begin(); 00143 Image<float>::iterator accPtr = acc.beginw(); 00144 00145 #ifdef ORI_QUE 00146 Image<float>::const_iterator oriPtr = ori.begin(); 00147 #endif 00148 00149 for(int y=0; y<h; y++) 00150 for(int x=0; x<w; x++) 00151 { 00152 float val = magPtr[y*w+x]; 00153 if (val > 100) 00154 { 00155 int minOri = 0, maxOri = numangle; 00156 #ifdef ORI_QUE 00157 int oriQue = int((oriPtr[y*w+x]*180/M_PI)); 00158 if (oriQue < 0) oriQue += 180; 00159 00160 minOri = (oriQue - 25); if (minOri < 0) minOri = 0; 00161 maxOri = (oriQue + 25); if (maxOri > numangle) maxOri = numangle-1; 00162 #endif 00163 00164 for(int m=minOri; m<maxOri; m++) 00165 { 00166 int r = int(x*tabCos[m] + y*tabSin[m]); 00167 r += (numrho -1) /2; 00168 accPtr[(m+1) * (numrho+2) + r+1] += val; 00169 } 00170 } 00171 } 00172 00173 return acc; 00174 00175 } 00176 00177 Image<PixRGB<byte> > showHough(const Image<float> &acc, const Image<float> &mag) 00178 { 00179 00180 Image<float> tmpAcc = acc; //(acc.getDims(), ZEROS); 00181 Image<PixRGB<byte> > retImg = mag; 00182 // int thresh = 1; 00183 int numrho = acc.getWidth()-2; 00184 // int numangle = acc.getHeight()-2; 00185 00186 Point2D<int> maxPos; 00187 float maxVal; 00188 00189 /*//Image<float>::const_iterator accPtr = acc.begin(); 00190 //find local maximums 00191 for(int r=0; r<numrho; r++) 00192 for(int m=0; m<numangle; m++) 00193 { 00194 int base = (m+1)* (numrho+2) + r+1; 00195 if (acc[base] > thresh && 00196 acc[base] > acc[base-1] && acc[base] >= acc[base+1] && 00197 acc[base] > acc[base - numrho - 2] && acc[base] >= acc[base + numrho + 2]) 00198 { 00199 tmpAcc[base] = acc[base]; 00200 //float rho = (r - (numrho - 1)*0.5f); 00201 //float theta = (m * CV_PI/180); 00202 //printf("Base %f\n", acc[base]); 00203 //putLine(retImg, rho, theta); 00204 00205 } 00206 } 00207 */ 00208 00209 for(int i=0; i<10; i++) 00210 { 00211 findMax(tmpAcc, maxPos, maxVal); 00212 int r = maxPos.i; 00213 int m = maxPos.j; 00214 float rho = (r - (numrho - 1)*0.5f); 00215 float theta = (m * CV_PI/180); 00216 putLine(retImg, rho, theta); 00217 00218 drawDisk(tmpAcc, Point2D<int>(r,m), 5 , float(0)); //IOR 00219 // SHOWIMG(tmpAcc); 00220 // SHOWIMG(retImg); 00221 } 00222 00223 00224 return retImg; 00225 } 00226 00227 float w (float *p, int k) 00228 { 00229 int i; 00230 float x=0.0; 00231 00232 for (i=1; i<=k; i++) x += p[i]; 00233 return x; 00234 } 00235 00236 float u (float *p, int k) 00237 { 00238 int i; 00239 float x=0.0; 00240 00241 for (i=1; i<=k; i++) x += (float)i*p[i]; 00242 return x; 00243 } 00244 00245 float nu (float *p, int k, float ut, float vt) 00246 { 00247 float x, y; 00248 00249 y = w(p,k); 00250 x = ut*y - u(p,k); 00251 x = x*x; 00252 y = y*(1.0-y); 00253 if (y>0) x = x/y; 00254 else x = 0.0; 00255 return x/vt; 00256 } 00257 00258 00259 Image<float> segmentProb(const Image<float> &img) 00260 { 00261 Image<float> retImg = img; 00262 int hist[260]; 00263 float p[260]; 00264 00265 inplaceNormalize(retImg, 0.0F, 255.0F); 00266 00267 for(int i=0; i<260; i++) 00268 { 00269 hist[i] = 0; //set histogram to 0 00270 p[i] = 0; //set prob to 0 00271 } 00272 00273 for (int y=0; y<retImg.getHeight(); y++) 00274 for(int x=0; x<retImg.getWidth(); x++) 00275 { 00276 int val = (int)retImg.getVal(x,y); 00277 hist[val+1]++; 00278 } 00279 00280 //nomalize into a distribution 00281 for (int i=1; i<=256; i++) 00282 p[i] = (float)hist[i]/(float)retImg.getSize(); 00283 00284 //find the global mean 00285 float ut = 0.0; 00286 for(int i=1; i<=256; i++) 00287 ut += (float)i*p[i]; 00288 00289 //find the global variance 00290 float vt = 0.0; 00291 for(int i=1; i<=256; i++) 00292 vt += (i-ut)*(i-ut)*p[i]; 00293 00294 int j=-1, k=-1; 00295 for(int i=1; i<=256; i++) 00296 { 00297 if ((j<0) && (p[i] > 0.0)) j = i; //first index 00298 if (p[i] > 0.0) k = i; //last index 00299 } 00300 00301 float z = -1.0; 00302 int m = -1; 00303 for (int i=j; i<=k; i++) 00304 { 00305 float y = nu(p,i,ut,vt); //compute nu 00306 00307 if (y>=z) 00308 { 00309 z = y; 00310 m = i; 00311 } 00312 } 00313 00314 int t = m; 00315 00316 if (t < 0) 00317 LINFO("ERROR"); 00318 else 00319 LINFO("THreshold is %i", t); 00320 00321 //threshold 00322 for (int y=0; y<retImg.getHeight(); y++) 00323 for(int x=0; x<retImg.getWidth(); x++) 00324 { 00325 int val = (int)retImg.getVal(x,y); 00326 if (val < t) 00327 retImg.setVal(x,y,0); 00328 else 00329 retImg.setVal(x,y,255.0); 00330 00331 } 00332 00333 00334 return retImg; 00335 } 00336 00337 float entropy (float *h, int a, float p) 00338 { 00339 if (h[a] > 0.0 && p>0.0) 00340 return -(h[a]/p * (float)log((double)(h[a])/p)); 00341 return 0.0; 00342 } 00343 00344 00345 Image<float> segment(const Image<float> &img) 00346 { 00347 Image<float> retImg = img; 00348 float hist[300]; 00349 float pt[300]; 00350 float F[300]; 00351 00352 inplaceNormalize(retImg, 0.0F, 255.0F); 00353 00354 for(int i=0; i<256; i++) 00355 { 00356 hist[i] = 0; //set histogram to 0 00357 pt[i] = 0; //set prob to 0 00358 } 00359 00360 for (int y=0; y<retImg.getHeight(); y++) 00361 for(int x=0; x<retImg.getWidth(); x++) 00362 { 00363 int val = (int)retImg.getVal(x,y); 00364 hist[val]++; 00365 } 00366 00367 //nomalize into a distribution 00368 for (int i=0; i<256; i++) 00369 hist[i] = (float)hist[i]/(float)retImg.getSize(); 00370 00371 //compute factors 00372 pt[0] = hist[0]; 00373 for(int i=1; i<256; i++) 00374 pt[i] = pt[i-1] + hist[i]; 00375 00376 int t = -1; 00377 00378 for(int i=0; i<256; i++) 00379 { 00380 float Hb = 0, Hw = 0; 00381 for(int j=0; j<256; j++) 00382 if (j<=i) 00383 Hb += entropy(hist, j, pt[i]); 00384 else 00385 Hw += entropy(hist, j, 1.0-pt[i]); 00386 F[i] = Hb+Hw; 00387 if (i>0 && F[i] > F[t]) t = i; 00388 } 00389 if (t < 0) 00390 LINFO("ERROR"); 00391 else 00392 LINFO("THreshold is %i", t); 00393 00394 //threshold 00395 for (int y=0; y<retImg.getHeight(); y++) 00396 for(int x=0; x<retImg.getWidth(); x++) 00397 { 00398 int val = (int)retImg.getVal(x,y); 00399 if (val < t) 00400 retImg.setVal(x,y,0); 00401 else 00402 retImg.setVal(x,y,255.0); 00403 00404 } 00405 00406 00407 return retImg; 00408 } 00409 00410 00411 00412 int main(const int argc, const char **argv) 00413 { 00414 00415 MYLOGVERB = LOG_INFO; 00416 mgr = new ModelManager("Test ObjRec"); 00417 00418 nub::ref<InputFrameSeries> ifs(new InputFrameSeries(*mgr)); 00419 mgr->addSubComponent(ifs); 00420 00421 nub::ref<OutputFrameSeries> ofs(new OutputFrameSeries(*mgr)); 00422 mgr->addSubComponent(ofs); 00423 00424 nub::ref<EnvVisualCortex> evc(new EnvVisualCortex(*mgr)); 00425 mgr->addSubComponent(evc); 00426 00427 mgr->exportOptions(MC_RECURSE); 00428 //mgr->setOptionValString(&OPT_EvcMaxnormType, "None"); 00429 //mgr->setOptionValString(&OPT_EvcLevelSpec, "0,2,5,6,0"); 00430 //mgr->setOptionValString(&OPT_EvcLevelSpec, "0,4,1,4,0"); 00431 //mgr->setOptionValString(&OPT_EvcLevelSpec, "0,2,3,4,2"); 00432 //mgr->setOptionValString(&OPT_EvcLevelSpec, "0,1,8,8,0"); 00433 00434 00435 //evc->setIweight(0); 00436 evc->setFweight(0); 00437 evc->setMweight(0); 00438 evc->setCweight(0); 00439 evc->setOweight(0); 00440 00441 if (mgr->parseCommandLine( 00442 (const int)argc, (const char**)argv, "image", 0, 0) == false) 00443 return 1; 00444 00445 mgr->start(); 00446 00447 // do post-command-line configs: 00448 00449 //start streaming 00450 ifs->startStream(); 00451 00452 //build the sin/cos tables 00453 float ang; 00454 int i; 00455 for(ang =0,i=0; i < 180; ang += CV_PI/180, i++) 00456 { 00457 tabSin[i] = (float)(sin(ang)); 00458 tabCos[i] = (float)(cos(ang)); 00459 } 00460 00461 while(1) 00462 { 00463 Image< PixRGB<byte> > inputImg; 00464 const FrameState is = ifs->updateNext(); 00465 LINFO("Frame %i\n", ifs->frame()); 00466 if (is == FRAME_COMPLETE) 00467 break; 00468 00469 //grab the images 00470 GenericFrame input = ifs->readFrame(); 00471 if (!input.initialized()) 00472 break; 00473 inputImg = input.asRgb(); 00474 00475 int fw = 100; 00476 Image<PixRGB<byte> > fimg = crop(inputImg, 00477 Point2D<int>((inputImg.getWidth()/2)-(fw/2), (inputImg.getHeight()/2)-(fw/2)), Dims(fw,fw)); 00478 // SHOWIMG(rescale(inputImg, 512, 512)); 00479 00480 //evc->setSubmapPostNormProc(&biasProc); 00481 //evc->setSubmapPreProc(&biasProc); 00482 //evc->setSubmapPostProc(NULL); 00483 00484 fimg = rescale(fimg, inputImg.getDims()); 00485 evc->input(fimg); 00486 00487 Image<float> vcxMap = evc->getVCXmap(); 00488 Image<float> lum = luminance(fimg); 00489 00490 00491 vcxMap = rescale(vcxMap, inputImg.getDims()); 00492 lum = rescale(lum, inputImg.getDims()); 00493 00494 Image<float> mag, ori; 00495 gradientSobel(lum, mag, ori, 3); 00496 //inplaceNormalize(vcxMap, 0.0F, 255.0F); 00497 //inplaceNormalize(mag, 0.0F, 255.0F); 00498 mag = (vcxMap); 00499 00500 00501 Image<float> seg = segment(mag); 00502 00503 gradientSobel(lum, mag, ori, 3); 00504 lum =mag; 00505 00506 Image<PixRGB<byte> > salHoughDisp; 00507 Image<PixRGB<byte> > opencvHoughDisp; 00508 00509 //calculate the hough 00510 Image<float> acc = houghTrans(mag, ori, vcxMap); 00511 00512 //show the lines 00513 salHoughDisp = showHough(acc, mag); 00514 00515 00516 00517 #ifdef SALIENCY_HOUGH 00518 Image<float> mag, ori; 00519 gradientSobel(vcxMap, mag, ori, 3); 00520 mag *= vcxMap; //weight the orientations by the saliency 00521 inplaceNormalize(mag, 0.0F, 255.0F); 00522 00523 //calculate the hough 00524 Image<float> acc = houghTrans(mag, ori, vcxMap); 00525 00526 //show the lines 00527 salHoughDisp = showHough(acc, mag); 00528 #endif 00529 00530 #ifdef OPENCV_HOUGH 00531 00532 //Opencv hough 00533 inplaceNormalize(lum, 0.0F, 255.0F); 00534 CvMemStorage* storage = cvCreateMemStorage(0); 00535 IplImage *dst = cvCreateImage( cvGetSize(img2ipl(lum)), 8, 1 ); 00536 cvCanny( img2ipl((Image<byte>)lum), dst, 150, 200, 3 ); 00537 00538 Image<float> edge = ipl2float(dst); 00539 opencvHoughDisp = edge; 00540 00541 /*CvSeq *lines = cvHoughLines2(dst, storage, CV_HOUGH_STANDARD, 1, CV_PI/180, 50 , 0, 0); 00542 00543 for(int i = 0; i < MIN(lines->total,10); i++ ) 00544 { 00545 ccb 00546 float rho = line[0]; 00547 float theta = line[1]; 00548 CvPoint pt1, pt2; 00549 double a = cos(theta), b = sin(theta); 00550 double x0 = a*rho, y0 = b*rho; 00551 pt1.x = cvRound(x0 + 1000*(-b)); 00552 pt1.y = cvRound(y0 + 1000*(a)); 00553 pt2.x = cvRound(x0 - 1000*(-b)); 00554 pt2.y = cvRound(y0 - 1000*(a)); 00555 00556 drawLine(opencvHoughDisp, Point2D<int>(pt1.x,pt1.y), Point2D<int>(pt2.x, pt2.y), PixRGB<byte>(255,0,0)); 00557 }*/ 00558 00559 00560 CvSeq *lines = cvHoughLines2( dst, storage, CV_HOUGH_PROBABILISTIC, 1, CV_PI/180, 10, 5, 1 ); 00561 for( i = 0; i < lines->total; i++ ) 00562 { 00563 CvPoint* line = (CvPoint*)cvGetSeqElem(lines,i); 00564 drawLine(opencvHoughDisp, Point2D<int>(line[0].x,line[0].y), Point2D<int>(line[1].x, line[1].y), PixRGB<byte>(255,0,0)); 00565 } 00566 00567 #endif 00568 00569 00570 display(inputImg, vcxMap, lum, Point2D<int>(-1, -1), 2, Point2D<int>(-1, -1), ofs); 00571 00572 00573 } 00574 00575 00576 00577 // stop all our ModelComponents 00578 mgr->stop(); 00579 00580 return 0; 00581 00582 } 00583 00584 00585 void display(Image<PixRGB<byte> > &leftImg, 00586 const Image<PixRGB<byte> > &leftSmap, 00587 const Image<PixRGB<byte> > &hough, 00588 const Point2D<int> &leftWinner, 00589 const byte maxVal, 00590 const Point2D<int> &targetLoc, 00591 nub::ref<OutputFrameSeries> ofs) 00592 { 00593 static int avgn = 0; 00594 static uint64 avgtime = 0; 00595 static double fps = 0; 00596 char msg[255]; 00597 00598 Image<PixRGB<byte> > outDisp(leftImg.getWidth()*2,leftImg.getHeight()*2+20, ZEROS); 00599 00600 00601 //Left Image 00602 inplacePaste(outDisp, leftImg, Point2D<int>(0,0)); 00603 inplacePaste(outDisp, leftSmap, Point2D<int>(0,leftImg.getHeight())); 00604 inplacePaste(outDisp, hough, Point2D<int>(leftImg.getWidth(),leftImg.getHeight())); 00605 00606 00607 //calculate fps 00608 avgn++; 00609 avgtime += timer.getReset(); 00610 if (avgn == 20) 00611 { 00612 fps = 1000.0F / double(avgtime) * double(avgn); 00613 avgtime = 0; 00614 avgn = 0; 00615 } 00616 00617 sprintf(msg, "%.1ffps ", fps); 00618 00619 Image<PixRGB<byte> > infoImg(leftImg.getWidth()*2, 20, NO_INIT); 00620 writeText(infoImg, Point2D<int>(0,0), msg, 00621 PixRGB<byte>(255), PixRGB<byte>(127)); 00622 inplacePaste(outDisp, infoImg, Point2D<int>(0,leftImg.getHeight()*2)); 00623 00624 ofs->writeRGB(outDisp, "output", FrameInfo("output", SRC_POS)); 00625 } 00626 00627