У меня есть программа, которая вычисляет выпуклую оболочку изображения. Я пытаюсь использовать эту информацию для подсчета количества пальцы которые присутствуют во входном изображении. Из какого-то серфинга я узнал, что способ сделать это (считать пальцы) —
Но у меня возникли проблемы с использованием функции дефектов выпуклости. Он компилируется нормально, но во время выполнения программа вылетает с определенными входными изображениями, но не с другими, и я не могу понять, почему.
Это входные изображения
код..
#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;
}
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 ()
Хотя не могу сказать почему. Поскольку параметры кажутся в порядке, вы можете захотеть зарегистрировать новый выпуск здесь.