watershed segmentation opencv xcode
Solution 1
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 notimage
as your code suggests; About that, you need to grab the return ofprocess()
!
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:
Solution 2
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 :
Below is my output image :
See the code explanation here : Simple watershed Sample in OpenCV
Yaozhong
Updated on May 16, 2020Comments
-
Yaozhong about 4 years
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!
-
Yaozhong almost 12 yearsThx! I have one question: what's the relationship between sofwatershed.jpg and sofwsthresh.png?
-
Abid Rahman K almost 12 yearsOH. 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.
-
Yaozhong almost 12 yearsI 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...
-
Abid Rahman K almost 12 yearssecond image is the result. Actually i am not at all good in C++. I use Python only.
-
karlphillip almost 12 years@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.
-
Yaozhong almost 12 yearscool!it works!the size of original image and binary image should be the same. Thx!
-
Abid Rahman K almost 12 years@karlphillip: yeah, i know it. But as usual, C++ is still a tragedy for me :)
-
karlphillip over 6 yearsThis is from 2012. OpenCV API may have changed a bit since then. What problems are you having?
-
Daniel almost 6 years@karlphillip I think he is referring to the fact that no segmentation has occurred?
-
karlphillip almost 6 years@Daniel "Not working" is a poor definition of the problem. I can't help anyone without more technical information.
-
Daniel almost 6 yearsYeah 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, 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.
-
karlphillip almost 6 years@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.
-
KansaiRobot almost 6 yearswatershedding is separating the pills in the original image. Which the final result is not doing
-
karlphillip almost 6 yearsGuys, 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.