Filling elements 2 (the triangle problem)

Related with my previous question "Filling elements" which was kindly solved by Michael Burdinov. I have the following question.

Filling Elements

What if I have a situation like the following: As you can see it is a little different than my previous question. If I apply the algorithm I got last time , the result is the following which is not the ideal I would like to get. Is there any way, or can any of you have any idea on how to get these elements filled without filling the space between them that is formed when they are in a triangle position?? (actually any closed position)

Any idea will be warmly welcomed

edit retag close merge delete

can you please post a link to the previous question? I cannot find it. If your element are like that, maybe the fitting ellipse or Hough line detection will work

2

actually if you could upload the source image, that might help.

1

Thanks for the comments. I edited the post to put a link to the previous question.

I haven't tried closing and opening this time, but my experience tells me (as I posted in the previous question) that first, closing sometimes have the undesirable effect of linking separated areas (that is why I posted the previous question) and also even when it works it would fill the insides of the triangle too.

I am thinking maybe some combination of opening closing and separating and joining elements would work, but would like to hear your ideas on this. (I am sure I am not the only one who has find himself in this situation)

what about showing us the source image, maybe there is a feature that can be used and it is not clear through the binary images that you have now

2

In another way you can try contour approach,

• Find contour(outermost only)
• Iterate through each contour.
• Draw contour with filled option.
1

@Haris this will not work because the outermost contour will fill the whole blob and he will get the same result as in the second image. Moreover, the inner contours (i.e. the 3 ellipses-ish and the triangle-ish) are all in the same level. So, you need one more procedure to distinguish what is what.

You are not getting the 3 ellipses and the triangle? Then you shall apply THRESH_BIN_INV flag and you should think of something for filtering the triangles, like area, or length

I suggest that you can use the algorithm of Haris, and for each contour you can get the bounding-box, the minrect, apply a hough transform to get the lines. With all this information, you can do a simple decisor to verify if the region is a triangle or not.

Sort by » oldest newest most voted Actually, you can use the approxPolyDP() function and approximate your contours with accuracy proportional to the contour perimeter. Here is some code:

#include <iostream>
#include <opencv2/opencv.hpp>

using namespace std;
using namespace cv;
int main()
{
Mat src = imread( "holes.jpg");
if( !src.data )
{ return -1; }

// Show source image
imshow("src", src); // Create binary image from source image
Mat bw;
cvtColor(src, bw, CV_BGR2GRAY);
threshold(bw, bw, 40, 255, CV_THRESH_BINARY | CV_THRESH_OTSU);
imshow("bin", bw); // Find contours
vector<Vec4i> hierarchy;
std::vector<std::vector<cv::Point> > contours;
cv::findContours(bw.clone(), contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0));

// The array for storing the approximation curve
std::vector<cv::Point> approx;

// We'll put the labels in this destination image
cv::Mat dst = Mat::zeros(bw.size(), CV_8UC1);

// Loop through detected contours, and process accordingly
for (int i = 0; i < contours.size(); i++)
{
// Approximate contour with accuracy proportional
// to the contour perimeter with approxPolyDP. In this,
// the third argument is called epsilon, which is maximum
// distance from contour to approximated contour. It is
// an accuracy parameter. A wise selection of epsilon is
//needed to get the correct output.
double epsilon = cv::arcLength(cv::Mat(contours[i]), true) * 0.1; // epsilon = 10% of arc length
cv::approxPolyDP(
cv::Mat(contours[i]),
approx,
epsilon,
true
);

// Skip small or convex objects
if (std::fabs(cv::contourArea(contours[i])) < 500 || cv::isContourConvex(approx))
continue;

drawContours(dst, contours, i, Scalar(255, 255, 255), CV_FILLED, 8, hierarchy, 0, Point());
}

imshow("contours", dst); // sum two images
dst += bw;

imshow("output", dst); waitKey(0);
return 0;
}

of course you should play with the epsilon value in order to pick a value robust enough for all of your cases. Enjoy.

more

1

another way to go would also be to use the approxPolyDP() function and approx structure to determine the shape of the contours but then complexity increases. I think the above approach is simple and fast.

Thank you. I will study your solution today, seems quite nice. and let you know.

I understand the general working of the algorithm. Quite neat, thank you. In it the approximation of the contours that are "convex" are eliminated.

So the remaining ones are concave?? I painted the approximations and found out that they are lines! (I suppose lines are considered concave??)

I haven't experiment it yet but does this means that this only works for long shapes like the picture and not say circles arranged in a closed formation... Thank you for your reply.

1

Yes the remaining ones are concave. As I am stating the important parameter here is the epsilon. If you want to detect other objects like triangles, circles, squares you should then use the convex objects which I am skipping here. Of course it would be wise to decrease the epsilon value in order to obtain more convexs and determine the object more accurately. Have a look in the following examples:

Contour Approximation

Detecting shapes in image

Detect Squares

Stats

Asked: 2015-02-10 03:01:41 -0500

Seen: 268 times

Last updated: Feb 12 '15