1 /*
2 * GStreamer hand gesture detection plugins
3 * Copyright (C) 2012 Andol Li <<andol@andol.info>>
4 * Copyright (C) 2013 Sreerenj Balachandran <sreerenj.balachandran@intel.com>
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
23 *
24 * Alternatively, the contents of this file may be used under the
25 * GNU Lesser General Public License Version 2.1 (the "LGPL"), in
26 * which case the following provisions apply instead of the ones
27 * mentioned above:
28 *
29 * This library is free software; you can redistribute it and/or
30 * modify it under the terms of the GNU Library General Public
31 * License as published by the Free Software Foundation; either
32 * version 2 of the License, or (at your option) any later version.
33 *
34 * This library is distributed in the hope that it will be useful,
35 * but WITHOUT ANY WARRANTY; without even the implied warranty of
36 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
37 * Library General Public License for more details.
38 *
39 * You should have received a copy of the GNU Library General Public
40 * License along with this library; if not, write to the
41 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
42 * Boston, MA 02111-1307, USA.
43 */
44 /**
45 * SECTION:video-filter-handdetect
46 *
47 * FIXME:operates hand gesture detection in video streams and images,
48 * and enable media operation e.g. play/stop/fast forward/back rewind.
49 *
50 * ## Example launch line
51 *
52 * |[
53 * gst-launch-1.0 autovideosrc ! videoconvert ! "video/x-raw, format=RGB, width=320, height=240" ! \
54 * videoscale ! handdetect ! videoconvert ! xvimagesink
55 * ]|
56 */
57
58 #ifdef HAVE_CONFIG_H
59 #include <config.h>
60 #endif
61
62 /* element header */
63 #include "gsthanddetect.h"
64 #include <opencv2/imgproc.hpp>
65
66 GST_DEBUG_CATEGORY_STATIC (gst_handdetect_debug);
67 #define GST_CAT_DEFAULT gst_handdetect_debug
68 #if (CV_MAJOR_VERSION < 4)
69 #define CASCADE_DO_CANNY_PRUNING CV_HAAR_DO_CANNY_PRUNING
70 #endif
71
72 /* define HAAR files */
73 #define HAAR_FILE_FIST GST_HAAR_CASCADES_DIR G_DIR_SEPARATOR_S "fist.xml"
74 #define HAAR_FILE_PALM GST_HAAR_CASCADES_DIR G_DIR_SEPARATOR_S "palm.xml"
75
76 using namespace cv;
77 using namespace std;
78 /* Filter signals and args */
79 enum
80 {
81 /* FILL ME */
82 LAST_SIGNAL
83 };
84
85 enum
86 {
87 PROP_0,
88 PROP_DISPLAY,
89 PROP_PROFILE_FIST,
90 PROP_PROFILE_PALM,
91 PROP_ROI_X,
92 PROP_ROI_Y,
93 PROP_ROI_WIDTH,
94 PROP_ROI_HEIGHT
95 };
96
97 /* the capabilities of the inputs and outputs */
98 static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
99 GST_PAD_SINK,
100 GST_PAD_ALWAYS,
101 GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("RGB"))
102 );
103 static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
104 GST_PAD_SRC,
105 GST_PAD_ALWAYS,
106 GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("RGB"))
107 );
108
109 static void gst_handdetect_set_property (GObject * object, guint prop_id,
110 const GValue * value, GParamSpec * pspec);
111 static void gst_handdetect_get_property (GObject * object, guint prop_id,
112 GValue * value, GParamSpec * pspec);
113 static gboolean gst_handdetect_set_caps (GstOpencvVideoFilter * transform,
114 gint in_width, gint in_height, int in_cv_type,
115 gint out_width, gint out_height, int out_cv_type);
116 static GstFlowReturn gst_handdetect_transform_ip (GstOpencvVideoFilter *
117 transform, GstBuffer * buffer, Mat img);
118
119 static CascadeClassifier *gst_handdetect_load_profile (GstHanddetect * filter,
120 gchar * profile);
121
122 static void gst_handdetect_navigation_interface_init (GstNavigationInterface *
123 iface);
124 static void gst_handdetect_navigation_send_event (GstNavigation * navigation,
125 GstStructure * structure);
126
127 G_DEFINE_TYPE_WITH_CODE (GstHanddetect, gst_handdetect,
128 GST_TYPE_OPENCV_VIDEO_FILTER,
129 G_IMPLEMENT_INTERFACE (GST_TYPE_NAVIGATION,
130 gst_handdetect_navigation_interface_init);
131 GST_DEBUG_CATEGORY_INIT (gst_handdetect_debug,
132 "handdetect", 0, "opencv hand gesture detection"));
133 GST_ELEMENT_REGISTER_DEFINE (handdetect, "handdetect", GST_RANK_NONE,
134 GST_TYPE_HANDDETECT);
135
136 static void
gst_handdetect_navigation_interface_init(GstNavigationInterface * iface)137 gst_handdetect_navigation_interface_init (GstNavigationInterface * iface)
138 {
139 iface->send_event = gst_handdetect_navigation_send_event;
140 }
141
142 /* FIXME: this function used to parse the region of interests coordinates
143 * sending from applications when the hand gestures reach the defined regions of interests,
144 * at this moment this function is not doing anything significantly
145 * but will be CHANGED when the gstreamer is patched with new hand gesture events
146 */
147 static void
gst_handdetect_navigation_send_event(GstNavigation * navigation,GstStructure * structure)148 gst_handdetect_navigation_send_event (GstNavigation * navigation,
149 GstStructure * structure)
150 {
151 GstHanddetect *filter = GST_HANDDETECT (navigation);
152 GstPad *peer;
153
154 if ((peer = gst_pad_get_peer (GST_BASE_TRANSFORM_CAST (filter)->sinkpad))) {
155 GstEvent *event;
156 event = gst_event_new_navigation (structure);
157 gst_pad_send_event (peer, event);
158 gst_object_unref (peer);
159 }
160 }
161
162 /* clean opencv images and parameters */
163 static void
gst_handdetect_finalize(GObject * obj)164 gst_handdetect_finalize (GObject * obj)
165 {
166 GstHanddetect *filter = GST_HANDDETECT (obj);
167
168 filter->cvGray.release ();
169 g_free (filter->profile_fist);
170 g_free (filter->profile_palm);
171 delete (filter->best_r);
172 if (filter->cvCascade_fist)
173 delete filter->cvCascade_fist;
174 if (filter->cvCascade_palm)
175 delete filter->cvCascade_palm;
176
177 G_OBJECT_CLASS (gst_handdetect_parent_class)->finalize (obj);
178 }
179
180 /* initialise the HANDDETECT class */
181 static void
gst_handdetect_class_init(GstHanddetectClass * klass)182 gst_handdetect_class_init (GstHanddetectClass * klass)
183 {
184 GObjectClass *gobject_class;
185 GstOpencvVideoFilterClass *gstopencvbasefilter_class;
186
187 GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
188 gobject_class = (GObjectClass *) klass;
189 gstopencvbasefilter_class = (GstOpencvVideoFilterClass *) klass;
190
191 gstopencvbasefilter_class->cv_trans_ip_func = gst_handdetect_transform_ip;
192 gstopencvbasefilter_class->cv_set_caps = gst_handdetect_set_caps;
193
194 gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_handdetect_finalize);
195 gobject_class->set_property = gst_handdetect_set_property;
196 gobject_class->get_property = gst_handdetect_get_property;
197
198 g_object_class_install_property (gobject_class,
199 PROP_DISPLAY,
200 g_param_spec_boolean ("display",
201 "Display",
202 "Whether the detected hands are highlighted in output frame",
203 TRUE, (GParamFlags) G_PARAM_READWRITE)
204 );
205 g_object_class_install_property (gobject_class,
206 PROP_PROFILE_FIST,
207 g_param_spec_string ("profile_fist",
208 "Profile_fist",
209 "Location of HAAR cascade file (fist gesture)",
210 HAAR_FILE_FIST, (GParamFlags) G_PARAM_READWRITE)
211 );
212 g_object_class_install_property (gobject_class,
213 PROP_PROFILE_PALM,
214 g_param_spec_string ("profile_palm",
215 "Profile_palm",
216 "Location of HAAR cascade file (palm gesture)",
217 HAAR_FILE_PALM, (GParamFlags) G_PARAM_READWRITE)
218 );
219 /* FIXME: property name needs fixing */
220 g_object_class_install_property (gobject_class,
221 PROP_ROI_X,
222 g_param_spec_int ("ROI_X",
223 "ROI_X",
224 "X of left-top pointer in region of interest \nGestures in the defined region of interest will emit messages",
225 0, INT_MAX, 0, (GParamFlags) G_PARAM_READWRITE)
226 );
227 /* FIXME: property name needs fixing */
228 g_object_class_install_property (gobject_class,
229 PROP_ROI_Y,
230 g_param_spec_int ("ROI_Y",
231 "ROI_Y",
232 "Y of left-top pointer in region of interest \nGestures in the defined region of interest will emit messages",
233 0, INT_MAX, 0, (GParamFlags) G_PARAM_READWRITE)
234 );
235 /* FIXME: property name needs fixing */
236 g_object_class_install_property (gobject_class,
237 PROP_ROI_WIDTH,
238 g_param_spec_int ("ROI_WIDTH",
239 "ROI_WIDTH",
240 "WIDTH of left-top pointer in region of interest \nGestures in the defined region of interest will emit messages",
241 0, INT_MAX, 0, (GParamFlags) G_PARAM_READWRITE)
242 );
243 /* FIXME: property name needs fixing */
244 g_object_class_install_property (gobject_class,
245 PROP_ROI_HEIGHT,
246 g_param_spec_int ("ROI_HEIGHT",
247 "ROI_HEIGHT",
248 "HEIGHT of left-top pointer in region of interest \nGestures in the defined region of interest will emit messages",
249 0, INT_MAX, 0, (GParamFlags) G_PARAM_READWRITE)
250 );
251
252 gst_element_class_set_static_metadata (element_class,
253 "handdetect",
254 "Filter/Effect/Video",
255 "Performs hand gesture detection on videos, providing detected hand positions via bus message and navigation event, and deals with hand gesture events",
256 "Andol Li <andol@andol.info>");
257
258 gst_element_class_add_static_pad_template (element_class, &src_factory);
259 gst_element_class_add_static_pad_template (element_class, &sink_factory);
260
261 }
262
263 /* initialise the new element
264 * instantiate pads and add them to element
265 * set pad call-back functions
266 * initialise instance structure
267 */
268 static void
gst_handdetect_init(GstHanddetect * filter)269 gst_handdetect_init (GstHanddetect * filter)
270 {
271 const gchar *haar_path;
272
273 haar_path = g_getenv ("GST_HAAR_CASCADES_PATH");
274 if (haar_path) {
275 filter->profile_fist = g_build_filename (haar_path, "fist.xml", NULL);
276 filter->profile_palm = g_build_filename (haar_path, "palm.xml", NULL);
277 } else {
278 filter->profile_fist = g_strdup (HAAR_FILE_FIST);
279 filter->profile_palm = g_strdup (HAAR_FILE_PALM);
280 }
281
282 filter->roi_x = 0;
283 filter->roi_y = 0;
284 filter->roi_width = 0;
285 filter->roi_height = 0;
286 filter->display = TRUE;
287
288 filter->cvCascade_fist =
289 gst_handdetect_load_profile (filter, filter->profile_fist);
290 filter->cvCascade_palm =
291 gst_handdetect_load_profile (filter, filter->profile_palm);
292
293 gst_opencv_video_filter_set_in_place (GST_OPENCV_VIDEO_FILTER_CAST (filter),
294 TRUE);
295 }
296
297 static void
gst_handdetect_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)298 gst_handdetect_set_property (GObject * object, guint prop_id,
299 const GValue * value, GParamSpec * pspec)
300 {
301 GstHanddetect *filter = GST_HANDDETECT (object);
302
303 switch (prop_id) {
304 case PROP_PROFILE_FIST:
305 g_free (filter->profile_fist);
306 if (filter->cvCascade_fist)
307 delete filter->cvCascade_fist;
308 filter->profile_fist = g_value_dup_string (value);
309 filter->cvCascade_fist =
310 gst_handdetect_load_profile (filter, filter->profile_fist);
311 break;
312 case PROP_PROFILE_PALM:
313 g_free (filter->profile_palm);
314 if (filter->cvCascade_palm)
315 delete filter->cvCascade_palm;
316 filter->profile_palm = g_value_dup_string (value);
317 filter->cvCascade_palm =
318 gst_handdetect_load_profile (filter, filter->profile_palm);
319 break;
320 case PROP_DISPLAY:
321 filter->display = g_value_get_boolean (value);
322 break;
323 case PROP_ROI_X:
324 filter->roi_x = g_value_get_int (value);
325 break;
326 case PROP_ROI_Y:
327 filter->roi_y = g_value_get_int (value);
328 break;
329 case PROP_ROI_WIDTH:
330 filter->roi_width = g_value_get_int (value);
331 break;
332 case PROP_ROI_HEIGHT:
333 filter->roi_height = g_value_get_int (value);
334 break;
335 default:
336 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
337 break;
338 }
339 }
340
341 static void
gst_handdetect_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)342 gst_handdetect_get_property (GObject * object, guint prop_id, GValue * value,
343 GParamSpec * pspec)
344 {
345 GstHanddetect *filter = GST_HANDDETECT (object);
346
347 switch (prop_id) {
348 case PROP_DISPLAY:
349 g_value_set_boolean (value, filter->display);
350 break;
351 case PROP_PROFILE_FIST:
352 g_value_set_string (value, filter->profile_fist);
353 break;
354 case PROP_PROFILE_PALM:
355 g_value_set_string (value, filter->profile_palm);
356 break;
357 case PROP_ROI_X:
358 g_value_set_int (value, filter->roi_x);
359 break;
360 case PROP_ROI_Y:
361 g_value_set_int (value, filter->roi_y);
362 break;
363 case PROP_ROI_WIDTH:
364 g_value_set_int (value, filter->roi_width);
365 break;
366 case PROP_ROI_HEIGHT:
367 g_value_set_int (value, filter->roi_height);
368 break;
369 default:
370 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
371 break;
372 }
373 }
374
375 /* GstElement vmethod implementations */
376 /* this function handles the link with other elements */
377 static gboolean
gst_handdetect_set_caps(GstOpencvVideoFilter * transform,gint in_width,gint in_height,int in_cv_type,gint out_width,gint out_height,int out_cv_type)378 gst_handdetect_set_caps (GstOpencvVideoFilter * transform,
379 gint in_width, gint in_height, int in_cv_type,
380 gint out_width, gint out_height, int out_cv_type)
381 {
382 GstHanddetect *filter;
383 filter = GST_HANDDETECT (transform);
384
385 /* 320 x 240 is with the best detect accuracy, if not, give info */
386 if (in_width != 320 || in_height != 240)
387 GST_WARNING_OBJECT (filter,
388 "resize to 320 x 240 to have best detect accuracy.\n");
389
390 filter->cvGray.create (Size (in_width, in_height), CV_8UC1);
391
392 return TRUE;
393 }
394
395 /* Hand detection function
396 * This function does the actual processing 'of hand detect and display'
397 */
398 static GstFlowReturn
gst_handdetect_transform_ip(GstOpencvVideoFilter * transform,GstBuffer * buffer,Mat img)399 gst_handdetect_transform_ip (GstOpencvVideoFilter * transform,
400 GstBuffer * buffer, Mat img)
401 {
402 GstHanddetect *filter = GST_HANDDETECT (transform);
403 Rect *r;
404 GstStructure *s;
405 GstMessage *m;
406 unsigned int i;
407 vector < Rect > hands;
408
409 /* check detection cascades */
410 if (filter->cvCascade_fist && filter->cvCascade_palm) {
411 /* cvt to gray colour space for hand detect */
412 cvtColor (img, filter->cvGray, COLOR_RGB2GRAY);
413
414 /* detect FIST gesture fist */
415 Mat roi (filter->cvGray, Rect (0,
416 0, filter->cvGray.size ().width, filter->cvGray.size ().height));
417 filter->cvCascade_fist->detectMultiScale (roi, hands, 1.1, 2,
418 CASCADE_DO_CANNY_PRUNING, Size (24, 24), Size (0, 0));
419
420 /* if FIST gesture detected */
421 if (!hands.empty ()) {
422
423 int min_distance, distance;
424 Rect temp_r;
425 Point c;
426
427 /* Go through all detected FIST gestures to get the best one
428 * prev_r => previous hand
429 * best_r => best hand in this frame
430 */
431 /* set min_distance for init comparison */
432 min_distance = img.size ().width + img.size ().height;
433 /* Init filter->prev_r */
434 temp_r = Rect (0, 0, 0, 0);
435 if (filter->prev_r == NULL)
436 filter->prev_r = &temp_r;
437 /* Get the best FIST gesture */
438 for (i = 0; i < hands.size (); i++) {
439 r = &hands[i];
440 distance = (int) sqrt (pow ((r->x - filter->prev_r->x),
441 2) + pow ((r->y - filter->prev_r->y), 2));
442 if (distance <= min_distance) {
443 min_distance = distance;
444 delete (filter->best_r);
445 filter->best_r = new Rect (*r);
446 }
447 }
448 /* Save best_r as prev_r for next frame comparison */
449 filter->prev_r = filter->best_r;
450
451 /* send msg to app/bus if the detected gesture falls in the region of interest */
452 /* get center point of gesture */
453 c = Point (filter->best_r->x + filter->best_r->width / 2,
454 filter->best_r->y + filter->best_r->height / 2);
455 /* send message:
456 * if the center point is in the region of interest, OR,
457 * if the region of interest remains default as (0,0,0,0)*/
458 if ((c.x >= filter->roi_x && c.x <= (filter->roi_x + filter->roi_width)
459 && c.y >= filter->roi_y
460 && c.y <= (filter->roi_y + filter->roi_height))
461 || (filter->roi_x == 0
462 && filter->roi_y == 0
463 && filter->roi_width == 0 && filter->roi_height == 0)) {
464 /* Define structure for message post */
465 s = gst_structure_new ("hand-gesture",
466 "gesture", G_TYPE_STRING, "fist",
467 "x", G_TYPE_INT,
468 (gint) (filter->best_r->x + filter->best_r->width * 0.5), "y",
469 G_TYPE_INT,
470 (gint) (filter->best_r->y + filter->best_r->height * 0.5), "width",
471 G_TYPE_INT, (gint) filter->best_r->width, "height", G_TYPE_INT,
472 (gint) filter->best_r->height, NULL);
473 /* Init message element */
474 m = gst_message_new_element (GST_OBJECT (filter), s);
475 /* Send message */
476 gst_element_post_message (GST_ELEMENT (filter), m);
477
478 #if 0
479 /* send event
480 * here we use mouse-move event instead of fist-move or palm-move event
481 * !!! this will CHANGE in the future !!!
482 * !!! by adding gst_navigation_send_hand_detect_event() in navigation.c !!!
483 */
484 gst_navigation_send_mouse_event (GST_NAVIGATION (filter),
485 "mouse-move",
486 0,
487 (double) (filter->best_r->x + filter->best_r->width * 0.5),
488 (double) (filter->best_r->y + filter->best_r->height * 0.5));
489
490 #endif
491 }
492 /* Check filter->display,
493 * If TRUE, displaying red circle marker in the out frame */
494 if (filter->display) {
495 Point center;
496 int radius;
497 center.x = cvRound ((filter->best_r->x + filter->best_r->width * 0.5));
498 center.y = cvRound ((filter->best_r->y + filter->best_r->height * 0.5));
499 radius =
500 cvRound ((filter->best_r->width + filter->best_r->height) * 0.25);
501 circle (img, center, radius, CV_RGB (0, 0, 200), 1, 8, 0);
502 }
503 } else {
504 /* if NO FIST gesture, detecting PALM gesture */
505 filter->cvCascade_palm->detectMultiScale (roi, hands, 1.1, 2,
506 CASCADE_DO_CANNY_PRUNING, Size (24, 24), Size (0, 0));
507 /* if PALM detected */
508 if (!hands.empty ()) {
509 int min_distance, distance;
510 Rect temp_r;
511 Point c;
512
513 if (filter->display) {
514 GST_DEBUG_OBJECT (filter, "%d PALM gestures detected",
515 (int) hands.size ());
516 }
517 /* Go through all detected PALM gestures to get the best one
518 * prev_r => previous hand
519 * best_r => best hand in this frame
520 */
521 /* suppose a min_distance for init comparison */
522 min_distance = img.size ().width + img.size ().height;
523 /* Init filter->prev_r */
524 temp_r = Rect (0, 0, 0, 0);
525 if (filter->prev_r == NULL)
526 filter->prev_r = &temp_r;
527 /* Get the best PALM gesture */
528 for (i = 0; i < hands.size (); ++i) {
529 r = &hands[i];
530 distance = (int) sqrt (pow ((r->x - filter->prev_r->x),
531 2) + pow ((r->y - filter->prev_r->y), 2));
532 if (distance <= min_distance) {
533 min_distance = distance;
534 delete (filter->best_r);
535 filter->best_r = new Rect (*r);
536 }
537 }
538 /* Save best_r as prev_r for next frame comparison */
539 filter->prev_r = filter->best_r;
540
541 /* send msg to app/bus if the detected gesture falls in the region of interest */
542 /* get center point of gesture */
543 c = Point (filter->best_r->x + filter->best_r->width / 2,
544 filter->best_r->y + filter->best_r->height / 2);
545 /* send message:
546 * if the center point is in the region of interest, OR,
547 * if the region of interest remains default as (0,0,0,0)*/
548 if (((gint) c.x >= filter->roi_x
549 && (gint) c.x <= (filter->roi_x + filter->roi_width)
550 && (gint) c.y >= filter->roi_y
551 && (gint) c.y <= (filter->roi_y + filter->roi_height))
552 || (filter->roi_x == 0 && filter->roi_y == 0
553 && filter->roi_width == 0 && filter->roi_height == 0)) {
554 /* Define structure for message post */
555 s = gst_structure_new ("hand-gesture",
556 "gesture", G_TYPE_STRING, "palm",
557 "x", G_TYPE_INT,
558 (gint) (filter->best_r->x + filter->best_r->width * 0.5), "y",
559 G_TYPE_INT,
560 (gint) (filter->best_r->y + filter->best_r->height * 0.5),
561 "width", G_TYPE_INT, (gint) filter->best_r->width, "height",
562 G_TYPE_INT, (gint) filter->best_r->height, NULL);
563 /* Init message element */
564 m = gst_message_new_element (GST_OBJECT (filter), s);
565 /* Send message */
566 gst_element_post_message (GST_ELEMENT (filter), m);
567
568 #if 0
569 /* send event
570 * here we use mouse-move event instead of fist-move or palm-move event
571 * !!! this will CHANGE in the future !!!
572 * !!! by adding gst_navigation_send_hand_detect_event() in navigation.c !!!
573 */
574 gst_navigation_send_mouse_event (GST_NAVIGATION (filter),
575 "mouse-move",
576 0,
577 (double) (filter->best_r->x + filter->best_r->width * 0.5),
578 (double) (filter->best_r->y + filter->best_r->height * 0.5));
579
580 /* or use another way to send upstream navigation event for debug
581 *
582 * GstEvent *event =
583 * gst_event_new_navigation (gst_structure_new
584 * ("application/x-gst-navigation", "event", G_TYPE_STRING,
585 * "mouse-move",
586 * "button", G_TYPE_INT, 0,
587 * "pointer_x", G_TYPE_DOUBLE,
588 * (double) (filter->best_r->x + filter->best_r->width * 0.5),
589 * "pointer_y", G_TYPE_DOUBLE,
590 * (double) (filter->best_r->y + filter->best_r->height * 0.5),
591 * NULL));
592 * gst_pad_send_event (GST_BASE_TRANSFORM_CAST (filter)->srcpad, event);
593 */
594 #endif
595 }
596 /* Check filter->display,
597 * If TRUE, displaying red circle marker in the out frame */
598 if (filter->display) {
599 Point center;
600 int radius;
601 center.x =
602 cvRound ((filter->best_r->x + filter->best_r->width * 0.5));
603 center.y =
604 cvRound ((filter->best_r->y + filter->best_r->height * 0.5));
605 radius =
606 cvRound ((filter->best_r->width + filter->best_r->height) * 0.25);
607 circle (img, center, radius, CV_RGB (0, 0, 200), 1, 8, 0);
608 }
609 }
610 }
611 }
612
613 /* Push out the incoming buffer */
614 return GST_FLOW_OK;
615 }
616
617 static CascadeClassifier *
gst_handdetect_load_profile(GstHanddetect * filter,gchar * profile)618 gst_handdetect_load_profile (GstHanddetect * filter, gchar * profile)
619 {
620 CascadeClassifier *cascade;
621
622 cascade = new CascadeClassifier (profile);
623 if (cascade->empty ()) {
624 GST_ERROR_OBJECT (filter, "Invalid profile file: %s", profile);
625 delete cascade;
626 return NULL;
627 }
628
629 return cascade;
630 }
631