4

I am now learning a code from the opencv codebook (OpenCV 2 Computer Vision Application Programming Cookbook): Chapter 5, Segmenting images using watersheds, page 131.

Here is my main code:

#include "opencv2/opencv.hpp"
#include <string>

using namespace cv;
using namespace std;

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

    cv::Mat process(const cv::Mat &image){
        cv::watershed(image,markers);
        return markers;
    }
};

int main ()
{
    cv::Mat image = cv::imread("/Users/yaozhongsong/Pictures/IMG_1648.JPG");

    // Eliminate noise and smaller objects
    cv::Mat fg;
    cv::erode(binary,fg,cv::Mat(),cv::Point(-1,-1),6);

    // Identify image pixels without objects
    cv::Mat bg;
    cv::dilate(binary,bg,cv::Mat(),cv::Point(-1,-1),6);
    cv::threshold(bg,bg,1,128,cv::THRESH_BINARY_INV);

    // Create markers image
    cv::Mat markers(binary.size(),CV_8U,cv::Scalar(0));
    markers= fg+bg;

    // Create watershed segmentation object
    WatershedSegmenter segmenter;
    // Set markers and process
    segmenter.setMarkers(markers);
    segmenter.process(image);

    imshow("a",image);
    std::cout<<".";
    cv::waitKey(0);
}

However, it doesn't work. How could I initialize a binary image? And how could I make this segmentation code work?

I am not very clear about this part of the book. Thanks in advance!

karlphillip
  • 92,053
  • 36
  • 243
  • 426
Yaozhong
  • 89
  • 1
  • 2
  • 7
  • Hi, Is your problem with understanding the code? Also check the versions of the OpenCV used. I have also heard that there are some errors in that book, i haven't checked it. – Abid Rahman K Jul 11 '12 at 16:42
  • I am using opencv 2.4.1...yea, I have some difficulty understanding this code... – Yaozhong Jul 11 '12 at 18:35
  • You can check the link i have set in my answer. Not about how algorithm works, but how it function can be used. – Abid Rahman K Jul 11 '12 at 18:36

3 Answers3

11

There's a couple of things that should be mentioned about your code:

  • Watershed expects the input and the output image to have the same size;
  • You probably want to get rid of the const parameters in the methods;
  • Notice that the result of watershed is actually markers and not image as your code suggests; About that, you need to grab the return of process()!

This is your code, with the fixes above:

// 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 binary;// = cv::imread(argv[2], 0);
    cv::cvtColor(image, binary, CV_BGR2GRAY);
    cv::threshold(binary, binary, 100, 255, THRESH_BINARY);

    imshow("originalimage", image);
    imshow("originalbinary", binary);

    // Eliminate noise and smaller objects
    cv::Mat fg;
    cv::erode(binary,fg,cv::Mat(),cv::Point(-1,-1),2);
    imshow("fg", fg);

    // Identify image pixels without objects
    cv::Mat bg;
    cv::dilate(binary,bg,cv::Mat(),cv::Point(-1,-1),3);
    cv::threshold(bg,bg,1, 128,cv::THRESH_BINARY_INV);
    imshow("bg", bg);

    // Create markers image
    cv::Mat markers(binary.size(),CV_8U,cv::Scalar(0));
    markers= fg+bg;
    imshow("markers", markers);

    // Create watershed segmentation object
    WatershedSegmenter segmenter;
    segmenter.setMarkers(markers);

    cv::Mat result = segmenter.process(image);
    result.convertTo(result,CV_8U);
    imshow("final_result", result);

    cv::waitKey(0);

    return 0;
}

I took the liberty of using Abid's input image for testing and this is what I got:

enter image description here

Mark Fu
  • 320
  • 2
  • 9
