Calculate perimeter of convex hull in opencv - c++

For detection of table I need to calculate perimeter of convex hull in each connected component. I wrote the following code, but it is giving wrong answer.
findContours(rois[wp], contoursc, hierarchyh, CV_RETR_EXTERNAL, CHAIN_APPROX_NONE);
double perim=0;
vector<vector<Point> > hullh(contoursc.size());
for (int i = 0; i < contoursc.size(); i++)
{
convexHull(contoursc[i], hullh[i], false);
}
for(int i=0;i<hullh.size();i++){
perim=perim + arcLength(hullh[i],true);
}
cout<<"Perimeter of convex hull = "<<peri<<"\n";
Can someone explain what could be the reason of wrong result.

Related

opencv find perimeter of a connected component

I'm using opencv 2.4.13
I'm trying to find the perimeter of a connected component, I was thinking of using ConnectedComponentWithStats but it doesn't return the perimeter, only the area, width, etc...
There is a method to find the area with the contour but not the opposite (with one component i mean, not the entire image).
The method arcLength doesn't work as well beause i have all the points of the component, not only the contour.
I know there is a BF way to find it by iterating through each pixel of the component and see if he has neighbors which aren't in the same component. But I'd like a function which costs less.
Otherwise, if you know a way to link a component with the contours found by the method findContours, it suits me as well.
Thanks
Adding to #Miki's answer, This is a faster way to find the perimeter of the connected component
//getting the connected components with statistics
cv::Mat1i labels, stats;
cv::Mat centroids;
int lab = connectedComponentsWithStats(img, labels, stats, centroids);
for (int i = 1; i < lab; ++i)
{
//Rectangle around the connected component
cv::Rect rect(stats(i, 0), stats(i, 1), stats(i, 2), stats(i, 3));
// Get the mask for the i-th contour
Mat1b mask_i = labels(rect) == i;
// Compute the contour
vector<vector<Point>> contours;
findContours(mask_i, contours, RETR_EXTERNAL, CHAIN_APPROX_NONE);
if(contours.size() <= 0)
continue;
//Finding the perimeter
double perimeter = contours[0].size();
//you can use this as well for measuring perimeter
//double perimeter = arcLength(contours[0], true);
}
The easiest thing is probably to use findContours.
You can compute the contour on the i-th component computed by connectedComponents(WithStats) , so they are aligned with your labels. Using CHAIN_APPROX_NONE you'll get all the points in the contour, so the size() of the vector is already a measure of the perimeter. You can eventually use arcLength(...) to get a more accurate result:
Mat1i labels;
int n_labels = connectedComponents(img, labels);
for (int i = 1; i < n_labels; ++i)
{
// Get the mask for the i-th contour
Mat1b mask_i = labels == i;
// Compute the contour
vector<vector<Point>> contours;
findContours(mask_i.clone(), contours, RETR_EXTERNAL, CHAIN_APPROX_NONE);
if (!contours.empty())
{
// The first contour (and probably the only one)
// is the one you're looking for
// Compute the perimeter
double perimeter_i = contours[0].size();
}
}

Jigsaw puzzle solving based on shape C++. OPENCV

