Skip to content

Commit 09a3c14

Browse files
committed
Added cvWatershedSegmentation to the project.
1 parent 9b789e2 commit 09a3c14

File tree

4 files changed

+127
-0
lines changed

4 files changed

+127
-0
lines changed

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,3 +31,7 @@ QtFPSvsTIMEanimation
3131
--------------
3232
A Qt implementation of FPS-based and Time-based animation techniques, as explained by Steven Lambert:
3333
http://blog.sklambert.com/using-time-based-animation-implement/
34+
35+
cvWatershedSegmentation
36+
--------------
37+
A simple watershed segmentation example using distance transform to segment beans.

cvWatershedSegmentation/beans.png

36.5 KB
Loading

cvWatershedSegmentation/main.cpp

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
/* A simple Watershed segmentation example, as described at:
2+
* http://stackoverflow.com/a/25851951/176769
3+
*/
4+
#include <iostream>
5+
#include <vector>
6+
7+
#include <opencv2/highgui/highgui.hpp>
8+
#include <opencv2/imgproc/imgproc.hpp>
9+
10+
int main()
11+
{
12+
cv::Mat img = cv::imread("beans.png");
13+
if (img.empty())
14+
{
15+
std::cout << "!!! Failed to open image" << std::endl;
16+
return -1;
17+
}
18+
19+
/* Pre-processing */
20+
21+
// Convert input image to grayscale
22+
cv::Mat img_gray;
23+
cv::cvtColor(img, img_gray, cv::COLOR_BGR2GRAY);
24+
25+
// Threshold the image and retrieve its binary representation
26+
cv::Mat img_bin;
27+
cv::threshold(img_gray, img_bin, 128, 255, cv::THRESH_OTSU | cv::THRESH_BINARY_INV);
28+
cv::imwrite("img_bin.png", img_bin);
29+
30+
// Remove small objects (noises)
31+
cv::Mat three_by_three_element(5, 5, CV_8U, cv::Scalar(1));
32+
cv::morphologyEx(img_bin, img_bin, cv::MORPH_OPEN, three_by_three_element);
33+
cv::imwrite("img_bin_morphoEx.png", img_bin);
34+
35+
/* Processing */
36+
37+
// Get the borders of the objects (beans)
38+
cv::Mat dilation, erosion;
39+
cv::dilate(img_bin, dilation, cv::Mat(), cv::Point(-1,-1), 3);
40+
cv::erode(dilation, erosion, cv::Mat());
41+
cv::Mat border(img_bin.size(), CV_8U, cv::Scalar(0));
42+
border = dilation - erosion;
43+
cv::imwrite("border.png", border);
44+
45+
// Get the distance transform and normalize the result to [0,255]
46+
cv::Mat dt;
47+
cv::distanceTransform(img_bin, dt, cv::DIST_L2, 5);
48+
cv::normalize(dt, dt, 0, 255, cv::NORM_MINMAX);
49+
50+
// Threshold it to isolate the peaks
51+
cv::threshold(dt, dt, 135, 255, cv::THRESH_BINARY);
52+
cv::imwrite("dt_thres.png", dt);
53+
54+
// Use connectedComponents() to isolate the objects
55+
dt.convertTo(dt, CV_8U);
56+
cv::Mat lbl(dt.size(), CV_32S);
57+
int ncc = cv::connectedComponents(dt, lbl, 4);
58+
//std::cout << "Number of Connected Components: " << ncc << std::endl;
59+
60+
// Create a gray color spectrum to paint the peaks
61+
std::vector<unsigned char> colors(ncc);
62+
colors[0] = 0; // for background
63+
for(int label = 1; label < ncc; ++label)
64+
colors[label] = 255/ncc*label;
65+
66+
// Paint every peak (bean candidate) with a shade of gray
67+
for (int x = 0; x < dt.rows; x++) {
68+
for (int y = 0; y < dt.cols; y++) {
69+
int label = lbl.at<int>(x, y);
70+
dt.at<unsigned char>(x, y) = colors[label];
71+
}
72+
}
73+
cv::imwrite("conn_comp.png", dt);
74+
75+
// Create the marker image for watershed
76+
cv::Mat markers = cv::Mat::zeros(dt.size(), CV_8U);
77+
markers = dt + border;
78+
cv::imwrite("markers.png", markers);
79+
80+
markers.convertTo(markers, CV_32SC1);
81+
cv::watershed(img, markers);
82+
83+
markers.convertTo(markers, CV_8U);
84+
markers = 255 - markers; // cv::bitwise_not()
85+
cv::imwrite("watershed.png", markers);
86+
87+
// Create a green mask with the sillhuete of the detected objects
88+
cv::Mat green_mask = cv::Mat::zeros(markers.size(), CV_8UC3);
89+
for (int i = 0; i < markers.rows; i++)
90+
{
91+
for (int j = 0; j < markers.cols; j++)
92+
{
93+
// Draw the marker's silhuete (white) as green in the mask
94+
if (markers.at<unsigned char>(i,j) == 255)
95+
green_mask.at<cv::Vec3b>(i,j) = cv::Vec3b(0, 255, 0);
96+
}
97+
}
98+
99+
cv::dilate(green_mask, green_mask, cv::Mat());
100+
cv::imshow(std::string("result"), green_mask);
101+
102+
cv::Mat result = img + green_mask;
103+
cv::imshow(std::string("result"), result);
104+
cv::imwrite("result.png", result);
105+
106+
cv::waitKey(0);
107+
108+
return 0;
109+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
## OpenCV settings for Windows and OpenCV 3.0 Alpha
2+
win32 {
3+
message("* Using settings for Windows.")
4+
INCLUDEPATH += "C:\\opencv\\build\\include" \
5+
"C:\\opencv\\build\\include\\opencv" \
6+
"C:\\opencv\\build\\include\\opencv2"
7+
8+
LIBS += -L"C:\\opencv\\build\\x86\\vc12\\lib" \
9+
-lopencv_world300d
10+
}
11+
12+
SOURCES += \
13+
main.cpp
14+

0 commit comments

Comments
 (0)