3
3
4
4
use opencv:: {
5
5
core:: { bitwise_and, find_file, CommandLineParser , Point , Scalar , CV_8UC1 , CV_8UC3 } ,
6
- highgui:: { self , * } ,
6
+ highgui:: { self , imshow } ,
7
7
imgcodecs:: { imread, IMREAD_COLOR } ,
8
8
imgproc,
9
9
prelude:: * ,
@@ -19,6 +19,16 @@ use std::{
19
19
20
20
const SOURCE_WINDOW : & str = "Source image" ;
21
21
22
+ #[ derive( Debug , Clone , Copy ) ]
23
+ enum DrawingState {
24
+ Init ,
25
+ DrawingMarkerPoint ,
26
+ DrawingMarkerPointFinished ,
27
+ DrawingMask ,
28
+ DrawingMaskFinished ,
29
+ Resetting ,
30
+ }
31
+
22
32
fn main ( ) {
23
33
let args: Vec < String > = env:: args ( ) . collect ( ) ;
24
34
let ( argc, argv) = ( args. len ( ) as i32 , args. iter ( ) . map ( |s| s. as_str ( ) ) . collect :: < Vec < & str > > ( ) ) ;
@@ -33,18 +43,23 @@ fn main() {
33
43
) ;
34
44
35
45
// 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 ] ;
46
+ let input_image = argv. into_iter ( ) . nth ( 2 ) . unwrap_or ( "lena.jpg" ) ;
47
+ let input_image_path = find_file ( input_image, true , false )
48
+ . map ( |path| {
49
+ println ! ( "find input_image {} in : {}" , input_image, path) ;
50
+ path
51
+ } )
52
+ . unwrap_or_else ( |_| panic ! ( "Cannot find input_image: {}" , input_image) ) ;
53
+
54
+ let [ src, mut next_frame, mut mask, mut final_img] : [ Mat ; 4 ] ;
40
55
src = imread ( & input_image_path, IMREAD_COLOR ) . unwrap ( ) ;
41
56
if src. empty ( ) {
42
57
eprintln ! ( "Error opening image: {}" , input_image) ;
43
58
process:: exit ( -1 ) ;
44
59
}
45
60
46
- highgui:: named_window ( SOURCE_WINDOW , WINDOW_AUTOSIZE ) . unwrap ( ) ;
47
- let mouse_event_data: ( i32 , i32 , i32 , i32 ) = Default :: default ( ) ;
61
+ highgui:: named_window ( SOURCE_WINDOW , highgui :: WINDOW_AUTOSIZE ) . unwrap ( ) ;
62
+ let mouse_event_data = ( highgui :: MouseEventTypes :: EVENT_MOUSEWHEEL , 0 , 0 , 0 ) ;
48
63
let ( mouse_event_data, should_handle_mouse_event) = ( Arc :: new ( Mutex :: new ( mouse_event_data) ) , Arc :: new ( AtomicBool :: new ( false ) ) ) ;
49
64
50
65
let mouse_event_dispatcher = {
@@ -54,7 +69,7 @@ fn main() {
54
69
move |event : i32 , x : i32 , y : i32 , flags : i32 | {
55
70
// can intercept specific mouse events here to don't update the mouse_data
56
71
if let Ok ( mut mouse_data) = mouse_data. lock ( ) {
57
- * mouse_data = ( event, x, y, flags) ;
72
+ * mouse_data = ( mouse_event_from_i32 ( event) , x, y, flags) ;
58
73
}
59
74
should_handle_mouse_event. store ( true , atomic:: Ordering :: Relaxed ) ;
60
75
}
@@ -63,10 +78,9 @@ fn main() {
63
78
64
79
highgui:: imshow ( SOURCE_WINDOW , & src) . unwrap ( ) ;
65
80
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 ( ) ;
81
+ let ( mut marker_points, mut drawing_state) = ( Vec :: < Point > :: new ( ) , DrawingState :: Init ) ;
68
82
69
- img1 = Mat :: new_size_with_default ( src. size ( ) . unwrap ( ) , CV_8UC3 , Scalar :: new ( 0.0 , 0.0 , 0.0 , 0.0 ) ) . unwrap ( ) ;
83
+ next_frame = Mat :: zeros_size ( src. size ( ) . unwrap ( ) , CV_8UC3 ) . unwrap ( ) . to_mat ( ) . unwrap ( ) ;
70
84
71
85
loop {
72
86
// Press Esc to exit
@@ -75,104 +89,141 @@ fn main() {
75
89
}
76
90
77
91
let ( mouse_event, x, y, _) = {
78
- if ! should_handle_mouse_event. load ( atomic:: Ordering :: Relaxed ) {
92
+ if should_handle_mouse_event. load ( atomic:: Ordering :: Relaxed ) {
79
93
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
94
} else {
86
- continue ;
87
- }
88
- } ;
95
+ should_handle_mouse_event. store ( false , atomic:: Ordering :: Relaxed ) ;
89
96
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 ( ) ;
97
+ if let Ok ( mouse_event_data) = mouse_event_data. lock ( ) {
98
+ * mouse_event_data
99
+ } else {
100
+ continue ;
119
101
}
120
102
}
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) ) ;
103
+ } ;
131
104
132
- right_button_down = true ;
133
- let mut img1 = src. clone ( ) ;
105
+ drawing_state = self :: state_transform ( drawing_state, mouse_event) ;
134
106
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 ( ) ;
107
+ match drawing_state {
108
+ DrawingState :: Init | DrawingState :: DrawingMarkerPointFinished => { /* do nothing */ }
109
+ DrawingState :: DrawingMarkerPoint => {
110
+ if marker_points. is_empty ( ) {
111
+ next_frame = src. clone ( ) ;
138
112
}
139
113
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. ) ,
114
+ let point = Point :: new ( x, y) ;
115
+ imgproc:: circle (
116
+ & mut next_frame,
117
+ point,
118
+ 2 ,
119
+ Scalar :: new ( 0. , 0. , 255. , 0. ) ,
120
+ -1 ,
155
121
imgproc:: LINE_8 ,
156
122
0 ,
157
- Point :: default ( ) ,
158
123
)
159
124
. unwrap ( ) ;
125
+ marker_points. push ( point) ;
126
+
127
+ if marker_points. len ( ) > 1 {
128
+ imgproc:: line (
129
+ & mut next_frame,
130
+ marker_points[ marker_points. len ( ) - 2 ] ,
131
+ point,
132
+ Scalar :: new ( 0. , 0. , 255. , 0. ) ,
133
+ 2 ,
134
+ imgproc:: LINE_8 ,
135
+ 0 ,
136
+ )
137
+ . unwrap ( ) ;
138
+ }
160
139
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 ( ) ;
140
+ imshow ( SOURCE_WINDOW , & next_frame) . unwrap ( ) ;
141
+ }
142
+ DrawingState :: DrawingMask => {
143
+ if !marker_points. is_empty ( ) {
144
+ next_frame = src. clone ( ) ;
145
+
146
+ let pts_mat = Mat :: from_slice ( marker_points. as_slice ( ) ) . unwrap ( ) ;
147
+ imgproc:: polylines (
148
+ & mut next_frame,
149
+ & pts_mat,
150
+ true ,
151
+ Scalar :: new ( 0. , 0. , 0. , 0. ) ,
152
+ 2 ,
153
+ imgproc:: LINE_8 ,
154
+ 0 ,
155
+ )
156
+ . unwrap ( ) ;
157
+
158
+ imshow ( SOURCE_WINDOW , & next_frame) . unwrap ( ) ;
159
+ }
160
+ }
161
+ DrawingState :: DrawingMaskFinished => {
162
+ if !marker_points. is_empty ( ) {
163
+ final_img = Mat :: zeros_size ( src. size ( ) . unwrap ( ) , CV_8UC3 ) . unwrap ( ) . to_mat ( ) . unwrap ( ) ;
164
+ mask = Mat :: zeros_size ( src. size ( ) . unwrap ( ) , CV_8UC1 ) . unwrap ( ) . to_mat ( ) . unwrap ( ) ;
165
+
166
+ imgproc:: fill_poly (
167
+ & mut mask,
168
+ & Mat :: from_slice ( marker_points. as_slice ( ) ) . unwrap ( ) ,
169
+ Scalar :: new ( 255. , 255. , 255. , 255. ) ,
170
+ imgproc:: LINE_8 ,
171
+ 0 ,
172
+ Point :: default ( ) ,
173
+ )
174
+ . unwrap ( ) ;
175
+
176
+ bitwise_and ( & src, & src, & mut final_img, & mask) . unwrap ( ) ;
177
+
178
+ imshow ( "Mask" , & mask) . unwrap ( ) ;
179
+ imshow ( "Result" , & final_img) . unwrap ( ) ;
180
+ imshow ( SOURCE_WINDOW , & next_frame) . unwrap ( ) ;
181
+ }
166
182
}
167
- EVENT_MBUTTONDOWN => {
168
- dbg ! ( ( mouse_event, x, y) ) ;
183
+ DrawingState :: Resetting => {
184
+ if !marker_points. is_empty ( ) {
185
+ marker_points. clear ( ) ;
186
+ next_frame = src. clone ( ) ;
169
187
170
- num_points_has_add = 0 ;
171
- points. clear ( ) ;
172
- img1 = src. clone ( ) ;
173
- imshow ( SOURCE_WINDOW , & img1) . unwrap ( ) ;
188
+ imshow ( SOURCE_WINDOW , & next_frame) . unwrap ( ) ;
189
+ }
174
190
}
175
- _ => { }
191
+ }
192
+ }
193
+ }
194
+
195
+ /// Converts an `i32` to a `opencv::highgui::MouseEventTypes`
196
+ ///
197
+ /// # Panics
198
+ ///
199
+ /// Panics if the argument less than 0 or greater than 11.
200
+ fn mouse_event_from_i32 ( value : i32 ) -> opencv:: highgui:: MouseEventTypes {
201
+ ( value. gt ( & ( opencv:: highgui:: MouseEventTypes :: EVENT_MOUSEHWHEEL as i32 ) /* 11 */ )
202
+ || ( value. lt ( & ( opencv:: highgui:: MouseEventTypes :: EVENT_MOUSEMOVE as i32 ) /* 0 */ ) ) )
203
+ . then ( || panic ! ( "Invalid cv::highgui::MouseEventTypes value: {}" , value) ) ;
204
+
205
+ // Safe because of the previous check
206
+ unsafe { std:: mem:: transmute ( value) }
207
+ }
208
+
209
+ fn state_transform ( drawing_state : DrawingState , mouse_event : highgui:: MouseEventTypes ) -> DrawingState {
210
+ use self :: DrawingState :: * ;
211
+ use opencv:: highgui:: MouseEventTypes :: * ;
212
+
213
+ match ( & drawing_state, mouse_event) {
214
+ ( Init , EVENT_LBUTTONDOWN ) => DrawingMarkerPoint ,
215
+ ( DrawingMarkerPoint , EVENT_LBUTTONUP ) => DrawingMarkerPointFinished ,
216
+ ( DrawingMarkerPointFinished , EVENT_LBUTTONDOWN ) => DrawingMarkerPoint ,
217
+ ( DrawingMarkerPointFinished , EVENT_RBUTTONDOWN ) => DrawingMask ,
218
+ ( DrawingMask , EVENT_RBUTTONUP ) => DrawingMaskFinished ,
219
+ ( Init | DrawingMarkerPointFinished | DrawingMaskFinished , EVENT_MBUTTONDOWN ) => Resetting ,
220
+ ( Resetting , EVENT_MBUTTONUP ) => Init ,
221
+ _ => {
222
+ println ! (
223
+ "Invalid state transition from {:?} with event {:?}" ,
224
+ drawing_state, mouse_event
225
+ ) ;
226
+ drawing_state
176
227
}
177
228
}
178
229
}
0 commit comments