问题
I have a program that calculates the convex hull of an image. I'm trying to use this information in order to count the number of fingers that are present in an input image. From some surfing I found out that the way to do this (count fingers) is by
- Finding contours
- Convex Hull
- Convexity defects
But I'm having trouble using the convexity defects function. It compiles fine but at runtime the program crashes with certain input images but not with others and I can't seem to figure out why.
These are the input images
- this image causes a crash
- but this does not.
- this also causes a crash even though its similar to the above
code..
#include <opencv/cv.h>
#include <opencv/highgui.h>
#include <opencv/cxcore.h>
#include <stdio.h>
#define CVX_RED CV_RGB(0xff,0x00,0x00)
#define CVX_GREEN CV_RGB(0x00,0xff,0x00)
#define CVX_BLUE CV_RGB(0x00,0x00,0xff)
int main(int argc, char* argv[]) {
cvNamedWindow( "original", 1 );
cvNamedWindow( "contours", 1 );
cvNamedWindow( "hull", 1 );
IplImage* original_img = NULL;
original_img = cvLoadImage("img.jpg", 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,
&first_contour,
sizeof(CvContour),
CV_RETR_LIST // Try all four values and see what happens
);
for( CvSeq* c=first_contour; c!=NULL; c=c->h_next ) {
cvCvtColor( original_img, contour_img, CV_GRAY2BGR );
cvDrawContours(
contour_img,
c,
CVX_RED,
CVX_BLUE,
0,
2,
8
);
}
//----------------------------------------------------------------------Convex Hull
CvMemStorage* hull_storage = cvCreateMemStorage();
CvSeq* retHulls = NULL;
for(CvSeq* i = first_contour; i != NULL; i = i->h_next){
retHulls = cvConvexHull2(i,hull_storage,CV_CLOCKWISE,0);
// with 1 it draws the Hull image but not with 0..?
// however it needs to be 0 for convexitydefects to work?
}
printf(" %d elements:\n", retHulls->total );
// drawing hull
for( CvSeq* j=retHulls; j!=NULL; j=j->h_next ) {
cvCvtColor( original_img, hull_img, CV_GRAY2BGR );
cvDrawContours(
hull_img,
j,
CVX_RED,
CVX_BLUE,
0,
2,
8
);
}
//----------------------------------------------------------------------Convexity Defects??
CvMemStorage* convexStorage = cvCreateMemStorage();
CvSeq* defect = NULL;
defect = cvConvexityDefects(first_contour,retHulls, convexStorage);
printf(" %d defect:\n", defect->total );
cvShowImage( "contours", contour_img );
cvShowImage( "original", original_img );
cvShowImage( "hull", hull_img );
cvWaitKey(0);
cvDestroyWindow( "contours" );
cvDestroyWindow( "original" );
cvDestroyWindow( "hull" );
cvReleaseImage( &original_img );
cvReleaseImage( &contour_img );
cvReleaseImage( &hull_img );
cvReleaseImage( &img_edge );
return 0;
}
回答1:
cvConvexityDefects
expects the convexHull
sequence (second argument) to contain indices into the contour
sequence (first argument):
Convex hull obtained using ConvexHull2 that should contain pointers or indices to the contour points, not the hull points themselves
In the most trivial case, where
cvFindContours
returns a single simple contour (your second image) you got lucky and your code would supply the correct sequence as the first parameter.In case
cvFindContours
finds holes in the contour (your third image), or if there are several simple contours or contours with holes (your first image) your code:finds a convex hull of each contour in turn, but only remembers the last one (since each iteration of the loop overwrites
retHulls
variable)passes the whole hierarchy of the contours, which doesn't correspond to indices in
retHulls
, tocvConvexityDefects
as the first argument.
Instead, you should have:
passed
CV_RETR_EXTERNAL
to thecvFindContour
to only get the outer contours (you don't care for defects of holes)moved the
cvConvexityDefects
inside the last loop.
Something like:
/* ... */
if (argc < 2) {
std::cerr << "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,
&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->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->h_next){
retHulls = cvConvexHull2(i,hull_storage,CV_CLOCKWISE,0);
printf(" %d elements:\n", retHulls->total );
CvSeq* defect = NULL;
defect = cvConvexityDefects(i,retHulls, NULL); // reuse storage of the contour
printf(" %d defect:\n", defect->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 );
/* ... */
回答2:
Running your application with the problematic images freezes it, but I see no crash with OpenCV 2.4.2, and the problem is really happening at cvConvexityDefects()
, according to gdb
:
(gdb) bt
#0 0x00000001002b1491 in cvConvexityDefects ()
#1 0x0000000100001a8d in main ()
Can't tell you why, though. Since the parameters seem to be OK, you might want to register a new issue here.
来源:https://stackoverflow.com/questions/12526179/finding-convexity-defects-in-opencv-crashes-depending-on-the-given-input-image