5

画像の凸包を計算するプログラムがあります。入力画像に存在するの数をカウントするために、この情報を使用しようとしています。いくつかのサーフィンから、これを行う方法(指を数える)が次の方法であることがわかりました

  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

4 に答える 4

3

問題のあるイメージでアプリケーションを実行するとフリーズしますが、OpenCV 2.4.2 ではクラッシュは見られません。また、問題は で実際に発生cvConvexityDefects()していgdbます。

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

ただし、理由はわかりません。パラメータは問題ないようですので、ここで新しい課題を登録してください

于 2012-09-24T03:29:40.037 に答える
3

cvConvexityDefectsconvexHullシーケンス (2 番目の引数) にシーケンス (1 番目の引数) へのインデックスが含まれていることを期待しcontourます。

ConvexHull2 を使用して取得された凸包。これには、凸包ポイント自体ではなく、輪郭ポイントへのポインターまたはインデックスが含まれている必要があります。

  1. cvFindContourswhereが単一の単純な輪郭 (2 番目の画像) を返す最も些細なケースでは、運が良かったので、コードは最初のパラメーターとして正しいシーケンスを提供します。

  2. 輪郭に穴が見つかった場合cvFindContours(3 番目の画像)、またはいくつかの単純な輪郭または穴のある輪郭 (最初の画像) がある場合は、コード:

    1. 各輪郭の凸包を順番に見つけますが、最後のものだけを覚えています (ループの各反復がretHulls変数を上書きするため)

    2. retHullsのインデックスに対応しない等高線の階層全体をcvConvexityDefects最初の引数として に渡します。

代わりに、次のものが必要です。

  1. に渡しCV_RETR_EXTERNALcvFindContour、外側の輪郭のみを取得します (穴の欠陥は気にしません)。

  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 );
  /* ... */
于 2012-09-27T08:49:41.280 に答える