Skip to content

Commit 819b33c

Browse files
gfgafntwistedfall
authored andcommitted
chore: Add example to create mask and use set_mouse_callback
1 parent d2f3731 commit 819b33c

File tree

1 file changed

+178
-0
lines changed

1 file changed

+178
-0
lines changed

examples/create_mask.rs

Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
//! # Create Mask
2+
//! Reference: [opencv/samples/cpp/create_mask.cpp](https://github.com/opencv/opencv/blob/4.x/samples/cpp/create_mask.cpp)
3+
4+
use opencv::{
5+
core::{bitwise_and, find_file, CommandLineParser, Point, Scalar, CV_8UC1, CV_8UC3},
6+
highgui::{self, *},
7+
imgcodecs::{imread, IMREAD_COLOR},
8+
imgproc,
9+
prelude::*,
10+
};
11+
12+
use std::{
13+
env, process,
14+
sync::{
15+
atomic::{self, AtomicBool},
16+
Arc, Mutex,
17+
},
18+
};
19+
20+
const SOURCE_WINDOW: &str = "Source image";
21+
22+
fn main() {
23+
let args: Vec<String> = env::args().collect();
24+
let (argc, argv) = (args.len() as i32, args.iter().map(|s| s.as_str()).collect::<Vec<&str>>());
25+
26+
let mut parser = CommandLineParser::new(argc, &argv, "{@input | lena.jpg | input image}").unwrap();
27+
parser.about("This program demonstrates using mouse events\n").unwrap();
28+
parser.print_message().unwrap();
29+
println!(
30+
"\n\tleft mouse button - set a point to create mask shape\n\
31+
\tright mouse button - create mask from points\n\
32+
\tmiddle mouse button - reset"
33+
);
34+
35+
// HACK: replace with parser.get<String>("@input")
36+
let input_image = "lena.jpg";
37+
let input_image_path = find_file(input_image, true, false).expect("Cannot find input image");
38+
39+
let [src, mut img1, mut mask, mut final_img]: [Mat; 4];
40+
src = imread(&input_image_path, IMREAD_COLOR).unwrap();
41+
if src.empty() {
42+
eprintln!("Error opening image: {}", input_image);
43+
process::exit(-1);
44+
}
45+
46+
highgui::named_window(SOURCE_WINDOW, WINDOW_AUTOSIZE).unwrap();
47+
let mouse_event_data: (i32, i32, i32, i32) = Default::default();
48+
let (mouse_event_data, should_handle_mouse_event) = (Arc::new(Mutex::new(mouse_event_data)), Arc::new(AtomicBool::new(false)));
49+
50+
let mouse_event_dispatcher = {
51+
let mouse_data = Arc::clone(&mouse_event_data);
52+
let should_handle_mouse_event = Arc::clone(&should_handle_mouse_event);
53+
54+
move |event: i32, x: i32, y: i32, flags: i32| {
55+
// can intercept specific mouse events here to don't update the mouse_data
56+
if let Ok(mut mouse_data) = mouse_data.lock() {
57+
*mouse_data = (event, x, y, flags);
58+
}
59+
should_handle_mouse_event.store(true, atomic::Ordering::Relaxed);
60+
}
61+
};
62+
highgui::set_mouse_callback(SOURCE_WINDOW, Some(Box::new(mouse_event_dispatcher))).expect("Cannot set mouse callback");
63+
64+
highgui::imshow(SOURCE_WINDOW, &src).unwrap();
65+
66+
let (mut num_points_has_add, mut drag_left_button, mut right_button_down) = (0, false, false);
67+
let mut points = Vec::<Point>::new();
68+
69+
img1 = Mat::new_size_with_default(src.size().unwrap(), CV_8UC3, Scalar::new(0.0, 0.0, 0.0, 0.0)).unwrap();
70+
71+
loop {
72+
// Press Esc to exit
73+
if highgui::wait_key(10).unwrap() == 27 {
74+
break;
75+
}
76+
77+
let (mouse_event, x, y, _) = {
78+
if !should_handle_mouse_event.load(atomic::Ordering::Relaxed) {
79+
continue;
80+
}
81+
should_handle_mouse_event.store(false, atomic::Ordering::Relaxed);
82+
83+
if let Ok(mouse_event_data) = mouse_event_data.lock() {
84+
*mouse_event_data
85+
} else {
86+
continue;
87+
}
88+
};
89+
90+
match mouse_event {
91+
EVENT_LBUTTONDOWN => {
92+
dbg!((mouse_event, x, y));
93+
94+
if !drag_left_button && !right_button_down {
95+
if num_points_has_add == 0 {
96+
img1 = src.clone();
97+
}
98+
99+
let point = Point::new(x, y);
100+
imgproc::circle(&mut img1, point, 2, Scalar::new(0., 0., 255., 0.), -1, imgproc::LINE_8, 0).unwrap();
101+
points.push(point);
102+
num_points_has_add += 1;
103+
drag_left_button = true;
104+
105+
if num_points_has_add > 1 {
106+
imgproc::line(
107+
&mut img1,
108+
points[num_points_has_add - 2],
109+
point,
110+
Scalar::new(0., 0., 255., 0.),
111+
2,
112+
imgproc::LINE_8,
113+
0,
114+
)
115+
.unwrap();
116+
}
117+
118+
imshow(SOURCE_WINDOW, &img1).unwrap();
119+
}
120+
}
121+
EVENT_LBUTTONUP => {
122+
dbg!((mouse_event, x, y));
123+
124+
if drag_left_button {
125+
imshow(SOURCE_WINDOW, &img1).unwrap();
126+
drag_left_button = false;
127+
}
128+
}
129+
EVENT_RBUTTONDOWN => {
130+
dbg!((mouse_event, x, y));
131+
132+
right_button_down = true;
133+
let mut img1 = src.clone();
134+
135+
if num_points_has_add > 0 {
136+
let pts_mat = Mat::from_slice(points.as_slice()).unwrap();
137+
imgproc::polylines(&mut img1, &pts_mat, true, Scalar::new(0., 0., 0., 0.), 2, imgproc::LINE_8, 0).unwrap();
138+
}
139+
140+
imshow(SOURCE_WINDOW, &img1).unwrap();
141+
}
142+
EVENT_RBUTTONUP => {
143+
dbg!((mouse_event, x, y));
144+
145+
right_button_down = false;
146+
final_img = Mat::zeros_size(src.size().unwrap(), CV_8UC3).unwrap().to_mat().unwrap();
147+
148+
mask = Mat::zeros_size(src.size().unwrap(), CV_8UC1).unwrap().to_mat().unwrap();
149+
150+
let points_mat = Mat::from_slice(points.as_slice()).unwrap();
151+
imgproc::fill_poly(
152+
&mut mask,
153+
&points_mat,
154+
Scalar::new(255., 255., 255., 255.),
155+
imgproc::LINE_8,
156+
0,
157+
Point::default(),
158+
)
159+
.unwrap();
160+
161+
bitwise_and(&src, &src, &mut final_img, &mask).unwrap();
162+
163+
imshow("Mask", &mask).unwrap();
164+
imshow("Result", &final_img).unwrap();
165+
imshow(SOURCE_WINDOW, &img1).unwrap();
166+
}
167+
EVENT_MBUTTONDOWN => {
168+
dbg!((mouse_event, x, y));
169+
170+
num_points_has_add = 0;
171+
points.clear();
172+
img1 = src.clone();
173+
imshow(SOURCE_WINDOW, &img1).unwrap();
174+
}
175+
_ => {}
176+
}
177+
}
178+
}

0 commit comments

Comments
 (0)