Ask Your Question
0

How to get a connected component in one Mat

asked 2018-01-24 08:09:52 -0600

yode gravatar image

updated 2018-01-24 08:55:34 -0600

I have such image

I hope to get one connected component in one Mat with an efficient method. So I have write such code to implement it.

 #include<opencv.hpp>
using namespace std;
using namespace cv;

int main() {

    Mat bin_img = Mat::zeros(10, 10, CV_8UC1);
    rectangle(bin_img, Point(1, 2), Point(3, 4), Scalar(255), -1);
    circle(bin_img, Point(5, 7), 2, Scalar(255), -1);

    int img_height = bin_img.rows, img_width = bin_img.cols;
    Mat labels;
    int n = connectedComponents(bin_img, labels);
    vector<Mat> masks(n - 1, Mat::zeros(bin_img.size(), CV_8UC1));

    Mat mask1 = masks[0];
    Mat mask2 = masks[1];
    for (int i = 0; i < img_height; i++)
    {
        int*plabels = labels.ptr<int>(i);
        for (int j = 0; j < img_width; j++)
        {
            if (plabels[j] != 0)
            {
                uchar* pmask = masks[plabels[j] - 1].ptr<uchar>(i);
                pmask[j] = 255;
            }
        }
        cout << endl;

    }
    for (int i = 0; i < n - 1; i++)
        imshow(to_string(i), masks[i]);

    waitKey(0);
    return 0;
}

But I don't know why all my element in vector masks is same totally.


update

Of course, I know there are some method can do this, such as compare in fllowing anser or inRange or operator ==. But I hope to use .ptr method here. Could anybody can give me a hand?

edit retag flag offensive close merge delete

1 answer

Sort by ยป oldest newest most voted
1

answered 2018-01-24 08:27:12 -0600

berak gravatar image

updated 2018-01-24 10:00:09 -0600

it maybe far easier, than you thought:

Mat labels;
int n = connectedComponents(bin_img, labels);
// now, we have n-1 different components there,
// (0 is background)
// get the mask for each of them
vector<Mat> masks;
for (size_t i=1; i<n; i++) {
    Mat mask;
    compare(labels, Scalar(i), mask, CMP_EQ);
    masks.push_back(mask);
}

But I don't know why all my element in vector masks is same totally.

there is a pitfall with this vector constructor:

vector<Mat> vm(27,Mat(3,3,0,17));

now you have 27 items in the vector, but they all are the same Mat, pointing to the same data !

the only way around that is initializing them in a loop:

vector<Mat> vm(27);
for (int i=0; i<27; i++)
     vm[i] = Mat(3,3,0,17);
edit flag offensive delete link more

Comments

Actually if I use operator ==, it will be very ease too. But I hope to use method based on .ptr.Because the actual bin_img is very big and .ptr is fastest as I know. Could you help me to find any mistake in my code?

yode gravatar imageyode ( 2018-01-24 08:48:07 -0600 )edit

writing per-pixel loops is the 1st mistake, don't do that !

(an no, it won't be faster, if you try to overtake the opencv devs on the left lane ...)

berak gravatar imageberak ( 2018-01-24 08:49:41 -0600 )edit

Thanks a lot. I have ever tried inRange, compare and == method. But none of them is faster than .ptr. So I expected an answer based on .ptr still.

yode gravatar imageyode ( 2018-01-24 08:57:32 -0600 )edit

that's bs.

berak gravatar imageberak ( 2018-01-24 08:59:29 -0600 )edit

Done, as your update~ https://i.stack.imgur.com/MMSo4.png. Thanks very very very much..

yode gravatar imageyode ( 2018-01-24 09:04:02 -0600 )edit

Question Tools

1 follower

Stats

Asked: 2018-01-24 08:09:52 -0600

Seen: 385 times

Last updated: Jan 24 '18