17
votes

When you retrieve contours from an image, you should get 2 contours per blob - one inner and one outer. Consider the circle below - since the circle is a line with a pixel width larger than one, you should be able to find two contours in the image - one from the inner part of the circle and one from the outer part.

Using OpenCV, I want to retrieve the INNER contours. However, when I use findContours (), I only seem to be getting the outer contours. How would I retrieve the inner contours of a blob using OpenCV?

I am using the C++ API, not C therefore only suggest functions that use the C++ API. (i.e. findContours () rather than cvFindContours ())

Thanks.

enter image description here

3
Well, I don't really have any unique code. I just have a Mat I retrieve from the camera. I run the canny edge detector on it, and then find contours using findContours (). All contours found are stored in a vector<vector<Point> >. Thats basically all I have so there isn't much point in me posting actual code - its just the traditional process of finding contours.fdh
I have worked a bit with contours, though my interest was only the outer contours. I tried colororing a contour, with 'drawContours()'. Which exspects a sort of hierachy. The sample on 'drawContours()' that I used, did not color inner contours. What I'm trying to get at here, is that you probably need to use the hierachy array from 'findContours()' to sort them. (The reason I do not post an answer is that my knowledge of this hierachy is limited, an I would not want to confuse you on the matter. I have done a bit of testing on these and I could explain my understanding so far, if you request.)Sonaten
Thanks for answering. If possible, I would appreciate it if you could explain your understanding of hierarchies so far. Thanks.fdh
the external and internal boundary contours can be accessed using the h_next and v_next pointers in the CvSeq* structure where the contours are stored by the findContours() function. Here's a link from the book about how this is organised (I always dealt with just the external contours so there isn't any working code to post): books.google.co.in/…AruniRC
I am using the C++ API not the C therefore I am not using CvSeq. I'm using vector<vector<Point> >fdh

3 Answers

31
votes

I ran this code on your image and it returned an inner and outer contour.

#include <iostream>
#include "opencv2/core/core.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"

int main(int argc, const char * argv[]) {

    cv::Mat image= cv::imread("../../so8449378.jpg");
    if (!image.data) {
        std::cout << "Image file not found\n";
        return 1;
    }

    //Prepare the image for findContours
    cv::cvtColor(image, image, CV_BGR2GRAY);
    cv::threshold(image, image, 128, 255, CV_THRESH_BINARY);

    //Find the contours. Use the contourOutput Mat so the original image doesn't get overwritten
    std::vector<std::vector<cv::Point> > contours;
    cv::Mat contourOutput = image.clone();
    cv::findContours( contourOutput, contours, CV_RETR_LIST, CV_CHAIN_APPROX_NONE );

    //Draw the contours
    cv::Mat contourImage(image.size(), CV_8UC3, cv::Scalar(0,0,0));
    cv::Scalar colors[3];
    colors[0] = cv::Scalar(255, 0, 0);
    colors[1] = cv::Scalar(0, 255, 0);
    colors[2] = cv::Scalar(0, 0, 255);
    for (size_t idx = 0; idx < contours.size(); idx++) {
        cv::drawContours(contourImage, contours, idx, colors[idx % 3]);
    }

    cv::imshow("Input Image", image);
    cvMoveWindow("Input Image", 0, 0);
    cv::imshow("Contours", contourImage);
    cvMoveWindow("Contours", 200, 0);
    cv::waitKey(0);

    return 0;
}

Here are the contours it found:

findContour result image

3
votes

I think what Farhad is asking is to crop the contour from the original image.

To do that you will need to find the contour as explained above, then use a mask to get the inside from the original, and then crop the result into an image with the same size as the contour.

0
votes

The findcontours function stores all the contours in different vectors, in the code given all contours are drawn, you just have draw the contour corresponding to the inner one, idx is the variable that states which contour is drawn.