Ask Your Question
0

Filling elements 2 (the triangle problem)

asked 2015-02-10 03:01:41 -0600

KansaiRobot gravatar image

updated 2015-02-11 18:23:14 -0600

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:

image description

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

image description

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 flag offensive close merge delete

Comments

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

thdrksdfthmn gravatar imagethdrksdfthmn ( 2015-02-10 06:02:45 -0600 )edit
2

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

theodore gravatar imagetheodore ( 2015-02-10 13:36:33 -0600 )edit

Have you tried closing + opening?

thdrksdfthmn gravatar imagethdrksdfthmn ( 2015-02-11 04:09:08 -0600 )edit
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)

KansaiRobot gravatar imageKansaiRobot ( 2015-02-11 18:27:16 -0600 )edit

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

theodore gravatar imagetheodore ( 2015-02-11 18:47:26 -0600 )edit
2

In another way you can try contour approach,

  • Find contour(outermost only)
  • Iterate through each contour.
  • Draw contour with filled option.
Haris gravatar imageHaris ( 2015-02-11 22:01:09 -0600 )edit
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.

theodore gravatar imagetheodore ( 2015-02-12 05:00:00 -0600 )edit

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

thdrksdfthmn gravatar imagethdrksdfthmn ( 2015-02-12 05:02:52 -0600 )edit

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.

Pakitobueu gravatar imagePakitobueu ( 2015-02-12 07:30:34 -0600 )edit

1 answer

Sort by ยป oldest newest most voted
3

answered 2015-02-12 07:58:43 -0600

theodore gravatar image

updated 2015-02-12 08:43:45 -0600

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()
{
    /// Load image
    Mat src = imread( "holes.jpg");
    if( !src.data )
      { return -1; }

    // Show source image
    imshow("src", src);

image description

    // 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);

image description

    // 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);

image description

    // sum two images
    dst += bw;

    imshow("output", dst);

image description

    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.

edit flag offensive delete link more

Comments

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.

theodore gravatar imagetheodore ( 2015-02-12 08:24:08 -0600 )edit

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

KansaiRobot gravatar imageKansaiRobot ( 2015-02-12 18:23:15 -0600 )edit

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.

KansaiRobot gravatar imageKansaiRobot ( 2015-02-13 04:02:05 -0600 )edit
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

theodore gravatar imagetheodore ( 2015-02-13 06:33:38 -0600 )edit

Question Tools

1 follower

Stats

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

Seen: 577 times

Last updated: Feb 12 '15