найти дефекты выпуклости в opencv? [вылетает в зависимости от заданного входного изображения ..]

У меня есть программа, которая вычисляет выпуклую оболочку изображения. Я пытаюсь использовать эту информацию для подсчета количества пальцы которые присутствуют во входном изображении. Из какого-то серфинга я узнал, что способ сделать это (считать пальцы) —

  1. Нахождение контуров
  2. Выпуклый корпус
  3. Дефекты выпуклости

Но у меня возникли проблемы с использованием функции дефектов выпуклости. Он компилируется нормально, но во время выполнения программа вылетает с определенными входными изображениями, но не с другими, и я не могу понять, почему.

Это входные изображения

  1. этот изображение вызывает сбой
  2. но этот не.
  3. этот также вызывает сбой, даже если он похож на выше

код..

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

4

Решение

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

Другие решения

Запуск вашего приложения с проблемными изображениями замораживает его, но я не вижу сбоя с OpenCV 2.4.2, и проблема действительно происходит в cvConvexityDefects(), в соответствии с gdb:

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

Хотя не могу сказать почему. Поскольку параметры кажутся в порядке, вы можете захотеть зарегистрировать новый выпуск здесь.

3

По вопросам рекламы [email protected]