How to run findContours() on meanShiftSegmentation() output?

asked 2013-08-29 19:23:32 -0500

B. Bogart gravatar image

I'm trying to rewrite my very slow naive segmentation using floodFill to something faster. I ruled out meanShiftFiltering a year ago because of the difficulty in labelling the colours and then finding their contours.

The current version of opencv seems to have a fast new function that labels segments using mean shift: gpu::meanShiftSegmentation(). It produces images like the following:

meanShiftSegmentation() output

So this looks to me pretty close to being able to generating contours. How can I run findContours to generate segments?

Seems to me, this would be done by extracting the labelled colours from the image, and then testing which pixel values in the image match each label colour to make a boolean image suitable for findContours. This is what I have done in the following (but its a bit slow and strikes me there should be a better way):

Mat image = imread("test.png");

...
// gpu operations on image resulting in gpuOpen
...

// Mean shift
TermCriteria iterations = TermCriteria(CV_TERMCRIT_ITER, 2, 0);
gpu::meanShiftSegmentation(gpuOpen, segments, 10, 20, 300, iterations);

// convert to greyscale (HSV image)
vector<Mat> channels;
split(segments, channels);

// get labels from histogram of image.
int size = 256;
labels = Mat(256, 1, CV_32SC1);
calcHist(&channels.at(2), 1, 0, Mat(), labels, 1, &size, 0);

// Loop through hist bins
for (int i=0; i<256; i++) {
    float count = labels.at<float>(i);

    // Does this bin represent a label in the image?
    if (count > 0) {
        // find areas of the image that match this label and findContours on the result.
        Mat label = Mat(channels.at(2).rows, channels.at(2).cols, CV_8UC1, Scalar::all(i)); // image filled with label colour.
        Mat boolImage = (channels.at(2) == label); // which pixels in labeled image are identical to this label?
        vector<vector<Point>> labelContours;
        findContours(boolImage, labelContours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);
        // Loop through contours.
        for (int idx = 0; idx < labelContours.size(); idx++) {
            // get bounds for this contour.
            bounds = boundingRect(labelContours[idx]);

            // create ROI for bounds to extract this region
            Mat patchROI = image(bounds);
            Mat maskROI = boolImage(bounds);
        }
    }
}

Is this the best approach or is there a better way to get the label colours? Seems it would be logical for meanShiftSegmentation to provide this information? (vector of colour values, or vector of masks for each label, etc.)

Thank you.

edit retag flag offensive close merge delete