Problem with getting information on contours
I am writing a function that takes a binary 8-bit image and trying to find the average area of blobs in there. My function is:
void rm_noise(cv::Mat& img, cv::Mat& clean_img)
{
std::vector<std::vector<cv::Point>> contours;
std::vector<cv::Vec4i> hierarchy;
cv::findContours ( img, contours, hierarchy, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE);
if ( contours.empty() )
return;
clean_img = cv::Mat::zeros(img.size(), CV_8UC1);
for (size_t i = 0; i < hierarchy.size(); i++)
{
cv::drawContours(clean_img, contours, i, cv::Scalar(0XFF), cv::FILLED, cv::LINE_AA, hierarchy);
}
cv::imshow("edges", clean_img);
cv::waitKey();
double area = 0;
//for (std::vector<std::vector<cv::Point>>::const_iterator c = contours.begin(); c != contours.end(); c++)
for (size_t i = 0; i >= 0; i = hierarchy[i][0])
{
const std::vector<cv::Point>& c = contours[i];
double a = std::fabs(cv::contourArea(cv::Mat(c)));
area += a;
}
double avg_area = area /= contours.size();
}
findContours
seems to work correctly as I can see the contours drawn properly using a loop with drawContours
. However, when I try to get the information on contours such as contourArea
or even bounding box, I get strange results. The results seem to give me contour area as very large (something of the order of 10^19 pixels) which is obviously wrong. And the code seg faults. Can someone help me with this as I have already wasted about five days trying different combinations to no avail.
I've got no error, no seg faults and average area of 7400pixels in my test image using this:
Have a careful look at the last line! There's an extra
=
in your codeI also got successful results with this (no need to use an extra variable):
/=
is not an error. However, in my 640x480 image, I get 71 contours. As I go through the contours, the first one has 4 points and an area of 56 (reasonable), the second one has 516 points and an area of 5.69e+19 (not right) and the third one has 120195045 points and issues an exception when computing area. I am perplexed.I'll be happy to test your image and see if I can find anything wrong with it. Btw, which version are you using?
I have the image here. I am using OpenCV 3.0 on Visual Studio 2013.
can you please post your image? (and maybe also a plot of the unfilled contours detected by OpenCV)
As per the documentation,
contourArea
does not actually count pixels, it uses a green formula which may give nonsensical results for contours that are not well behaved.Incidentally, you don't need the
std::fabs
,contourArea
has an optional flag for returning signed or unsigned area. The default is unsigned.guy
This is what I use and I've never had a problem with weird areas:
guy
@unxnut: using the provided image I get 2 contours corresponding to the 2 white blobs. But, important thing is that your image is in .jpg format, so due to compression issues your image is not longer binary - some pixels which should be 255 are now 254 or 253, those which should be 0 can take values of 1, 2 or 5 maybe. Therefore, findContours doesn't run as expected. Just put
threshold(image, image, 128, 255, CV_THRESH_BINARY);
to binarize image before calling your function.@unxnut: extra comment, if you just want to compute average area, you might find useful the new 3.0 function connectedComponentsWithStats:
approxPoly
didn't help either :-(