在opencv中找到凸性缺陷?

我有一个程序来计算图像的凸包。 我正在尝试使用此信息来计算输入图像中存在的手指数量。 从一些冲浪我发现这样做(计数手指)的方法是

  1. 寻找轮廓
  2. 凸壳
  3. 凸性缺陷

但是我在使用凸性缺陷函数时遇到了麻烦。 编译很好,但在运行时程序崩溃与某些输入图像,但没有其他人,我似乎无法弄清楚为什么。

这些是输入图像

  1. 此图像导致崩溃
  2. 但事实并非如此。
  3. 即使它与上面类似, 这也会导致崩溃

码..

#include  #include  #include  #include  #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; } 

cvConvexityDefects期望convexHull序列(第二个参数)包含contour序列(第一个参数)的索引:

使用ConvexHull2获得的凸包应该包含轮廓点的指针或索引,而不是船体点本身

  1. 在最简单的情况下, cvFindContours返回一个简单的轮廓(你的第二个图像),你很幸运,你的代码将提供正确的序列作为第一个参数。

  2. 如果cvFindContours在轮廓中找到了孔(您的第三个图像),或者有几个简单的轮廓或带孔的轮廓(您的第一个图像),您的代码:

    1. 依次找到每个轮廓的凸包,但只记住最后一个(因为循环的每次迭代都会覆盖retHulls变量)

    2. 将轮廓的整个层次结构(与retHulls索引不对应)传递给cvConvexityDefects作为第一个参数。

相反,你应该:

  1. CV_RETR_EXTERNAL传递给cvFindContour以仅获取外部轮廓(您不关心孔的缺陷)

  2. 在最后一个循环中移动了cvConvexityDefects

就像是:

  /* ... */ 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 ); /* ... */ 

使用有问题的图像运行你的应用程序会冻结它,但我看到OpenCV 2.4.2没有崩溃,并且问题确实发生在cvConvexityDefects() ,根据gdb

 (gdb) bt #0 0x00000001002b1491 in cvConvexityDefects () #1 0x0000000100001a8d in main () 

但是不能告诉你为什么。 由于参数似乎没问题,您可能需要在此处注册新问题 。