cv::Mat thr;
std::vector<std::vector<cv::Point> > contours;
std::vector<std::vector<cv::Vec4i> > hierarchy;
int largest_area = 0;
int largest_contour_index = 0;
cv::findContours( thr, contours, hierarchy,CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE ); // Find the contours in the image
for( int i = 0; i < contours.size(); i++ ) // iterate through each contour.
{
double a = contourArea( contours[i], false ); // Find the area of contour
if(a > largest_area)
{
largest_area = a;
largest_contour_index = i; // Store the index of largest contour
}
}
What should I do after finding the index of the largest contour? How I can delete all the other contours with its inner areas?
Image is binary (cv::Mat thr). Just black background with white areas.
Thanks.
In your case, deleting contours with its inner areas is equal to fill them to black. This can be done by drawing the contour regions with black color:
for (size_t i=0; i<contours.size(); ++i) {
if (i != largest_contour_index) { // not the largest one
cv::drawContours(thr, contours, i, cv::Scalar(0,0,0), CV_FILLED);
}
}
After finding contours find index of biggest contour and draw that contour on Mat.
int indexOfBiggestContour = -1;
int sizeOfBiggestContour = 0;
for (int i = 0; i < contours.size(); i++)
{
if (contours[i].size() > sizeOfBiggestContour)
{
sizeOfBiggestContour = contours[i].size();
indexOfBiggestContour = i;
}
}
cv::Mat newImage;
drawContours(newImage, contours, indexOfBiggestContour, Scalar(255), CV_FILLED, 8, hierarchy);
Related
I have this source image
and I have applied binary thresholding to get this
I used contours to differentiate between the ones having child contours and ones that don't.The resultant pic is
But how do I count the number of child contours that each green contour contains?. This is code I have used:-
Mat binMask = lung;// the thresholded image
Mat lung_src = imread("source.tiff");// the source image
//imshow("bin mask", binMask);
vector<std::vector<cv::Point>> contours;
vector<cv::Vec4i> hierarchy;
int count = 0, j;
double largest_area = 0;
int largest_contour_index = 0;
findContours(binMask, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, cv::Point(0, 0));
for (int i = 0; i < contours.size(); i++)
{
double a = contourArea(contours[i], false); // Find the area of contour
if (a>largest_area)
{
largest_area = a;
largest_contour_index = i;
}
for (j = 0; j <= i; j++)
{
if (hierarchy[j][2] != -1) // means it has child contour
{
drawContours(lung_src, contours, j, Scalar(0, 255, 0), 1, 8, hierarchy, 0, Point());
}
else // means it doesn't have any child contour
{
drawContours(lung_src, contours, j, Scalar(0, 0, 255), 1, 8, hierarchy, 0, Point());
}
}
}
drawContours(lung_src, contours, largest_contour_index, Scalar(255, 0, 0), 1, 8, hierarchy, 0, Point());
imshow("lung-mapped", lung_src);
EDIT-1- I added the code from Humam at the end to check it out:
std::vector<int> number_of_inner_contours(contours.size(), -1);
int number_of_childs = 0;
for (size_t i = 0; i < contours.size(); i++)
{
int first_child_index = hierarchy[i][2];
if (first_child_index >= 0)
{
int next_child_index = hierarchy[first_child_index][0];
if (number_of_inner_contours[next_child_index]<0)
{
number_of_childs = number_of_inner_contours[next_child_index];
}
else
{
while (next_child_index >= 0)
{
next_child_index = hierarchy[next_child_index][0];
++number_of_childs;
}
number_of_inner_contours[i] = number_of_childs;
}
}
else
{
number_of_inner_contours[i] = 0;
}
cout << "\nThe contour[" << i << "] has " << number_of_inner_contours[i] << "child contours";
}
But the output I got was like :
The contour[456 ] has 0 child contours
The contour[457 ] has 0 child contours
The contour[458 ] has 0 child contours
The contour[459 ] has -1 child contours
From OpenCV documentation :
hierarchy – Optional output vector, containing information about the
image topology. It has as many elements as the number of contours. For
each i-th contour contours[i] , the elements hierarchy[i][0] ,
hiearchyi , hiearchy[i][2] , and hiearchy[i][3] are set to
0-based indices in contours of the next and previous contours at the
same hierarchical level, the first child contour and the parent
contour, respectively. If for the contour i there are no next,
previous, parent, or nested contours, the corresponding elements of
hierarchy[i] will be negative.
This is untested code for doing the job:
std::vector<size_t> number_of_inner_contours;
number_of_inner_contours.reserve(contours.size());
for (size_t i = 0; i < contours.size(); i++){
size_t number_of_childs = 0;
auto first_child_index=hierarchy[i][2];
if(first_child_index>=0){
auto next_child_index=hierarchy[first_child_index][0];
while (next_child_index>=0){
next_child_index=hierarchy[next_child_index][0];
++number_of_childs;
}
number_of_inner_contours.emplace_back(number_of_childs);
}
else{
number_of_inner_contours.emplace_back(0);
}
}
This code could be done in a better way by using the concept of dynamic programming. This is a first try also:
std::vector<int> number_of_inner_contours(contours.size(),-1);
for (size_t i = 0; i < contours.size(); i++){
auto number_of_childs = 0;
auto first_child_index=hierarchy[i][2];
if(first_child_index>=0){
auto next_child_index=hierarchy[first_child_index][0];
if(number_of_inner_contours[next_child_index]<0){
number_of_childs=number_of_inner_contours[next_child_index];
}
else{
while (next_child_index>=0){
next_child_index=hierarchy[next_child_index][0];
++number_of_childs;
}
number_of_inner_contours[i]=number_of_childs;
}
}
else{
number_of_inner_contours[i]=0;
}
}
Can someone help me to solve this problem? I need to draw contours from the 2 largest objects with same color but I always get error and this is my code.
void showconvex(Mat &thresh,Mat &frame)
{
int largest_index = 0;
int largest_contour = 0;
int second_largest_index = 0;
int second_largest_contour = 0;
vector<vector<Point> > contours;
vector<Vec4i> hierarchy;
//find contours
findContours(thresh, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE);
/// Find the convex hull object for each contour
vector<vector<Point> >hull(contours.size());
vector<vector<int> >inthull(contours.size());
vector<vector<Vec4i> >defects(contours.size());
for (int i = 0; i < contours.size(); i++)
{
convexHull(Mat(contours[i]), hull[i], false);
convexHull(Mat(contours[i]),inthull[i], false);
if (inthull[i].size()>3)
convexityDefects(contours[i], inthull[i], defects[i]);
}
//find largest contour
for (int i = 0; i< contours.size(); i++) // iterate through each contour.
{
double a = contourArea(contours[i].size()); // Find the area of contour
if (a>largest_contour)
{
second_largest_contour = largest_contour;
second_largest_index = largest_index;
largest_contour = a;
largest_index = i;
}
else if(contours[i].size() > second_largest_contour)
{
second_largest_contour = contours[i].size();
second_largest_index = i;
}
}
drawContours(frame, contours, largest_index, CV_RGB(0,255,0), 2, 8, hierarchy);
drawContours(frame, contours, second_largest_index, CV_RGB(0,255,0), 2, 8, hierarchy);
}
After your cv::findContours() call catch the case when contours.size() is zero:
if ( contours.size() == 0 ) return;
Otherwise you are drawing contours of largest_index (equal to 0) and second_largest_index (also equal to 0) that do not exist.
I am trying to access the contour that is nested within another contour to run a few tests on it, such as an area test and to see if the bounding rectangle is about square. I figured out how to test if there is an internal contour, but I do not know how to access it.
Relevant code
vector<vector<Point> > contours;
vector<Vec4i> hierarchy;
DEBUG_SHOW("binary image", binary);
findContours(binary, contours, hierarchy, CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE, Point(0, 0));
vector<vector<Point> > polygons(contours.size());
for (size_t i = 0; i < contours.size(); i++) {
vector<Point> contour = contours[i];
double area = contourArea(contour);
if (area < 300) {
continue;
}
if(hierarchy[i][2] != -1){
//test internal contour
}
If I'm correct then you have a set of Points
Vector<point>
and then you have a collection of those sets
Vector<Vector<point>>
Now with that in mind. You iterate through the Vector(point) using
for (size_t i = 0; i < contours.size(); i++) {
& You are required to iterate through the vector within
You will need to:
for (size_t j=0; j = contours.at(i).size(); j++){
//Do Your Thang
i++;
}
How can I found the circles on image using the method minEnclosingCircle but avoid the internal circles?
I'm using the opencv with c++ to detect circles on a image. I was using the method HoughCircles but sometimes it lost some circles or it detected false circles.
Therefore I'm replacing it for the minEnclosingCircle. Now the algorithm is finding all circles, but in some cases it found circles inside other circles and I want avoid this.
The image 1 is a example of input and the image 2 is it output.
The code used to process those images is this:
Start of code:
vector < Circle > houghCircles(Mat thresholdImage, float minRadius, float maxRadiuss) {
vector < vector < Point > > contours;
vector < Vec4i > hierarchy;
findContours(thresholdImage, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0));
vector < vector < Point > > contours_poly(contours.size());
vector < Circle > circlesTMP(contours.size());
for (int i = 0; i < contours.size(); i++) {
Point2f detectedCenter;
float detectedRadius;
approxPolyDP(Mat(contours[i]), contours_poly[i], 3, true);
minEnclosingCircle((Mat) contours_poly[i], detectedCenter, detectedRadius);
if (minRadius != 0 && detectedRadius < minRadius) {
continue;
}
if (maxRadiuss != 0 && detectedRadius > maxRadiuss) {
continue;
}
sf::Circle _circle(detectedCenter, detectedRadius);
circlesTMP.push_back(_circle);
}
vector < Circle > circles;
for (int i = 0; i < circlesTMP.size(); i++) {
sf::Circle _circle = circlesTMP[i];
if (_circle.getRadius() > 0) {
circles.push_back(circlesTMP[i]);
}
}
cout << "Circles found: " << circles.size() << endl;
Mat drawing = Mat::zeros(thresholdImage.size(), CV_8UC3);
for (int i = 0; i < circles.size(); i++) {
sf::Circle _circle = circles[i];
Scalar color = Scalar(200, 187, 255);
circle(drawing, _circle.getCenter(), (int) _circle.getRadius(), color, 2, 8, 0);
}
imshow(drawing, "OpenCVUtil");
waitkey();
return circles;
}
you can check this link out and change your mode parameter and test your code:
http://docs.opencv.org/modules/imgproc/doc/structural_analysis_and_shape_descriptors.html?highlight=findcontours#findcontours
check out the results you obtain for CV_RETR_EXTERNAL instead of CV_RETR_TREE as the mode.
I am printing the Contours in the following way:
std::vector<std::vector<cv::Point> > contours;
std::vector<cv::Vec4i> hierarchy;
cv::findContours( mask, contours, hierarchy, cv::RETR_CCOMP, cv::CHAIN_APPROX_TC89_KCOS);
for ( size_t i=0; i<contours.size(); ++i )
{
cv::drawContours( img, contours, i, Scalar(200,0,0), 1, 8, hierarchy, 0, Point() );
cv::Rect brect = cv::boundingRect(contours[i]);
cv::rectangle(img, brect, Scalar(255,0,0));
}
Once I have a binnary image, I want to eliminate the smaller contours. Any suggestions on how to do so?
MY INPUT PICTURE:
WHAT I WANT TO ACHIEVE:
EDIT:
I am trying to get rid of the smaller segments. Any hints?
I've built a function that only prints points that belong to the bigger segments. It uses the pointPolygonTest, an awesome OpenCV function that can say if a point is inside, outside or at the bounds of a given contour. Check it out:
// Gets only the biggest segments
Mat Morphology::threshSegments(Mat &src, double threshSize) {
// FindContours:
vector<vector<Point> > contours;
vector<Vec4i> hierarchy;
Mat srcBuffer, output;
src.copyTo(srcBuffer);
findContours(srcBuffer, contours, hierarchy, cv::RETR_CCOMP, cv::CHAIN_APPROX_TC89_KCOS);
vector<vector<Point> > allSegments;
// For each segment:
for (size_t i = 0; i < contours.size(); ++i) {
cv::drawContours(srcBuffer, contours, i, Scalar(200, 0, 0), 1, 8, hierarchy, 0, Point());
cv::Rect brect = cv::boundingRect(contours[i]);
cv::rectangle(srcBuffer, brect, Scalar(255, 0, 0));
int result;
vector<Point> segment;
for (unsigned int row = brect.y; row < brect.y + brect.height; ++row) {
for (unsigned int col = brect.x; col < brect.x + brect.width; ++col) {
result = pointPolygonTest(contours[i], Point(col, row), false);
if (result == 1 || result == 0) {
segment.push_back(Point(col, row));
}
}
}
allSegments.push_back(segment);
}
output = Mat::zeros(src.size(), CV_8U);
int totalSize = output.rows*output.cols;
for (int segmentCount = 0; segmentCount < allSegments.size(); ++segmentCount) {
vector<Point> segment = allSegments[segmentCount];
if(segment.size() > totalSize*threshSize){
for (int idx = 0; idx < segment.size(); ++idx) {
output.at<uchar>(segment[idx].y, segment[idx].x) = 255;
}
}
}
return output;
}
I would suggest using morphological opening to get rid of the smaller blobs, followed by a morphological hole filling.