Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p><code>cvConvexityDefects</code> expects the <code>convexHull</code> sequence (second argument) to contain indices into the <code>contour</code> sequence (first argument):</p> <blockquote> <p>Convex hull obtained using ConvexHull2 that should contain pointers or indices to the contour points, not the hull points themselves </p> </blockquote> <ol> <li><p>In the most trivial case, where <code>cvFindContours</code> returns a single simple contour (your second image) you got lucky and your code would supply the correct sequence as the first parameter. </p></li> <li><p>In case <code>cvFindContours</code> finds holes in the contour (your third image), or if there are several simple contours or contours with holes (your first image) your code:</p> <ol> <li><p>finds a convex hull of each contour in turn, but only remembers the last one (since each iteration of the loop overwrites <code>retHulls</code> variable)</p></li> <li><p>passes the whole hierarchy of the contours, which doesn't correspond to indices in <code>retHulls</code>, to <code>cvConvexityDefects</code> as the first argument. </p></li> </ol></li> </ol> <p>Instead, you should have:</p> <ol> <li><p>passed <code>CV_RETR_EXTERNAL</code> to the <code>cvFindContour</code> to only get the outer contours (you don't care for defects of holes)</p></li> <li><p>moved the <code>cvConvexityDefects</code> inside the last loop. </p></li> </ol> <p>Something like:</p> <pre><code> /* ... */ if (argc &lt; 2) { std::cerr &lt;&lt; "Usage: convexity IMAGE\n"; exit(1); } cvNamedWindow( "original", 1 ); cvNamedWindow( "contours", 1 ); cvNamedWindow( "hull", 1 ); IplImage* original_img = NULL; original_img = cvLoadImage(argv[1], CV_LOAD_IMAGE_GRAYSCALE ); IplImage* img_edge = cvCreateImage( cvGetSize(original_img), 8, 1 ); IplImage* contour_img = cvCreateImage( cvGetSize(original_img), 8, 3 ); IplImage* hull_img = cvCreateImage( cvGetSize(original_img), 8, 3 ); cvThreshold( original_img, img_edge, 128, 255, CV_THRESH_BINARY ); CvMemStorage* storage = cvCreateMemStorage(); CvSeq* first_contour = NULL; int Nc = cvFindContours( img_edge, storage, &amp;first_contour, sizeof(CvContour), CV_RETR_EXTERNAL // Try all four values and see what happens ); cvCvtColor( original_img, contour_img, CV_GRAY2BGR ); for( CvSeq* c=first_contour; c!=NULL; c=c-&gt;h_next ) { cvDrawContours( contour_img, c, CVX_RED, CVX_BLUE, 0, 2, 8 ); } cvShowImage( "contours", contour_img ); //----------------------------------------------------------------------Convex Hull //-------------------------------------------------------------------Convex Defects CvMemStorage* hull_storage = cvCreateMemStorage(); CvSeq* retHulls = NULL; cvCvtColor( original_img, hull_img, CV_GRAY2BGR ); for(CvSeq* i = first_contour; i != NULL; i = i-&gt;h_next){ retHulls = cvConvexHull2(i,hull_storage,CV_CLOCKWISE,0); printf(" %d elements:\n", retHulls-&gt;total ); CvSeq* defect = NULL; defect = cvConvexityDefects(i,retHulls, NULL); // reuse storage of the contour printf(" %d defect:\n", defect-&gt;total ); // drawing hull.... you can't use the one returned above since it only // contains indices retHulls = cvConvexHull2(i,hull_storage,CV_CLOCKWISE,1); cvDrawContours( hull_img, retHulls, CVX_RED, CVX_BLUE, 0, 2, 8 ); } cvShowImage( "hull", hull_img ); /* ... */ </code></pre>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload