3

Hi i'm currently writing a basic C++ application using the OpenCV library to segment the subject of the image from its background. The application reads in an image file and uses the watershed algorithm to generate a mask based on data it finds around the edges and data it finds in the centre of the image.

(To start I created an image object that has an overall value of -1. Then I created a border around an empty image which has a value of 1. Then I created a rectangle roughly in the centre of the image which has a value of 2. The border and the rectangle are not touching.)

I attempt to remove data from the image using the generated mask using a bitwise AND between the original image and the auto-generated mask.

I have written this in C++ and would be very grateful if someone could take a quick look at my code. The only similar example I could find was using the native OpenCV bindings for Python.

Sample Mask: https://i.stack.imgur.com/wW0PJ.png

Sample Image: https://i.stack.imgur.com/w2Tpp.png

// Usage: ./app input.jpg
#include "opencv2/opencv.hpp"
#include <string>

using namespace cv;
using namespace std;

class WatershedSegmenter{
private:
    cv::Mat markers;
public:
    void setMarkers(cv::Mat& markerImage)
    {
        markerImage.convertTo(markers, CV_32S);
    }

    cv::Mat process(cv::Mat &image)
    {
        cv::watershed(image, markers);
        markers.convertTo(markers,CV_8U);
        return markers;
    }
};


int main(int argc, char* argv[])
{
    cv::Mat image = cv::imread(argv[1]);
    cv::Mat blank(image.size(),CV_8U,cv::Scalar(0xFF));
    cv::Mat dest(image.size(),CV_8U,cv::Scalar(0xFF));
    imshow("originalimage", image);

    // Create markers image
    cv::Mat markers(image.size(),CV_8U,cv::Scalar(-1));
    //Rect(topleftcornerX, topleftcornerY, width, height);
    //top rectangle
    markers(Rect(0,0,image.cols, 5)) = Scalar::all(1);
    //bottom rectangle
    markers(Rect(0,image.cols-5,image.cols, 5)) = Scalar::all(1);
    //left rectangle
    markers(Rect(0,0,5,image.rows)) = Scalar::all(1);
    //right rectangle
    markers(Rect(image.cols-5,0,5,image.rows)) = Scalar::all(1);
    //centre rectangle
    markers(Rect(image.cols/2,image.rows/2,50, 50)) = Scalar::all(2);


    //Create watershed segmentation object
    WatershedSegmenter segmenter;
    segmenter.setMarkers(markers);
    cv::Mat result = segmenter.process(image);
    result.convertTo(result,CV_8U);

    bitwise_and(image, blank, dest, result);
    imshow("final_result", dest);

    cv::waitKey(0);

    return 0;
}
Hugh Pearse
  • 699
  • 1
  • 7
  • 18

1 Answers1

8

Got it working!

// Usage: ./app input.jpg
#include "opencv2/opencv.hpp"
#include <string>

using namespace cv;
using namespace std;

class WatershedSegmenter{
private:
    cv::Mat markers;
public:
    void setMarkers(cv::Mat& markerImage)
    {
        markerImage.convertTo(markers, CV_32S);
    }

    cv::Mat process(cv::Mat &image)
    {
        cv::watershed(image, markers);
        markers.convertTo(markers,CV_8U);
        return markers;
    }
};


int main(int argc, char* argv[])
{
    cv::Mat image = cv::imread(argv[1]);
    cv::Mat blank(image.size(),CV_8U,cv::Scalar(0xFF));
    cv::Mat dest;
    imshow("originalimage", image);

    // Create markers image
    cv::Mat markers(image.size(),CV_8U,cv::Scalar(-1));
    //Rect(topleftcornerX, topleftcornerY, width, height);
    //top rectangle
    markers(Rect(0,0,image.cols, 5)) = Scalar::all(1);
    //bottom rectangle
    markers(Rect(0,image.rows-5,image.cols, 5)) = Scalar::all(1);
    //left rectangle
    markers(Rect(0,0,5,image.rows)) = Scalar::all(1);
    //right rectangle
    markers(Rect(image.cols-5,0,5,image.rows)) = Scalar::all(1);
    //centre rectangle
    int centreW = image.cols/4;
    int centreH = image.rows/4;
    markers(Rect((image.cols/2)-(centreW/2),(image.rows/2)-(centreH/2), centreW, centreH)) = Scalar::all(2);
    markers.convertTo(markers,CV_BGR2GRAY);
    imshow("markers", markers);

    //Create watershed segmentation object
    WatershedSegmenter segmenter;
    segmenter.setMarkers(markers);
    cv::Mat wshedMask = segmenter.process(image);
    cv::Mat mask;
    convertScaleAbs(wshedMask, mask, 1, 0);
    double thresh = threshold(mask, mask, 1, 255, THRESH_BINARY);
    bitwise_and(image, image, dest, mask);
    dest.convertTo(dest,CV_8U);

    imshow("final_result", dest);
    cv::waitKey(0);

    return 0;
}
Hugh Pearse
  • 699
  • 1
  • 7
  • 18
  • attached 2 images [flower-image](http://i.imgur.com/4sLUwM6h.jpg) [leaf-image](http://i.imgur.com/SF92dCQ.jpg) – Hugh Pearse Apr 18 '13 at 11:48
  • 3
    @Hugh If you solved your own problem, it is completely fine and appreciated to `accept` your own answer. I suggest you to point the problem you resolved, it can be helpful for others. Good Luck. – Pervez Alam Aug 07 '14 at 06:25