Search code examples
c++opencvedge-detection

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


Solution

  • 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