How to find unique labels for segments in Superpix

2019-07-22 14:49发布

问题:

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.

回答1:

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.