c++opencvopencv3.0superpixels

How to find unique labels for segments in SuperpixelSLIC


I am using cv::ximgproc::SuperpixelSLIC opencv c++ to generate segments of image. I want each segment label to be unique. Here is my code.

Mat segmentImage() {
    int num_iterations = 4;
    int prior = 2;
    bool double_step = false;
    int num_levels = 10;
    int num_histogram_bins = 5;

    int width, height;

    width = h1.size().width;
    height = h1.size().height;

    seeds = createSuperpixelSLIC(h1);

    Mat mask;

    seeds->iterate(num_iterations);

    Mat labels;
    seeds->getLabels(labels);
    for (int i = 0; i < labels.rows; i++) {
        for (int j = 0; j < labels.cols; j++) {
            if (labels.at<int>(i, j) == 0)
                cout << i << " " << j << " " << labels.at<int>(i, j) << endl;

        }
    }
    ofstream myfile;
    myfile.open("label.txt");
    myfile << labels;
    myfile.close();

    seeds->getLabelContourMask(mask, false);
    h1.setTo(Scalar(0, 0, 255), mask);

    imshow("result", h1);
    imwrite("result.png", h1);
    return labels;
}

In label.txt file I observe that label 0 has been given to two segments (i.e. segment include pixel(0,0) and pixel(692,442). These two segments are pretty far away.

Is this normal thing or my code is incorrect. Please help me to find unique label for each segment.


Solution

  • What you essentially need is a connected components algorithm. Without knowing the exact SLIC implementation you use, SLIC usually tends to produce disconnected superpixels, i.e. disconnected segments with the same label. A simple solution I used is the connected components algorithm form here: https://github.com/davidstutz/matlab-multi-label-connected-components (originally from here: http://xenia.media.mit.edu/~rahimi/connected/). Note that this repository contains a MatLab wrapper. In your case you only need connected_components.h together with the following code:

    #include "connected_components.h"
    // ...
    
    void relabelSuperpixels(cv::Mat &labels) {
    
        int max_label = 0;
        for (int i = 0; i < labels.rows; i++) {
            for (int j = 0; j < labels.cols; j++) {
                if (labels.at<int>(i, j) > max_label) {
                    max_label = labels.at<int>(i, j);
                }
            }
        }
    
        int current_label = 0;
        std::vector<int> label_correspondence(max_label + 1, -1);
    
        for (int i = 0; i < labels.rows; i++) {
            for (int j = 0; j < labels.cols; j++) {
                int label = labels.at<int>(i, j);
    
                if (label_correspondence[label] < 0) {
                    label_correspondence[label] = current_label++;
                }
    
                labels.at<int>(i, j) = label_correspondence[label];
            }
        }
    }
    
    int relabelConnectedSuperpixels(cv::Mat &labels) {
    
        relabelSuperpixels(labels);
    
        int max = 0;
        for (int i = 0; i < labels.rows; ++i) {
            for (int j = 0; j < labels.cols; ++j) {
                if (labels.at<int>(i, j) > max) {
                    max = labels.at<int>(i, j);
                }
            }
        }
    
        ConnectedComponents cc(2*max);
    
        cv::Mat components(labels.rows, labels.cols, CV_32SC1, cv::Scalar(0));
        int component_count = cc.connected<int, int, std::equal_to<int>, bool>((int*) labels.data, (int*) components.data, labels.cols, 
                labels.rows, std::equal_to<int>(), false);
    
        for (int i = 0; i < labels.rows; i++) {
            for (int j = 0; j < labels.cols; j++) {
                labels.at<int>(i, j) = components.at<int>(i, j);
            }
        }
    
        // component_count would be the NEXT label index, max is the current highest!
        return component_count - max - 1;
    }
    

    On the obtained labels, run relabelConnectedSuperpixels.