Toyo Toyo - 2 months ago 22
C++ Question

External and internal Edge Detection for ideal image

I am looking for an algorithm that can do external and internal contour detection on an ideal image containing only two different RGB values.

Below is a typical example of the image (first one) I want to process, next image is one I made myself showing the result I am expecting.

The last one is a result from OpenCV Canny detection made through the demo software available at OpenCV demo Software.

The canny algorithm is not satisfying as it is smoothing too much the shapes (especially corner).

Are there any elegant algorithm that could give the same results as in the second image?

Original Image

My own brain's contour detection and expected result

OpenCV -> Contour algorithm result

Answer

Contour extraction is the easiest thing to do this:

int main(int argc, char* argv[])
{
    cv::Mat input = cv::imread("C:/StackOverflow/Input/ContourExtraction.png");

    cv::Mat mask;
    // create a perfect mask: Easy if you know the 2 colors present in your image:
    cv::inRange(input, cv::Scalar(100, 0, 0), cv::Scalar(255, 255, 255), mask);
    cv::imshow("mask", mask);

    std::vector<std::vector<cv::Point> > contours; // contour points
    std::vector<cv::Vec4i> hierarchy; // this will give you the information whether it is an internal or external conotour.

    // contour extraction: This will alter the input image, so if you need it later use mask.clone() instead
    findContours(mask, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_NONE, cv::Point(0, 0)); // use different CV_CHAIN_APPROX_ if you dont need ALL the points but only the ones that dont lie on a common line

    // output images:
    cv::Mat contoursExternal = input.clone();
    cv::Mat contoursInternal = input.clone();
    cv::Mat contoursAll = cv::Mat::zeros(input.size(), CV_8UC1);

    // draw contours
    for (unsigned int i = 0; i < contours.size(); ++i)
    {
        cv::drawContours(contoursAll, contours, i, cv::Scalar::all(255), 1);
        if (hierarchy[i][3] != -1) cv::drawContours(contoursInternal, contours, i, cv::Scalar::all(255), 1);
        else cv::drawContours(contoursExternal, contours, i, cv::Scalar::all(255), 1);
    }

    cv::imshow("internal", contoursInternal);
    cv::imshow("external", contoursExternal);
    cv::imshow("all", contoursAll);


    cv::imshow("input", input);
    cv::waitKey(0);
    return 0;
}

giving these results:

External contours:

enter image description here

Internal contours:

enter image description here

result mask:

enter image description here

Comments