00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038 #include "Image/OpenCVUtil.H"
00039
00040 #include "Neuro/EnvSegmenterCannyContour.H"
00041
00042 #include "Image/CutPaste.H"
00043 #include "Image/DrawOps.H"
00044 #include "Image/Image.H"
00045 #include "Image/Pixels.H"
00046 #include "GUI/DebugWin.H"
00047
00048 #ifdef HAVE_OPENCV
00049
00050 namespace
00051 {
00052 const int thresh = 50;
00053
00054
00055
00056
00057 double angle( CvPoint* pt1, CvPoint* pt2, CvPoint* pt0 )
00058 {
00059 double dx1 = pt1->x - pt0->x;
00060 double dy1 = pt1->y - pt0->y;
00061 double dx2 = pt2->x - pt0->x;
00062 double dy2 = pt2->y - pt0->y;
00063 return (dx1*dx2 + dy1*dy2)/sqrt((dx1*dx1 + dy1*dy1)*(dx2*dx2 + dy2*dy2) + 1e-10);
00064 }
00065
00066 CvSeq* findSquares(const Image<PixRGB<byte> >& in, CvMemStorage* storage,
00067 const int minarea, const int maxarea, const double mincos)
00068 {
00069 const int N = 11;
00070
00071 IplImage* img = img2ipl(in);
00072
00073 CvSize sz = cvSize( img->width & -2, img->height & -2 );
00074 IplImage* timg = cvCloneImage( img );
00075 IplImage* gray = cvCreateImage( sz, 8, 1 );
00076 IplImage* pyr = cvCreateImage( cvSize(sz.width/2, sz.height/2), 8, 3 );
00077
00078
00079 CvSeq* squares = cvCreateSeq( 0, sizeof(CvSeq), sizeof(CvPoint), storage );
00080
00081
00082
00083 cvSetImageROI( timg, cvRect( 0, 0, sz.width, sz.height ));
00084
00085
00086 cvPyrDown( timg, pyr, 7 );
00087 cvPyrUp( pyr, timg, 7 );
00088 IplImage* tgray = cvCreateImage( sz, 8, 1 );
00089
00090
00091 for (int c = 0; c < 3; ++c)
00092 {
00093
00094 cvSetImageCOI( timg, c+1 );
00095 cvCopy( timg, tgray, 0 );
00096
00097
00098 for (int l = 0; l < N; ++l)
00099 {
00100
00101
00102 if( l == 0 )
00103 {
00104
00105
00106 cvCanny( tgray, gray, 0, thresh, 5 );
00107
00108
00109 cvDilate( gray, gray, 0, 1 );
00110 }
00111 else
00112 {
00113
00114
00115 cvThreshold( tgray, gray, (l+1)*255/N, 255, CV_THRESH_BINARY );
00116 }
00117
00118
00119 CvSeq* contours = 0;
00120 cvFindContours( gray, storage, &contours, sizeof(CvContour),
00121 CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE, cvPoint(0,0) );
00122
00123
00124 while( contours )
00125 {
00126
00127
00128 CvSeq* result =
00129 cvApproxPoly( contours, sizeof(CvContour), storage,
00130 CV_POLY_APPROX_DP, cvContourPerimeter(contours)*0.02, 0 );
00131
00132
00133
00134
00135
00136
00137 const double area = fabs(cvContourArea(result,CV_WHOLE_SEQ));
00138 if (result->total == 4 &&
00139 area >= minarea && area <= maxarea &&
00140 cvCheckContourConvexity(result))
00141 {
00142 double s = 0;
00143
00144 for (int i = 0; i < 4; ++i)
00145 {
00146
00147
00148 const double t =
00149 fabs(angle((CvPoint*)cvGetSeqElem( result, i % 4 ),
00150 (CvPoint*)cvGetSeqElem( result, (i-2) % 4 ),
00151 (CvPoint*)cvGetSeqElem( result, (i-1) % 4 )));
00152 s = s > t ? s : t;
00153 }
00154
00155
00156
00157
00158
00159 if (s < mincos)
00160 {
00161 for (int i = 0; i < 4; ++i)
00162 cvSeqPush(squares,
00163 (CvPoint*)cvGetSeqElem( result, i ));
00164
00165 }
00166 }
00167
00168
00169 contours = contours->h_next;
00170 }
00171 }
00172 }
00173
00174
00175 cvReleaseImage( &gray );
00176 cvReleaseImage( &pyr );
00177 cvReleaseImage( &tgray );
00178 cvReleaseImage( &timg );
00179 cvReleaseImageHeader( &img );
00180
00181 return squares;
00182 }
00183
00184
00185 Image<PixRGB<byte> > drawSquares(const Image<PixRGB<byte> >&in, CvSeq* squares)
00186 {
00187 Image<PixRGB<byte> > out(in);
00188
00189 CvSeqReader reader;
00190
00191
00192 cvStartReadSeq(squares, &reader, 0);
00193
00194
00195 for (int i = 0; i < squares->total; i += 4)
00196 {
00197 CvPoint pt[4];
00198
00199
00200 CV_READ_SEQ_ELEM( pt[0], reader );
00201 CV_READ_SEQ_ELEM( pt[1], reader );
00202 CV_READ_SEQ_ELEM( pt[2], reader );
00203 CV_READ_SEQ_ELEM( pt[3], reader );
00204
00205 for (int j = 0; j < 4; ++j)
00206 drawLine(out,
00207 Point2D<int>(pt[j].x, pt[j].y),
00208 Point2D<int>(pt[(j+1)%4].x, pt[(j+1)%4].y),
00209 PixRGB<byte>(0, 255, 0),
00210 2);
00211 }
00212
00213 return out;
00214 }
00215
00216 Rectangle getRectangle(CvSeq* cards)
00217 {
00218 CvSeqReader reader;
00219
00220 cvStartReadSeq( cards, &reader, 0 );
00221
00222 Rectangle result;
00223
00224 if (cards->total > 0)
00225 {
00226 CvPoint pt[4];
00227
00228 CV_READ_SEQ_ELEM( pt[0], reader );
00229 CV_READ_SEQ_ELEM( pt[1], reader );
00230 CV_READ_SEQ_ELEM( pt[2], reader );
00231 CV_READ_SEQ_ELEM( pt[3], reader );
00232
00233
00234 Point2D<int> tl(pt[0].x, pt[0].y), br(pt[0].x, pt[0].y);
00235 for(int i=1; i<4; i++)
00236 {
00237 if (pt[i].x < tl.i) tl.i = pt[i].x;
00238 else if (pt[i].x > br.i) br.i = pt[i].x;
00239
00240 if (pt[i].y < tl.j) tl.j = pt[i].y;
00241 else if (pt[i].y > br.j) br.j = pt[i].y;
00242 }
00243 tl.i -= 10; tl.j -= 10;
00244 br.i += 10; br.j += 10;
00245
00246 result = Rectangle::tlbrO(tl.j, tl.i, br.j, br.i);
00247 }
00248
00249 return result;
00250 }
00251 }
00252
00253 #endif //HAVE_OPENCV
00254
00255
00256 EnvSegmenterCannyContour::EnvSegmenterCannyContour(OptionManager& mgr)
00257 :
00258 EnvSegmenter(mgr, "Embeddable Canny Contour FOA Segmenter",
00259 "EnvSegmenterCannyContour"),
00260 itsMinArea("CannyMinArea", this, 500, ALLOW_ONLINE_CHANGES),
00261 itsMaxArea("CannyMaxArea", this, 7000, ALLOW_ONLINE_CHANGES),
00262 itsMinCos("CannyMinCos", this, 0.1, ALLOW_ONLINE_CHANGES)
00263 #ifdef HAVE_OPENCV
00264 ,
00265 itsStorage(cvCreateMemStorage(0))
00266 #endif
00267 {
00268 #ifndef HAVE_OPENCV
00269 LFATAL("OpenCV must be installed in order to use this function");
00270 #else
00271 ASSERT(itsStorage != 0);
00272 #endif
00273 }
00274
00275
00276 EnvSegmenterCannyContour::~EnvSegmenterCannyContour()
00277 {
00278 #ifndef HAVE_OPENCV
00279 LERROR("OpenCV must be installed in order to use this function");
00280 #else
00281 cvReleaseMemStorage(&itsStorage);
00282 #endif
00283 }
00284
00285
00286 Rectangle EnvSegmenterCannyContour::getFoa(const Image<PixRGB<byte> >& rgbin,
00287 const Point2D<int>& center,
00288 Image<byte>* foamask,
00289 Image<PixRGB<byte> >* segmentdisp) const
00290 {
00291 #ifndef HAVE_OPENCV
00292 LFATAL("OpenCV must be installed in order to use this function");
00293 return Rectangle();
00294 #else
00295
00296 CvSeq* cards = findSquares(rgbin, itsStorage, itsMinArea.getVal(), itsMaxArea.getVal(), itsMinCos.getVal());
00297
00298 const Rectangle result = getRectangle(cards);
00299
00300 const Image<PixRGB<byte> > out = drawSquares(rgbin, cards);
00301
00302 if (foamask)
00303 {
00304 *foamask = Image<byte>(rgbin.getDims(), ZEROS);
00305
00306 if (result.isValid())
00307 inplaceClearRegion(*foamask, result, byte(255));
00308 else
00309 foamask->setVal(center, 255);
00310 }
00311
00312 if (segmentdisp)
00313 *segmentdisp = out;
00314
00315 cvClearMemStorage(itsStorage);
00316
00317 return result.getOverlap(rgbin.getBounds());
00318 #endif
00319 }
00320
00321
00322 std::vector<Rectangle> EnvSegmenterCannyContour::getSquares(const Image<PixRGB<byte> >& rgbin, Image<PixRGB<byte> >* segmentDisp)
00323 {
00324 #ifndef HAVE_OPENCV
00325 LFATAL("OpenCV must be installed in order to use this function");
00326 return std::vector<Rectangle>();
00327 #else
00328
00329 CvSeq* squares = findSquares(rgbin, itsStorage, itsMinArea.getVal(), itsMaxArea.getVal(), itsMinCos.getVal());
00330
00331
00332 if (segmentDisp)
00333 *segmentDisp = drawSquares(rgbin, squares);
00334
00335
00336 std::vector<Rectangle> results;
00337
00338
00339 CvSeqReader reader;
00340
00341 cvStartReadSeq(squares, &reader, 0);
00342
00343
00344 for (int i = 0; i < squares->total; i += 4)
00345 {
00346 CvPoint pt[4];
00347
00348
00349 CV_READ_SEQ_ELEM( pt[0], reader );
00350 CV_READ_SEQ_ELEM( pt[1], reader );
00351 CV_READ_SEQ_ELEM( pt[2], reader );
00352 CV_READ_SEQ_ELEM( pt[3], reader );
00353
00354
00355 Point2D<int> tl(pt[0].x, pt[0].y), br(pt[0].x, pt[0].y);
00356 for(int i=1; i<4; i++)
00357 {
00358 if (pt[i].x < tl.i) tl.i = pt[i].x;
00359 else if (pt[i].x > br.i) br.i = pt[i].x;
00360
00361 if (pt[i].y < tl.j) tl.j = pt[i].y;
00362 else if (pt[i].y > br.j) br.j = pt[i].y;
00363 }
00364 tl.i -= 10; tl.j -= 10;
00365 br.i += 10; br.j += 10;
00366 Rectangle rect = Rectangle::tlbrO(tl.j, tl.i, br.j, br.i);
00367 results.push_back(rect.getOverlap(rgbin.getBounds()));
00368 }
00369
00370 cvClearMemStorage(itsStorage);
00371
00372 return results;
00373 #endif
00374 }
00375
00376
00377
00378
00379
00380
00381