在opencv中找到凸性缺陷?
我有一个程序来计算图像的凸包。 我正在尝试使用此信息来计算输入图像中存在的手指数量。 从一些冲浪我发现这样做(计数手指)的方法是
- 寻找轮廓
- 凸壳
- 凸性缺陷
但是我在使用凸性缺陷函数时遇到了麻烦。 编译很好,但在运行时程序崩溃与某些输入图像,但没有其他人,我似乎无法弄清楚为什么。
这些是输入图像
- 此图像导致崩溃
- 但事实并非如此。
- 即使它与上面类似, 这也会导致崩溃
码..
#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获得的凸包应该包含轮廓点的指针或索引,而不是船体点本身
-
在最简单的情况下,
cvFindContours
返回一个简单的轮廓(你的第二个图像),你很幸运,你的代码将提供正确的序列作为第一个参数。 -
如果
cvFindContours
在轮廓中找到了孔(您的第三个图像),或者有几个简单的轮廓或带孔的轮廓(您的第一个图像),您的代码:-
依次找到每个轮廓的凸包,但只记住最后一个(因为循环的每次迭代都会覆盖
retHulls
变量) -
将轮廓的整个层次结构(与
retHulls
索引不对应)传递给cvConvexityDefects
作为第一个参数。
-
相反,你应该:
-
将
CV_RETR_EXTERNAL
传递给cvFindContour
以仅获取外部轮廓(您不关心孔的缺陷) -
在最后一个循环中移动了
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 ()
但是不能告诉你为什么。 由于参数似乎没问题,您可能需要在此处注册新问题 。