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
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With