color image here : color_image ploy approximation image here : poly_approximation_image \n
I got 54 pieces of Jigsaw puzzle, I would like to solve these puzzle using shape of each puzzle.
What I have done is :
segment each piece from the background.
get the canny edges and the contours.
apply poly approximation.
Now, I would like to apply convex hull, but however, I don't know how can I get convex and concave of each piece using opencv.
puzzle.input_image.copyTo(input_copy);
cvtColor(puzzle.input_image,input_image_gray,CV_RGB2GRAY); // convert to gray.
Mat thresholded_image=puzzle.get_thresholded_image(input_image_gray);
imshow("thresholded",thresholded_image);
Mat floodfill_image=puzzle.floodfill(thresholded_image);
contours=puzzle.get_contours(floodfill_image);
puzzle.get_puzzle_pieces(thresholded_image,input_copy);
for(int i=0; i< puzzle.pieces_color.size() ; i++){
Mat temp = Mat::zeros(puzzle.pieces_color.at(i).rows,puzzle.pieces_color.at(i).cols,CV_8U);
Mat temp2= Mat::zeros(puzzle.pieces_color.at(i).rows,puzzle.pieces_color.at(i).cols,CV_8U);
Mat temp3= Mat::zeros(puzzle.pieces_color.at(i).rows,puzzle.pieces_color.at(i).cols,CV_8U);
cvtColor(puzzle.pieces_color[i],temp,CV_RGB2GRAY);
temp2=puzzle.get_thresholded_image(temp);
puzzle.pieces_binary.push_back(temp2);
temp3=puzzle.get_canny(temp2);
imshow("temp2",temp3);
imwrite("temp2.jpg",temp3);
// getting the contours.
contours=puzzle.get_contours(temp2);
for(int c=0; c< contours.size() ; c++){ // poly approxamiation for all the contours for every piece.
std::vector<cv::Point> poly;
cv::approxPolyDP(cv::Mat(contours[c]),poly,5,true);
// Iterate over each segment and draw it
std::vector<cv::Point>::const_iterator itp= poly.begin();
while (itp!=(poly.end()-1)) {
cv::line(temp2,*itp,*(itp+1),cv::Scalar(255),2);
++itp;
}
// last point linked to first point
cv::line(temp2,*(poly.begin()),*(poly.end()-1),cv::Scalar(255),2);
}
Any help?
Thanks.

Drawing minarea rectangle for convex hull

Hi i've been trying to recognize hand signatures(numbers) using OpenCV.i am encountering a problem where 1 and 2 show the same number of convexity defects.
One way i thought i could rectify this was by drawing a Minbounding rectangle..and find the ratio of the area of the convex hull to that of the bounding rectangle.
However im not aware how to do this.
vector<vector<Point>> hull;
The index of the hull i am interested in is say k;
How do i draw a rotated rectangle for this convex hull?
// Assuming
// vector<vector<Point>> hull;
// Mat3b frame;
if((k >= 0) && (k < hull.size()) && (!hull[k].empty()))
{
RotatedRect rotated = minAreaRect(hull[k]);
Point2f rect_points[4];
rotated.points( rect_points );
for( int j = 0; j < 4; j++ ) {
line( frame, rect_points[j], rect_points[(j+1)%4], Scalar(255,0,0), 1, 8 );
}
}

OpenCV convexhull doesn't give correct output

This is my input binary image:
Now I want to get its convex hull using OpenCV. For that, I wrote the following code:
cv::Mat input = cv::imread("input.jpg", CV_LOAD_IMAGE_GRAYSCALE);
cv::vector<cv::vector<cv::Point>> contours;
cv::vector<cv::Vec4i> hierarchy;
// Find contours
cv::findContours(input, contours, hierarchy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);
// Find the convex hull
cv::vector<cv::vector<cv::Point>> hull(contours.size());
for(int i = 0; i < contours.size(); i++)
{
cv::convexHull(cv::Mat(contours[i]), hull[i], false);
}
cv::Mat drawing = cv::Mat::zeros(input.size(), CV_8UC3);
cv::Scalar color = cv::Scalar(0, 0, 255);
for (int j = 0; j < hull.size(); j++)
{
cv::drawContours(drawing, hull, j, color, 1, 8, cv::vector<cv::Vec4i>(), 0, cv::Point());
}
cv::imshow("Convex hull", drawing);
cv::waitKey();
And this is the output:
In Matlab however, when I write the following code:
input = imread('input.jpg');
[x, y] = find(input);
k = convhull(x, y);
plot(y(k), x(k), 'r-', y, x, 'b.');
This gives me exactly what I want (the red line represents the convex hull that I want):
So, how can I obtain the same result in OpenCV? What should I've done incorrectly here? Thank you.
May be this answer is late, but for those who is still in search here it is.
You don't need to take contours. Just take all non-zero point from binary image using findNonZero() method and then apply convexHull to that set of points. It will work perfectly.

How to find the radius of an irregular circle using OpenCV C++

How can I estimate the radius of an irregular circle I have detected? I have used findContours() to find where the circles are and used moments() to find the centre of mass. I now just need the radius of the circle so I can estimate it's volume.
For finding contours I have used the following code:
findContours(Closed_Image, Contours, Hierarchy,
CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE, Point(0,0) );
For finding the centre of mass I have used the following code:
vector<Moments> mu(Contours.size() );
b = 0;
for(b = 0; b < Contours.size(); b++)
{
mu[b] = moments(Contours[b], true);
}
vector<Point2f> mc(Contours.size() );
c = 0;
for(c = 0; c < Contours.size(); c++)
{
mc[c] = Point2f(mu[c].m10/mu[c].m00, mu[c].m01/mu[c].m00);
cout << "Contours Centre = " << mc[c] << endl;
}
I'm guessing that I need to use the contour points stored in Contours but the shape isn't a perfect circle so the distance between each point in the contour and its centre of mass would be different. Is this just a matter of averaging the distance between the centre of mass and each point in the contour (average distance = radius)? If so, how can I actually implement it (I'm not sure how to access data in vector<vector<Point> > Contours;). Otherwise, how would I be able to achieve estimating the radius?
(Click here for the image I am working with)
Centre of mass is as follows: [424.081, 13.4634], [291.159, 10.4545], [157.833, 10.4286], [24.5198, 8.09127]