karlphillip
  • 92,053
  • 36
  • 243
  • 426
  • cool!it works!the size of original image and binary image should be the same. Thx! – Yaozhong Jul 11 '12 at 21:28
  • This is from 2012. OpenCV API may have changed a bit since then. What problems are you having? – karlphillip Oct 16 '17 at 22:29
  • @karlphillip I think he is referring to the fact that no segmentation has occurred? – Daniel Jun 20 '18 at 15:15
  • @Daniel "*Not working*" is a poor definition of the problem. I can't help anyone without more technical information. – karlphillip Jun 20 '18 at 18:01
  • Yeah it's just that what you've provided is a completely incorrect application of watershed. I think it is clear what @KansaiRobot is saying when s/he says "it is not working". All that's given is a solution for background subtraction. As [mmgp points out in the referenced thread](https://stackoverflow.com/a/14617359/84873), this is not the point of using watershed. Neither this answer nor Abid's should be upvoted in either thread, because **both are wrong**. A working watershed solution would segment the ROI, [like so](https://i.stack.imgur.com/wG5sQ.png). – Daniel Jun 21 '18 at 15:02
  • 1
    @Daniel Thanks for your comments. I would have never figured out all of that just from someone saying "*It's not working*". My first guess would be a compiler or a linker-related issue. – karlphillip Jun 21 '18 at 21:03
  • watershedding is separating the pills in the original image. Which the final result is *not* doing – KansaiRobot Jun 22 '18 at 07:24
  • Guys, I don't have access to the book and the OP also didn't ask help to **segment pills individually**. But more important than that, is that this answer was sufficient to help him solve his problem. There is no point on spending energy discussing an issue that was successfully closed 6 years ago. Now, **If you can provide a better answer, please write it!** As far as my choice to use watershed for something different, remember, watershed is just an algorithm. Computer algorithms have been used (for decades) to solve a multitude of problems that they weren't originally designed for. – karlphillip Jun 22 '18 at 15:19
4

Below is the simplified version of your code, and it works fine for me. Check it out :

#include "opencv2/objdetect/objdetect.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"

using namespace cv;
using namespace std;

int main ()
{
    Mat image = imread("sofwatershed.jpg");
    Mat binary = imread("sofwsthresh.png",0);

    // Eliminate noise and smaller objects
    Mat fg;
    erode(binary,fg,Mat(),Point(-1,-1),2);

    // Identify image pixels without objects
    Mat bg;
    dilate(binary,bg,Mat(),Point(-1,-1),3);
    threshold(bg,bg,1,128,THRESH_BINARY_INV);

// Create markers image
    Mat markers(binary.size(),CV_8U,Scalar(0));
    markers= fg+bg;

markers.convertTo(markers, CV_32S);
watershed(image,markers);

markers.convertTo(markers,CV_8U);
imshow("a",markers);
waitKey(0);
}

Below is my input image :

enter image description here

Below is my output image :

enter image description here

See the code explanation here : Simple watershed Sample in OpenCV

Community
  • 1
  • 1
Abid Rahman K
  • 51,886
  • 31
  • 146
  • 157
  • 1
    Thx! I have one question: what's the relationship between sofwatershed.jpg and sofwsthresh.png? – Yaozhong Jul 11 '12 at 18:24
  • OH. i am sorry. sofwatershed.png is the original image. sofwsthresh.png is the thresholded image. Actually i used Python. So i didn't want to binarize it again in C++. You can find those images in the link i have provided at end. – Abid Rahman K Jul 11 '12 at 18:27
  • I have a question, which image is your final segmentation image?is mat image?my image after the watershed function is the same as the original image... – Yaozhong Jul 11 '12 at 19:25
  • second image is the result. Actually i am not at all good in C++. I use Python only. – Abid Rahman K Jul 11 '12 at 19:28
  • @AbidRahmanK +1 I upvoted your answer for the initiative, but that won't show the OP his mistakes. So I added an answer as well. – karlphillip Jul 11 '12 at 21:22
  • @karlphillip: yeah, i know it. But as usual, C++ is still a tragedy for me :) – Abid Rahman K Jul 12 '12 at 05:15
0

I had the same problem as you, following the exact same code sample of the cookbook (great book btw).

Just to place the matter I was coding under Visual Studio 2013 and OpenCV 2.4.8. After a lot of searching and no solutions I decided to change the IDE.

It's still Visual Studio BUT it's 2010!!!! And boom it works!

Becareful of how you configure Visual Studio with OpenCV. Here's a great tutorial for installation here

Good day to all