test-CVcontour.C

Go to the documentation of this file.
00001 /*!@file SeaBee/test-CVcontour.C test opencv contour function   */
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/test-CVcontour.C $
00034 // $Id: test-CVcontour.C 10794 2009-02-08 06:21:09Z itti $
00035 
00036 #include "Component/ModelManager.H"
00037 
00038 #include "Media/FrameSeries.H"
00039 #include "Transport/FrameIstream.H"
00040 #include "Transport/FrameInfo.H"
00041 #include "Media/MediaOpts.H"
00042 
00043 #include "Image/Image.H"
00044 #include "Image/Pixels.H"
00045 #include "Raster/Raster.H"
00046 #include "Image/CutPaste.H"
00047 #include "Image/OpenCVUtil.H"
00048 
00049 #include "BeoSub/IsolateColor.H"
00050 #include "Image/DrawOps.H"
00051 #include "Image/ColorOps.H"
00052 
00053 #include "GUI/XWinManaged.H"
00054 
00055 #ifndef HAVE_OPENCV
00056   LFATAL("OpenCV must be installed in order to use this function");
00057 #else
00058 
00059 int thresh = 50;
00060 
00061 // helper function:
00062 // finds a cosine of angle between vectors
00063 // from pt0->pt1 and from pt0->pt2
00064 double angle( CvPoint* pt1, CvPoint* pt2, CvPoint* pt0 )
00065 {
00066     double dx1 = pt1->x - pt0->x;
00067     double dy1 = pt1->y - pt0->y;
00068     double dx2 = pt2->x - pt0->x;
00069     double dy2 = pt2->y - pt0->y;
00070     return (dx1*dx2 + dy1*dy2)/sqrt((dx1*dx1 + dy1*dy1)*(dx2*dx2 + dy2*dy2) + 1e-10);
00071 }
00072 
00073 // returns sequence of squares detected on the image.
00074 // the sequence is stored in the specified memory storage
00075 CvSeq* findSquares4( IplImage* img, CvMemStorage* storage )
00076 {
00077     CvSeq* contours;
00078     int i, c, l, N = 11;
00079     CvSize sz = cvSize( img->width & -2, img->height & -2 );
00080     IplImage* timg = cvCloneImage( img ); // make a copy of input image
00081     IplImage* gray = cvCreateImage( sz, 8, 1 );
00082     IplImage* pyr = cvCreateImage( cvSize(sz.width/2, sz.height/2), 8, 3 );
00083     IplImage* tgray;
00084     CvSeq* result;
00085     double s, t;
00086     // create empty sequence that will contain points -
00087     // 4 points per square (the square's vertices)
00088     CvSeq* squares = cvCreateSeq( 0, sizeof(CvSeq), sizeof(CvPoint), storage );
00089 
00090     // select the maximum ROI in the image
00091     // with the width and height divisible by 2
00092     cvSetImageROI( timg, cvRect( 0, 0, sz.width, sz.height ));
00093 
00094     // down-scale and upscale the image to filter out the noise
00095     cvPyrDown( timg, pyr, 7 );
00096     cvPyrUp( pyr, timg, 7 );
00097     tgray = cvCreateImage( sz, 8, 1 );
00098 
00099     // find squares in every color plane of the image
00100     for( c = 0; c < 3; c++ )
00101     {
00102         // extract the c-th color plane
00103         cvSetImageCOI( timg, c+1 );
00104         cvCopy( timg, tgray, 0 );
00105 
00106         // try several threshold levels
00107         for( l = 0; l < N; l++ )
00108         {
00109             // hack: use Canny instead of zero threshold level.
00110             // Canny helps to catch squares with gradient shading
00111             if( l == 0 )
00112             {
00113                 // apply Canny. Take the upper threshold from slider
00114                 // and set the lower to 0 (which forces edges merging)
00115                 cvCanny( tgray, gray, 0, thresh, 5 );
00116                 // dilate canny output to remove potential
00117                 // holes between edge segments
00118                 cvDilate( gray, gray, 0, 1 );
00119             }
00120             else
00121             {
00122                 // apply threshold if l!=0:
00123                 //     tgray(x,y) = gray(x,y) < (l+1)*255/N ? 255 : 0
00124                 cvThreshold( tgray, gray, (l+1)*255/N, 255, CV_THRESH_BINARY );
00125             }
00126 
00127             // find contours and store them all as a list
00128             cvFindContours( gray, storage, &contours, sizeof(CvContour),
00129                 CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE, cvPoint(0,0) );
00130 
00131             // test each contour
00132             while( contours )
00133             {
00134                 // approximate contour with accuracy proportional
00135                 // to the contour perimeter
00136                 result = cvApproxPoly( contours, sizeof(CvContour), storage,
00137                     CV_POLY_APPROX_DP, cvContourPerimeter(contours)*0.02, 0 );
00138                 // square contours should have 4 vertices after approximation
00139                 // relatively large area (to filter out noisy contours)
00140                 // and be convex.
00141                 // Note: absolute value of an area is used because
00142                 // area may be positive or negative - in accordance with the
00143                 // contour orientation
00144                 if( result->total == 4 &&
00145                     fabs(cvContourArea(result,CV_WHOLE_SEQ)) > 1000 &&
00146                     cvCheckContourConvexity(result) )
00147                 {
00148                     s = 0;
00149 
00150                     for( i = 0; i < 5; i++ )
00151                     {
00152                         // find minimum angle between joint
00153                         // edges (maximum of cosine)
00154                         if( i >= 2 )
00155                         {
00156                             t = fabs(angle(
00157                             (CvPoint*)cvGetSeqElem( result, i ),
00158                             (CvPoint*)cvGetSeqElem( result, i-2 ),
00159                             (CvPoint*)cvGetSeqElem( result, i-1 )));
00160                             s = s > t ? s : t;
00161                         }
00162                     }
00163 
00164                     // if cosines of all angles are small
00165                     // (all angles are ~90 degree) then write quandrange
00166                     // vertices to resultant sequence
00167                     if( s < 0.3 )
00168                         for( i = 0; i < 4; i++ )
00169                             cvSeqPush( squares,
00170                                 (CvPoint*)cvGetSeqElem( result, i ));
00171                 }
00172 
00173                 // take the next contour
00174                 contours = contours->h_next;
00175             }
00176         }
00177     }
00178 
00179     // release all the temporary images
00180     cvReleaseImage( &gray );
00181     cvReleaseImage( &pyr );
00182     cvReleaseImage( &tgray );
00183     cvReleaseImage( &timg );
00184 
00185     return squares;
00186 }
00187 
00188 
00189 // the function draws all the squares in the image
00190 void drawSquares( IplImage* img, IplImage* out, CvSeq* squares )
00191 {
00192     CvSeqReader reader;
00193     int i;
00194 
00195     // initialize reader of the sequence
00196     cvStartReadSeq( squares, &reader, 0 );
00197 
00198     // read 4 sequence elements at a time (all vertices of a square)
00199     for( i = 0; i < squares->total; i += 4 )
00200     {
00201         CvPoint pt[4], *rect = pt;
00202         int count = 4;
00203 
00204         // read 4 vertices
00205         CV_READ_SEQ_ELEM( pt[0], reader );
00206         CV_READ_SEQ_ELEM( pt[1], reader );
00207         CV_READ_SEQ_ELEM( pt[2], reader );
00208         CV_READ_SEQ_ELEM( pt[3], reader );
00209 
00210         // draw the square as a closed polyline
00211         cvPolyLine( out, &rect, &count, 1, 1, CV_RGB(0,255,0), 3, CV_AA, 0 );
00212     }
00213 
00214 }
00215 
00216 int main(int argc, char* argv[])
00217 {
00218 
00219   MYLOGVERB = LOG_INFO;
00220 
00221   ModelManager manager("CVContour Tester");
00222 
00223   nub::soft_ref<InputFrameSeries> ifs(new InputFrameSeries(manager));
00224   manager.addSubComponent(ifs);
00225 
00226   nub::soft_ref<OutputFrameSeries> ofs(new OutputFrameSeries(manager));
00227   manager.addSubComponent(ofs);
00228 
00229   manager.exportOptions(MC_RECURSE);
00230 
00231   // Parse command-line:
00232   if (manager.parseCommandLine(argc, argv,
00233                                "[image {*.ppm}]",
00234                                0, 1)
00235       == false) return(1);
00236 
00237   int w = ifs->getWidth(),  h = ifs->getHeight();
00238   std::string dims = convertToString(Dims(w, h));
00239   LINFO("image size: [%dx%d]", w, h);
00240   manager.setOptionValString(&OPT_InputFrameDims, dims);
00241 
00242   manager.setModelParamVal("InputFrameDims", Dims(w, h),
00243                            MC_RECURSE | MC_IGNORE_MISSING);
00244 
00245   manager.start();
00246 
00247   bool goforever = true;
00248 
00249   rutz::shared_ptr<XWinManaged> dispWin;
00250   dispWin.reset(new XWinManaged(Dims(w*2,h*2), 0, 0, "Contour Display"));
00251 
00252   // input image
00253   Image< PixRGB<byte> > img(w,h, ZEROS);
00254 
00255 
00256   IplImage* iplImg = 0;
00257   IplImage* out = 0;
00258   CvMemStorage* storage = 0;
00259 
00260   bool createMovie = true;
00261 
00262   while(goforever)
00263     {
00264       Image< PixRGB<byte> > dispImg(w*2,h*2, ZEROS);
00265 
00266       ifs->updateNext(); img = ifs->readRGB();
00267       if(!img.initialized()) {Raster::waitForKey(); break; }
00268 
00269       // create memory storage that will contain all the dynamic data
00270       storage = cvCreateMemStorage(0);
00271 
00272       iplImg = cvCloneImage(  img2ipl(img) );
00273       out = cvCloneImage(  img2ipl(img) );
00274 
00275       // find and draw the squares
00276       drawSquares( iplImg, out, findSquares4( iplImg, storage ) );
00277 
00278       inplacePaste(dispImg, ipl2rgb(out), Point2D<int>(w,0));
00279       dispWin->drawImage(dispImg, 0, 0);
00280 
00281 
00282       if(createMovie)
00283         {
00284           ofs->writeRGB(ipl2rgb(out), "test-CVcontour_Display",
00285                         FrameInfo("test-CVcontour_Display", SRC_POS));
00286         }
00287 
00288       // wait for key.
00289       //      Raster::waitForKey();
00290 
00291       // release both images
00292       cvReleaseImage( &iplImg );
00293       cvReleaseImage( &out );
00294 
00295       // clear memory storage - reset free space position
00296       cvClearMemStorage( storage );
00297     }
00298 
00299   // get ready to terminate:
00300   manager.stop();
00301   return 0;
00302 }
00303 #endif // HAVE_OPENCV
00304 
00305 
00306 // ######################################################################
00307 /* So things look consistent in everyone's emacs... */
00308 /* Local Variables: */
00309 /* indent-tabs-mode: nil */
00310 /* End: */
Generated on Sun May 8 08:42:15 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3