Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Calculating convexityDefects using OpenCV 2.4 in c++

Tags:

c++

ios

opencv

I'm using OpenCV 2.4 to calculate the convex hull of a image.

I'm also doing some processing to remove some noise from the image, which is not really relevant to the question.

The code to calculate the convexHull is the following:

...
cv::Mat sourceImage; // assume something is already here please
cv::vector<cv::Vec4i> hierarchy;    
std::vector<std::vector<cv::Point> > contours;

cv::findContours( sourceImage, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE,cv::Point(0, 0));

// Find the convex hull object for each contour
vector<cv::vector<cv::Point> >hull( contours.size() );

for (int i = 0; i < contours.size(); i++)
{
    convexHull( contours[i], hull[i], false );
}
...

Having both the convexHull and the contours I now want to calculate the convexityDefects of the hull(s), which by looking at opencv documentation I thought it would be like this:

cv::Vec4i defects;  
convexityDefects(cv::Mat(contours),  hull, defects);

Doing this I get this error:

OpenCV Error: Assertion failed (ptnum > 3) in convexityDefects, file ./opencv/opencv/modules/imgproc/src/contours.cpp, line 1969

Any ideas on what I'm doing wrong when using convexityDefects?

Opencv convexityDefects documentation

Thanks in advance.

UPDATE

Thanks to Innuendo answer I updated the main loop code to:

std::vector<Vec4i> defects; 
vector<cv::vector<cv::Point> >hull( contours.size() );

for (int i = 0; i < contours.size(); i++)
{  
    convexHull( contours[i], hull[i], false );
    convexityDefects(contours[i], hull[i], defects[i]);
}

Using this, the error that I now get is:

OpenCV Error: Assertion failed (hull.checkVector(1, CV_32S) > 2) in convexityDefects
like image 805
Tiago Avatar asked Dec 13 '22 02:12

Tiago


2 Answers

From openCV wiki :

Finds the convexity defects of a contour.

So you should include it in your loop.

std::vector<Vec4i> defects; 
vector<cv::vector<int> >hull( contours.size() );

for (int i = 0; i < contours.size(); i++)
{  
    convexHull( contours[i], hull[i], false );
    convexityDefects(contours[i], hull[i], defects[i]);
}

Also, as you mentioned, in wiki is said:

hull – Output convex hull. It is either an integer vector of indices or vector of points. In the first case, the hull elements are 0-based indices of the convex hull points in the original array (since the set of convex hull points is a subset of the original point set). In the second case, hull elements are the convex hull points themselves.

like image 179
Larry Cinnabar Avatar answered Jan 01 '23 15:01

Larry Cinnabar


For those who don't read the comments or didn't see it the solution is to use:

vector<cv::vector<int> >hull;

to create the hull instead of:

vector<cv::vector<Point> >hull;

as convexityDefects only works on hulls stored as a series of indices rather than a series of Points.

Sadly this gives another problem as drawContours only draws contours stored as a series of Points and not as a series of indices! So if you want to draw your hulls at a later stage you may want to create 2 stores when you are finding the hulls, one for drawing and one for finding defects from. Something along the lines of the following works:

  // create storage space
  vector<vector<int> > hullsI(contours.size());
  vector<vector<Point> > hullsP(contours.size());
  vector<vector<Vec4i> > defects(contours.size());

  for(int i = 0; i <contours.size(); ++i){
     //find the hulls
     convexHull(contours[i], hullsI[i], true);
     convexHull(contours[i], hullsP[i], true);
     //find the defects  
     convexityDefects(contours[i], hullsI[i], defects[i]);
     }

It may be more efficient to just use a different method to draw the hulls rather than calculating them twice but this was the most elegant way I saw of doing it.

Also I'm still getting the hang of C/C++ myself (Java guy) but I believe if you add using namespace cv to the top of the code you can save having to have cv:: throughout your code.

Hope I haven't stepped on toes Innuendo, not my intention at all if I have.

like image 45
RyanfaeScotland Avatar answered Jan 01 '23 15:01

RyanfaeScotland