问题 凸性缺陷C ++ OpenCv


如果你能帮我解决这个问题,我将不胜感激:)

关于这个问题 OpenCV 2.X / C ++中的cvConvexityDefects?, 我也有同样的问题。 OpenCV C ++包装器没有出现在C版本中的函数cvConvexityDefects,所以我尝试编写自己的版本。

部分代码是(请注意,countour和hull都是vector <Point>,单独计算:

CvSeq* contourPoints;
CvSeq* hullPoints;
CvSeq* defects;
CvMemStorage* storage;
CvMemStorage* strDefects;
CvMemStorage* contourStr;
CvMemStorage* hullStr;
CvConvexityDefect *defectArray = 0;

strDefects = cvCreateMemStorage();
defects = cvCreateSeq( CV_SEQ_KIND_GENERIC|CV_32SC2, sizeof(CvSeq),sizeof(CvPoint), strDefects );

//We start converting vector<Point> resulting from findContours
contourStr = cvCreateMemStorage();
contourPoints = cvCreateSeq(CV_SEQ_KIND_GENERIC|CV_32SC2, sizeof(CvSeq), sizeof(CvPoint), contourStr);
printf("Metiendo valores\n");
for(int i=0; i<(int)contour.size(); i++) {
    CvPoint cp = {contour[i].x,  contour[i].y};
    cvSeqPush(contourPoints, &cp);
}
//Now, the hull points obtained from convexHull c++
hullStr = cvCreateMemStorage(0);
hullPoints = cvCreateSeq(CV_SEQ_KIND_GENERIC|CV_32SC2, sizeof(CvSeq), sizeof(CvPoint), hullStr);
for(int i=0; i<(int)hull.size(); i++) {
    CvPoint cp = {hull[i].x,  hull[i].y};
    cvSeqPush(hullPoints, &cp);
}

//And we compute convexity defects
storage = cvCreateMemStorage(0);
defects = cvConvexityDefects(contourPoints, hullPoints, storage);

输出是 Convex hull must represented as a sequence of indices or sequence of pointers in function cvConvexityDefects。我真的不知道如何以正确的方式进行转换,我一直在网上搜索并尝试调整/复制/理解一些代码片段,但它总是使用C语法。

我希望我很清楚。先谢谢你!


4834
2017-07-24 11:54


起源

在用C ++编写时,标记C不合适。 - Puppy
对不起,我把C标签,因为它是我发布的C代码,我想为cvConvexityDefects做一些包装器给C ++ - cabreracanal
我建议使用两个标签。 - Sonaten
@cabreracanal嘿,我在类似的地方有问题,你能不能看看这里 stackoverflow.com/questions/12526179/... - silent


答案:


我提出了这个问题,因为我无法找到解决方案(今天不仅是我正在解决这个问题),但毕竟我能够解决问题!

我不得不改变我使用索引数组形式计算凸包的方式。所以现在我们有一个vector <int>而不是vector <Point>。

这是我使用的代码(它可以在图像上绘制点):

void HandDetection::findConvexityDefects(vector<Point>& contour, vector<int>& hull, vector<Point>& convexDefects){
    if(hull.size() > 0 && contour.size() > 0){
    CvSeq* contourPoints;
    CvSeq* defects;
    CvMemStorage* storage;
    CvMemStorage* strDefects;
    CvMemStorage* contourStr;
    CvConvexityDefect *defectArray = 0;

    strDefects = cvCreateMemStorage();
    defects = cvCreateSeq( CV_SEQ_KIND_GENERIC|CV_32SC2, sizeof(CvSeq),sizeof(CvPoint), strDefects );

    //We transform our vector<Point> into a CvSeq* object of CvPoint.
    contourStr = cvCreateMemStorage();
    contourPoints = cvCreateSeq(CV_SEQ_KIND_GENERIC|CV_32SC2, sizeof(CvSeq), sizeof(CvPoint), contourStr);
    for(int i=0; i<(int)contour.size(); i++) {
        CvPoint cp = {contour[i].x,  contour[i].y};
        cvSeqPush(contourPoints, &cp);
    }

    //Now, we do the same thing with the hull index
    int count = (int)hull.size();
    //int hullK[count];
    int* hullK = (int*)malloc(count*sizeof(int));
    for(int i=0; i<count; i++){hullK[i] = hull.at(i);}
    CvMat hullMat = cvMat(1, count, CV_32SC1, hullK);

    //We calculate convexity defects
    storage = cvCreateMemStorage(0);
    defects = cvConvexityDefects(contourPoints, &hullMat, storage);
    defectArray = (CvConvexityDefect*)malloc(sizeof(CvConvexityDefect)*defects->total);
    cvCvtSeqToArray(defects, defectArray, CV_WHOLE_SEQ);
    //printf("DefectArray %i %i\n",defectArray->end->x, defectArray->end->y);

    //We store defects points in the convexDefects parameter.
    for(int i = 0; i<defects->total; i++){
        CvPoint ptf;
        ptf.x = defectArray[i].depth_point->x;
        ptf.y = defectArray[i].depth_point->y;
        convexDefects.push_back(ptf);
    }

    //We release memory
    cvReleaseMemStorage(contourStr);
    cvReleaseMemStorage(strDefects);
    cvReleaseMemStorage(storage);
    }
}

这对我有用。如果您发现错误或其他方式来管理它,请告诉我!


7
2017-07-25 21:16



嘿,只是想知道,但为什么在cvConvexityDefects()中使用CvMat而不是hull参数的序列?谢谢。 - fdh
嗨,这是因为我需要cvConvexityDefects任何类型的某种序列(const void * convexhull)和CvMat来到我的脑海,但事实上,我在网上找到的例子使用了CvSeq *,所以我想你可以用它。 - cabreracanal
谢谢。还有一个问题。而不是将hullK作为一个指针,这仍然可以通过使用普通数组来工作吗?例如,使用“int hullK [hull.size()]”工作,而不是你做了什么?我只是想知道我现在无法访问编译器所以我无法测试它。 - fdh
你是这么说的,因为注释行“// int hullK [count];”?我现在也没有C编译器,但我声明数组的方式是声明动态数组的C方式。在实践中,获取和设置元素的时刻没有区别。区别在于,按照我的方式,您必须手动释放分配的内存。希望这可以帮到你:) - cabreracanal
从openCV 2.4开始,该方法有一个C ++ API版本: opencv.itseez.com/modules/imgproc/doc/... - Steve Heim


找到了一些使用cpp convexityDefects的直接方法。 通过convexHull函数进行类型处理。它按类型填充,int *返回indizes,Point *返回坐标。

void WorkFrame( Mat img, double minArea )
{
//assumption:
// img already preprocessed, threshold, gray, smooth, morphology whatever..

//get some contours
vector<vector<Point> > contours;
vector<Vec4i> hierarchy;
findContours( img, contours, hierarchy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE );

for( int i=0; i<contours.size(); i++ ) 
{
    vector<Point>& c=contours[i];
    double area = contourArea( c );
        if( area<minArea ){ continue; } //filter remaining noise

    //convexHull works typedependent.
    //std::vector<Point> ptHull1; //uncomment and compare to ptHull2
    //convexHull( c, ptHull1 ); //convexHull is smart and fills direct coordinates

    std::vector<int> ihull; 
    convexHull( c, ihull ); //convexHull is smart and fills in contourIndices

    std::vector<Vec4i> defects;
    convexityDefects( c, ihull, defects ); //expects indexed hull (internal assertion mat.channels()==1)

    std::vector< Point > ptHull2;
    std::vector<int>::iterator ii=ihull.begin();
    while( ii!=ihull.end() )
    {
        int idx=(*ii);
        ptHull2.push_back( c[idx] );
        ii++;
    }
    cv::polylines( mat, c, true, Scalar( 0xCC,0xCC,0xCC ), 1 );
    cv::polylines( mat, ptHull2, true, Scalar( 0xFF, 0x20, 0x20 ), 1 );

    std::vector<Vec4i>::iterator d=defects.begin();
    while( d!=defects.end() )
    {
        Vec4i& v=(*d); d++;
        int startidx=v[0]; Point ptStart( c[startidx] );
        int endidx=v[1]; Point ptEnd( c[endidx] );
        int faridx=v[2]; Point ptFar( c[faridx] );

        cv::circle( img, ptStart, 4, Scalar( 0x02,0x60,0xFF ), 2 );
        cv::circle( img, ptEnd,   4, Scalar( 0xFF,0x60,0x02 ), 2 );
        cv::circle( img, ptFar,   4, Scalar( 0x60,0xFF,0x02 ), 2 );
    }
}

}


3
2017-11-04 23:29