How to draw contours of each segmented object [closed]

asked 2015-11-06 09:35:39 -0500

vitruvius gravatar image


I apply watershed segmentation to detect touching objects. It works okay. Now, I would like to draw contours of each object. But the objects in the result of the segmentation are still touching. So, I fail to draw contours of each one. How can I apply a mask for each object? Then I could draw contours separately.

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

using namespace std;
using namespace cv;

int main()
    Mat src = imread("source.png");

    // Create binary image from source image
    Mat srcGray;
    cvtColor(src, srcGray, CV_BGR2GRAY);

    Mat srcThresh;
    threshold(srcGray, srcThresh, 0, 255, CV_THRESH_BINARY | CV_THRESH_OTSU);

    // Perform the distance transform algorithm
    Mat dist;
    distanceTransform(srcThresh, dist, CV_DIST_L2, 3);

    // Normalize the distance image for range = {0.0, 1.0}
    normalize(dist, dist, 0, 1., NORM_MINMAX);

    // Threshold to obtain the peaks 
    threshold(dist, dist, 0.1, 3.5, CV_THRESH_BINARY);

    // Create the CV_8U version of the distance image
    Mat dist_8u;
    dist.convertTo(dist_8u, CV_8U);

    // Find total markers
    vector<vector<Point> > contours;
    findContours(dist_8u, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);
    int ncomp = contours.size();

    // Create the marker image for the watershed algorithm
    Mat markers = Mat::zeros(dist.size(), CV_32SC1);

    // Draw the foreground markers
    for (int i = 0; i < ncomp; i++)
        drawContours(markers, contours, i, Scalar::all(i + 1), -1);

    // Draw the background marker
    circle(markers, Point(5, 5), 3, CV_RGB(255, 255, 255), -1);

    // Perform the watershed algorithm
    watershed(src, markers);

    Mat wgResult = (markers.clone()) * 10000;

    imshow("Watershed", wgResult);

    return 0;


image description

Watershed result: image description

edit retag flag offensive reopen merge delete

Closed for the following reason the question is answered, right answer was accepted by sturkmen
close date 2020-09-24 18:47:58.679637


Your objects have different color in the output of th watershed. So, just threshold the image to get each of them.

LorenaGdL gravatar imageLorenaGdL ( 2015-11-07 05:08:19 -0500 )edit

@LorenaGdL Yes, but I need a general solution as number of the objects could be different. So I looked at the tutorial on about how each object gets filled with random color. I modified it in a way that I could store each object in a vector.

vector<Mat> images;
    for (int obj = 1; obj < contours.size() + 1; obj++)
        for (int i = 0; i < markers.rows; i++)
            for (int j = 0; j < markers.cols; j++)
                int index =<int>(i, j);
                if (index == obj && index <= static_cast<int>(contours.size()))
          <Vec3b>(i, j) = colors[index - 1];
          <Vec3b>(i, j) = Vec3b(0, 0, 0);

But I keep getting the object on the right, in images[0] and images[1]

vitruvius gravatar imagevitruvius ( 2015-11-07 10:39:04 -0500 )edit


LorenaGdL gravatar imageLorenaGdL ( 2015-11-07 12:06:59 -0500 )edit

However, if you want my 2cts on this, you can easily avoid those per-pixel loops and get your original image segmented in 5 lines:

vector<Mat> images2;
for (int obj = 1; obj < contours.size() + 1; obj++)
    Mat dst2;
    src.copyTo(dst2, (markers == obj));
LorenaGdL gravatar imageLorenaGdL ( 2015-11-07 12:20:56 -0500 )edit

@LorenaGdL Thanks, I managed to do what I wanted. I will post an answer but turns out I have to wait 2 days for that.

vitruvius gravatar imagevitruvius ( 2015-11-08 05:50:42 -0500 )edit

Is there then a way to get the number of pixels of the largest object, 2nd largest, 3rd on?

vom gravatar imagevom ( 2019-09-23 05:49:01 -0500 )edit