Question

I would be grateful to you if you could help me with this issue :)

Relating to this question cvConvexityDefects in OpenCV 2.X / C++?, I have the same problem. The OpenCV C++ wrapper has not the function cvConvexityDefects that appears in the C version, so I tried to write my own version.

Part of the code is (please note that both countour and hull are vector< Point >, calculated separately :

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);

The output is Convex hull must represented as a sequence of indices or sequence of pointers in function cvConvexityDefects. Really I don't know how to do conversion in the right way, I've ben searching on the web and tried to adapt/copy/understand some pieces of code, but it is always with the C syntax.

I hope I was clear. Thank you in advance!

Was it helpful?

Solution

I raised this question because I wasn't able to figure out a solution (it is not only today that I was dealing with the matter hehe), but after all I was able to manage the problem!

I had to change the way I calculated the convex hull, using the index array form. So now we have a vector< int > instead a vector< Point >.

This is the code I used (it works I painted the points over an image):

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

This worked for me. If you see something wrong or another way to manage it, please tell me!

OTHER TIPS

found some direct approach using the cpp convexityDefects. Typehandling by convexHull-function. It fills by type, int* returns indizes, Point* returns coordinates.

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

}

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top