-
Notifications
You must be signed in to change notification settings - Fork 903
/
example_12-04.cpp
130 lines (106 loc) · 3.37 KB
/
example_12-04.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
// Example 12-4. Using Watershed for image segmentation
#include <iostream>
#include <string>
#include <opencv2/opencv.hpp>
using std::cout;
using std::cerr;
using std::endl;
cv::Mat img_preview;
cv::Mat img;
cv::Mat markers;
bool finished;
void displayResult() {
cv::imshow("image", img);
finished = true;
}
const int dx[4] = {-1, 1, 0, 0};
const int dy[4] = {0, 0, -1, 1};
void fillMarker(int x, int y, int marker_id) {
if (x < 0 || y < 0 || x >= markers.rows || y >= markers.cols) {
return;
}
if (markers.at<int>(x, y) != -1) {
return;
}
markers.at<int>(x, y) = marker_id;
for (int dir = 0; dir < 4; ++dir) {
int nx = x + dx[dir];
int ny = y + dy[dir];
fillMarker(nx, ny, marker_id);
}
}
static void onMouseClick(int event, int x, int y, int, void*) {
if (finished) {
return;
}
if (event == cv::EVENT_LBUTTONDOWN) {
cv::ellipse(markers, cv::Point(x, y), cv::Size(1, 1),
0, 0, 360, -1, 3);
cv::ellipse(img_preview, cv::Point(x, y), cv::Size(1, 1),
0, 0, 360, cv::Scalar(0, 0, 255), 3);
cv::imshow("image", img_preview);
return;
}
if (event == cv::EVENT_RBUTTONDOWN) {
int marker_id = 0;
for (int x = 0; x < markers.rows; ++x) {
for (int y = 0; y < markers.cols; ++y) {
if (markers.at<int>(x, y) == -1) {
++marker_id;
fillMarker(x, y, marker_id);
}
}
}
cv::watershed(img, markers);
cv::Vec3b borderColor(0, 0, 255);
for (int x = 0; x < img.rows; ++x) {
for (int y = 0; y < img.cols; ++y) {
if (markers.at<int>(x, y) == -1) {
img.at<cv::Vec3b>(x, y) = borderColor;
continue;
}
for (int dir = 0; dir < 4; ++dir) {
int nx = x + dx[dir];
int ny = y + dy[dir];
if (nx < 0 || ny < 0 || nx >= img.rows || ny >= img.cols) {
continue;
}
if (markers.at<int>(x, y) != markers.at<int>(nx, ny)) {
img.at<cv::Vec3b>(x, y) = borderColor;
}
}
}
}
displayResult();
return;
}
}
void help(char** argv) {
cout << "\nExample 12-4. Using Watershed for image segmentation"
<< "\n- Use left click on the image to place marker for the new segment"
<< "\n- Use right clock on the image to perform Watershed"
<< "\n- Press any key to terminate program"
<< "\nUsage: "
<< argv[0] << " <path/imagename>\n"
<< "\nExample:\n" << argv[0] << " ../stuff.jpg\n" << endl;
}
int main(int argc, char** argv) {
help(argv);
if (argc != 2) {
return -1;
}
img = cv::imread(std::string(argv[1]), CV_LOAD_IMAGE_COLOR);
if (img.channels() != 3) {
cerr << "Input image should have 3 channels" << endl;
exit(1);
}
markers = cv::Mat(img.size(), CV_32SC1);
markers.setTo(0);
img_preview = img.clone();
finished = false;
cv::namedWindow("image", cv::WINDOW_AUTOSIZE);
cv::setMouseCallback("image", onMouseClick, 0);
cv::imshow("image", img_preview);
cv::waitKey(0);
return 0;
}