| /* |
| * GStreamer hand gesture detection plugins |
| * Copyright (C) 2012 Andol Li <<andol@andol.info>> |
| * Copyright (C) 2013 Sreerenj Balachandran <sreerenj.balachandran@intel.com> |
| * |
| * Permission is hereby granted, free of charge, to any person obtaining a |
| * copy of this software and associated documentation files (the "Software"), |
| * to deal in the Software without restriction, including without limitation |
| * the rights to use, copy, modify, merge, publish, distribute, sublicense, |
| * and/or sell copies of the Software, and to permit persons to whom the |
| * Software is furnished to do so, subject to the following conditions: |
| * |
| * The above copyright notice and this permission notice shall be included in |
| * all copies or substantial portions of the Software. |
| * |
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
| * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
| * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
| * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
| * DEALINGS IN THE SOFTWARE. |
| * |
| * Alternatively, the contents of this file may be used under the |
| * GNU Lesser General Public License Version 2.1 (the "LGPL"), in |
| * which case the following provisions apply instead of the ones |
| * mentioned above: |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Library General Public |
| * License as published by the Free Software Foundation; either |
| * version 2 of the License, or (at your option) any later version. |
| * |
| * This library is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * Library General Public License for more details. |
| * |
| * You should have received a copy of the GNU Library General Public |
| * License along with this library; if not, write to the |
| * Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
| * Boston, MA 02111-1307, USA. |
| */ |
| /** |
| * SECTION:video-filter-handdetect |
| * |
| * FIXME:operates hand gesture detection in video streams and images, |
| * and enable media operation e.g. play/stop/fast forward/back rewind. |
| * |
| * <refsect2> |
| * <title>Example launch line</title> |
| * |[ |
| * gst-launch-1.0 autovideosrc ! videoconvert ! "video/x-raw, formt=RGB, width=320, height=240" ! \ |
| * videoscale ! handdetect ! videoconvert ! xvimagesink |
| * ]| |
| * </refsect2> |
| */ |
| |
| #ifdef HAVE_CONFIG_H |
| #include <config.h> |
| #endif |
| |
| /* element header */ |
| #include "gsthanddetect.h" |
| #include "gstopencvutils.h" |
| #include <opencv2/imgproc/imgproc_c.h> |
| |
| GST_DEBUG_CATEGORY_STATIC (gst_handdetect_debug); |
| #define GST_CAT_DEFAULT gst_handdetect_debug |
| |
| /* define HAAR files */ |
| #define HAAR_FILE_FIST GST_HAAR_CASCADES_DIR G_DIR_SEPARATOR_S "fist.xml" |
| #define HAAR_FILE_PALM GST_HAAR_CASCADES_DIR G_DIR_SEPARATOR_S "palm.xml" |
| |
| /* Filter signals and args */ |
| enum |
| { |
| /* FILL ME */ |
| LAST_SIGNAL |
| }; |
| |
| enum |
| { |
| PROP_0, |
| PROP_DISPLAY, |
| PROP_PROFILE_FIST, |
| PROP_PROFILE_PALM, |
| PROP_ROI_X, |
| PROP_ROI_Y, |
| PROP_ROI_WIDTH, |
| PROP_ROI_HEIGHT |
| }; |
| |
| /* the capabilities of the inputs and outputs */ |
| static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink", |
| GST_PAD_SINK, |
| GST_PAD_ALWAYS, |
| GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("RGB")) |
| ); |
| static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src", |
| GST_PAD_SRC, |
| GST_PAD_ALWAYS, |
| GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("RGB")) |
| ); |
| |
| static void gst_handdetect_set_property (GObject * object, guint prop_id, |
| const GValue * value, GParamSpec * pspec); |
| static void gst_handdetect_get_property (GObject * object, guint prop_id, |
| GValue * value, GParamSpec * pspec); |
| static gboolean gst_handdetect_set_caps (GstOpencvVideoFilter * transform, |
| gint in_width, gint in_height, gint in_depth, gint in_channels, |
| gint out_width, gint out_height, gint out_depth, gint out_channels); |
| static GstFlowReturn gst_handdetect_transform_ip (GstOpencvVideoFilter * |
| transform, GstBuffer * buffer, IplImage * img); |
| |
| static void gst_handdetect_load_profile (GstHanddetect * filter); |
| |
| static void gst_handdetect_navigation_interface_init (GstNavigationInterface * |
| iface); |
| static void gst_handdetect_navigation_send_event (GstNavigation * navigation, |
| GstStructure * structure); |
| |
| G_DEFINE_TYPE_WITH_CODE (GstHanddetect, gst_handdetect, |
| GST_TYPE_OPENCV_VIDEO_FILTER, |
| G_IMPLEMENT_INTERFACE (GST_TYPE_NAVIGATION, |
| gst_handdetect_navigation_interface_init);); |
| |
| static void |
| gst_handdetect_navigation_interface_init (GstNavigationInterface * iface) |
| { |
| iface->send_event = gst_handdetect_navigation_send_event; |
| } |
| |
| /* FIXME: this function used to parse the region of interests coordinates |
| * sending from applications when the hand gestures reach the defined regions of interests, |
| * at this moment this function is not doing anything significantly |
| * but will be CHANGED when the gstreamer is patched with new hand gesture events |
| */ |
| static void |
| gst_handdetect_navigation_send_event (GstNavigation * navigation, |
| GstStructure * structure) |
| { |
| GstHanddetect *filter = GST_HANDDETECT (navigation); |
| GstPad *peer; |
| |
| if ((peer = gst_pad_get_peer (GST_BASE_TRANSFORM_CAST (filter)->sinkpad))) { |
| GstEvent *event; |
| event = gst_event_new_navigation (structure); |
| gst_pad_send_event (peer, event); |
| gst_object_unref (peer); |
| } |
| } |
| |
| /* clean opencv images and parameters */ |
| static void |
| gst_handdetect_finalize (GObject * obj) |
| { |
| GstHanddetect *filter = GST_HANDDETECT (obj); |
| |
| if (filter->cvGray) |
| cvReleaseImage (&filter->cvGray); |
| if (filter->cvStorage) |
| cvReleaseMemStorage (&filter->cvStorage); |
| if (filter->cvStorage_palm) |
| cvReleaseMemStorage (&filter->cvStorage_palm); |
| g_free (filter->profile_fist); |
| g_free (filter->profile_palm); |
| |
| G_OBJECT_CLASS (gst_handdetect_parent_class)->finalize (obj); |
| } |
| |
| /* initialise the HANDDETECT class */ |
| static void |
| gst_handdetect_class_init (GstHanddetectClass * klass) |
| { |
| GObjectClass *gobject_class; |
| GstOpencvVideoFilterClass *gstopencvbasefilter_class; |
| |
| GstElementClass *element_class = GST_ELEMENT_CLASS (klass); |
| gobject_class = (GObjectClass *) klass; |
| gstopencvbasefilter_class = (GstOpencvVideoFilterClass *) klass; |
| |
| gstopencvbasefilter_class->cv_trans_ip_func = gst_handdetect_transform_ip; |
| gstopencvbasefilter_class->cv_set_caps = gst_handdetect_set_caps; |
| |
| gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_handdetect_finalize); |
| gobject_class->set_property = gst_handdetect_set_property; |
| gobject_class->get_property = gst_handdetect_get_property; |
| |
| g_object_class_install_property (gobject_class, |
| PROP_DISPLAY, |
| g_param_spec_boolean ("display", |
| "Display", |
| "Whether the detected hands are highlighted in output frame", |
| TRUE, G_PARAM_READWRITE) |
| ); |
| g_object_class_install_property (gobject_class, |
| PROP_PROFILE_FIST, |
| g_param_spec_string ("profile_fist", |
| "Profile_fist", |
| "Location of HAAR cascade file (fist gesture)", |
| HAAR_FILE_FIST, G_PARAM_READWRITE) |
| ); |
| g_object_class_install_property (gobject_class, |
| PROP_PROFILE_PALM, |
| g_param_spec_string ("profile_palm", |
| "Profile_palm", |
| "Location of HAAR cascade file (palm gesture)", |
| HAAR_FILE_PALM, G_PARAM_READWRITE) |
| ); |
| /* FIXME: property name needs fixing */ |
| g_object_class_install_property (gobject_class, |
| PROP_ROI_X, |
| g_param_spec_uint ("ROI_X", |
| "ROI_X", |
| "X of left-top pointer in region of interest \nGestures in the defined region of interest will emit messages", |
| 0, UINT_MAX, 0, G_PARAM_READWRITE) |
| ); |
| /* FIXME: property name needs fixing */ |
| g_object_class_install_property (gobject_class, |
| PROP_ROI_Y, |
| g_param_spec_uint ("ROI_Y", |
| "ROI_Y", |
| "Y of left-top pointer in region of interest \nGestures in the defined region of interest will emit messages", |
| 0, UINT_MAX, 0, G_PARAM_READWRITE) |
| ); |
| /* FIXME: property name needs fixing */ |
| g_object_class_install_property (gobject_class, |
| PROP_ROI_WIDTH, |
| g_param_spec_uint ("ROI_WIDTH", |
| "ROI_WIDTH", |
| "WIDTH of left-top pointer in region of interest \nGestures in the defined region of interest will emit messages", |
| 0, UINT_MAX, 0, G_PARAM_READWRITE) |
| ); |
| /* FIXME: property name needs fixing */ |
| g_object_class_install_property (gobject_class, |
| PROP_ROI_HEIGHT, |
| g_param_spec_uint ("ROI_HEIGHT", |
| "ROI_HEIGHT", |
| "HEIGHT of left-top pointer in region of interest \nGestures in the defined region of interest will emit messages", |
| 0, UINT_MAX, 0, G_PARAM_READWRITE) |
| ); |
| |
| gst_element_class_set_static_metadata (element_class, |
| "handdetect", |
| "Filter/Effect/Video", |
| "Performs hand gesture detection on videos, providing detected hand positions via bus message and navigation event, and deals with hand gesture events", |
| "Andol Li <andol@andol.info>"); |
| |
| gst_element_class_add_pad_template (element_class, |
| gst_static_pad_template_get (&src_factory)); |
| gst_element_class_add_pad_template (element_class, |
| gst_static_pad_template_get (&sink_factory)); |
| |
| } |
| |
| /* initialise the new element |
| * instantiate pads and add them to element |
| * set pad call-back functions |
| * initialise instance structure |
| */ |
| static void |
| gst_handdetect_init (GstHanddetect * filter) |
| { |
| filter->profile_fist = g_strdup (HAAR_FILE_FIST); |
| filter->profile_palm = g_strdup (HAAR_FILE_PALM); |
| filter->roi_x = 0; |
| filter->roi_y = 0; |
| filter->roi_width = 0; |
| filter->roi_height = 0; |
| filter->display = TRUE; |
| |
| gst_handdetect_load_profile (filter); |
| |
| gst_opencv_video_filter_set_in_place (GST_OPENCV_VIDEO_FILTER_CAST (filter), |
| TRUE); |
| } |
| |
| static void |
| gst_handdetect_set_property (GObject * object, guint prop_id, |
| const GValue * value, GParamSpec * pspec) |
| { |
| GstHanddetect *filter = GST_HANDDETECT (object); |
| |
| switch (prop_id) { |
| case PROP_PROFILE_FIST: |
| g_free (filter->profile_fist); |
| filter->profile_fist = g_value_dup_string (value); |
| gst_handdetect_load_profile (filter); |
| break; |
| case PROP_PROFILE_PALM: |
| g_free (filter->profile_palm); |
| filter->profile_palm = g_value_dup_string (value); |
| gst_handdetect_load_profile (filter); |
| break; |
| case PROP_DISPLAY: |
| filter->display = g_value_get_boolean (value); |
| break; |
| case PROP_ROI_X: |
| filter->roi_x = g_value_get_uint (value); |
| break; |
| case PROP_ROI_Y: |
| filter->roi_y = g_value_get_uint (value); |
| break; |
| case PROP_ROI_WIDTH: |
| filter->roi_width = g_value_get_uint (value); |
| break; |
| case PROP_ROI_HEIGHT: |
| filter->roi_height = g_value_get_uint (value); |
| break; |
| default: |
| G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); |
| break; |
| } |
| } |
| |
| static void |
| gst_handdetect_get_property (GObject * object, guint prop_id, GValue * value, |
| GParamSpec * pspec) |
| { |
| GstHanddetect *filter = GST_HANDDETECT (object); |
| |
| switch (prop_id) { |
| case PROP_DISPLAY: |
| g_value_set_boolean (value, filter->display); |
| break; |
| case PROP_PROFILE_FIST: |
| g_value_set_string (value, filter->profile_fist); |
| break; |
| case PROP_PROFILE_PALM: |
| g_value_set_string (value, filter->profile_palm); |
| break; |
| case PROP_ROI_X: |
| g_value_set_uint (value, filter->roi_x); |
| break; |
| case PROP_ROI_Y: |
| g_value_set_uint (value, filter->roi_y); |
| break; |
| case PROP_ROI_WIDTH: |
| g_value_set_uint (value, filter->roi_width); |
| break; |
| case PROP_ROI_HEIGHT: |
| g_value_set_uint (value, filter->roi_height); |
| break; |
| default: |
| G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); |
| break; |
| } |
| } |
| |
| /* GstElement vmethod implementations */ |
| /* this function handles the link with other elements */ |
| static gboolean |
| gst_handdetect_set_caps (GstOpencvVideoFilter * transform, |
| gint in_width, gint in_height, gint in_depth, gint in_channels, |
| gint out_width, gint out_height, gint out_depth, gint out_channels) |
| { |
| GstHanddetect *filter; |
| filter = GST_HANDDETECT (transform); |
| |
| /* 320 x 240 is with the best detect accuracy, if not, give info */ |
| if (in_width != 320 || in_height != 240) |
| GST_WARNING_OBJECT (filter, |
| "resize to 320 x 240 to have best detect accuracy.\n"); |
| |
| if (filter->cvGray) |
| cvReleaseImage (&filter->cvGray); |
| filter->cvGray = |
| cvCreateImage (cvSize (in_width, in_height), IPL_DEPTH_8U, 1); |
| |
| if (!filter->cvStorage) |
| filter->cvStorage = cvCreateMemStorage (0); |
| else |
| cvClearMemStorage (filter->cvStorage); |
| if (!filter->cvStorage_palm) |
| filter->cvStorage_palm = cvCreateMemStorage (0); |
| else |
| cvClearMemStorage (filter->cvStorage_palm); |
| return TRUE; |
| } |
| |
| /* Hand detection function |
| * This function does the actual processing 'of hand detect and display' |
| */ |
| static GstFlowReturn |
| gst_handdetect_transform_ip (GstOpencvVideoFilter * transform, |
| GstBuffer * buffer, IplImage * img) |
| { |
| GstHanddetect *filter = GST_HANDDETECT (transform); |
| CvSeq *hands; |
| CvRect *r; |
| GstStructure *s; |
| GstMessage *m; |
| int i; |
| |
| /* check detection cascades */ |
| if (!filter->cvCascade_fist || !filter->cvCascade_palm) |
| return GST_FLOW_OK; |
| |
| /* cvt to gray colour space for hand detect */ |
| cvCvtColor (img, filter->cvGray, CV_RGB2GRAY); |
| cvClearMemStorage (filter->cvStorage); |
| |
| /* detect FIST gesture fist */ |
| hands = |
| cvHaarDetectObjects (filter->cvGray, filter->cvCascade_fist, |
| filter->cvStorage, 1.1, 2, CV_HAAR_DO_CANNY_PRUNING, cvSize (24, 24) |
| #if (CV_MAJOR_VERSION >= 2) && (CV_MINOR_VERSION >= 2) |
| , cvSize (0, 0) |
| #endif |
| ); |
| |
| /* if FIST gesture detected */ |
| if (hands && hands->total > 0) { |
| int min_distance, distance; |
| CvRect temp_r; |
| CvPoint c; |
| |
| GST_DEBUG_OBJECT (filter, "%d FIST gestures detected\n", |
| (int) hands->total); |
| |
| /* Go through all detected FIST gestures to get the best one |
| * prev_r => previous hand |
| * best_r => best hand in this frame |
| */ |
| /* set min_distance for init comparison */ |
| min_distance = img->width + img->height; |
| /* Init filter->prev_r */ |
| temp_r = cvRect (0, 0, 0, 0); |
| if (filter->prev_r == NULL) |
| filter->prev_r = &temp_r; |
| /* Get the best FIST gesture */ |
| for (i = 0; i < hands->total; i++) { |
| r = (CvRect *) cvGetSeqElem (hands, i); |
| distance = (int) sqrt (pow ((r->x - filter->prev_r->x), |
| 2) + pow ((r->y - filter->prev_r->y), 2)); |
| if (distance <= min_distance) { |
| min_distance = distance; |
| filter->best_r = r; |
| } |
| } |
| /* Save best_r as prev_r for next frame comparison */ |
| filter->prev_r = (CvRect *) filter->best_r; |
| /* send msg to app/bus if the detected gesture falls in the region of interest */ |
| /* get center point of gesture */ |
| c = cvPoint (filter->best_r->x + filter->best_r->width / 2, |
| filter->best_r->y + filter->best_r->height / 2); |
| /* send message: |
| * if the center point is in the region of interest, OR, |
| * if the region of interest remains default as (0,0,0,0)*/ |
| if ((c.x >= filter->roi_x && c.x <= (filter->roi_x + filter->roi_width) |
| && c.y >= filter->roi_y |
| && c.y <= (filter->roi_y + filter->roi_height)) |
| || (filter->roi_x == 0 |
| && filter->roi_y == 0 |
| && filter->roi_width == 0 && filter->roi_height == 0)) { |
| /* Define structure for message post */ |
| s = gst_structure_new ("hand-gesture", |
| "gesture", G_TYPE_STRING, "fist", |
| "x", G_TYPE_UINT, |
| (guint) (filter->best_r->x + filter->best_r->width * 0.5), "y", |
| G_TYPE_UINT, |
| (guint) (filter->best_r->y + filter->best_r->height * 0.5), "width", |
| G_TYPE_UINT, (guint) filter->best_r->width, "height", G_TYPE_UINT, |
| (guint) filter->best_r->height, NULL); |
| /* Init message element */ |
| m = gst_message_new_element (GST_OBJECT (filter), s); |
| /* Send message */ |
| gst_element_post_message (GST_ELEMENT (filter), m); |
| |
| #if 0 |
| /* send event |
| * here we use mouse-move event instead of fist-move or palm-move event |
| * !!! this will CHANGE in the future !!! |
| * !!! by adding gst_navigation_send_hand_detect_event() in navigation.c !!! |
| */ |
| gst_navigation_send_mouse_event (GST_NAVIGATION (filter), |
| "mouse-move", |
| 0, |
| (double) (filter->best_r->x + filter->best_r->width * 0.5), |
| (double) (filter->best_r->y + filter->best_r->height * 0.5)); |
| #endif |
| } |
| /* Check filter->display, |
| * If TRUE, displaying red circle marker in the out frame */ |
| if (filter->display) { |
| CvPoint center; |
| int radius; |
| center.x = cvRound ((filter->best_r->x + filter->best_r->width * 0.5)); |
| center.y = cvRound ((filter->best_r->y + filter->best_r->height * 0.5)); |
| radius = |
| cvRound ((filter->best_r->width + filter->best_r->height) * 0.25); |
| cvCircle (img, center, radius, CV_RGB (0, 0, 200), 1, 8, 0); |
| } |
| } else { |
| /* if NO FIST gesture, detecting PALM gesture */ |
| hands = |
| cvHaarDetectObjects (filter->cvGray, filter->cvCascade_palm, |
| filter->cvStorage, 1.1, 3, CV_HAAR_DO_CANNY_PRUNING, cvSize (24, 24) |
| #if (CV_MAJOR_VERSION >= 2) && (CV_MINOR_VERSION >= 2) |
| , cvSize (0, 0) |
| #endif |
| ); |
| /* if PALM detected */ |
| if (hands && hands->total > 0) { |
| int min_distance, distance; |
| CvRect temp_r; |
| CvPoint c; |
| /* set frame buffer writable */ |
| if (filter->display) { |
| buffer = gst_buffer_make_writable (buffer); |
| GST_DEBUG_OBJECT (filter, "%d PALM gestures detected\n", |
| (int) hands->total); |
| } |
| /* Go through all detected PALM gestures to get the best one |
| * prev_r => previous hand |
| * best_r => best hand in this frame |
| */ |
| /* suppose a min_distance for init comparison */ |
| min_distance = img->width + img->height; |
| /* Init filter->prev_r */ |
| temp_r = cvRect (0, 0, 0, 0); |
| if (filter->prev_r == NULL) |
| filter->prev_r = &temp_r; |
| /* Get the best PALM gesture */ |
| for (i = 0; i < hands->total; i++) { |
| r = (CvRect *) cvGetSeqElem (hands, i); |
| distance = (int) sqrt (pow ((r->x - filter->prev_r->x), |
| 2) + pow ((r->y - filter->prev_r->y), 2)); |
| if (distance <= min_distance) { |
| min_distance = distance; |
| filter->best_r = r; |
| } |
| } |
| /* Save best_r as prev_r for next frame comparison */ |
| filter->prev_r = (CvRect *) filter->best_r; |
| |
| /* send msg to app/bus if the detected gesture falls in the region of interest */ |
| /* get center point of gesture */ |
| c = cvPoint (filter->best_r->x + filter->best_r->width / 2, |
| filter->best_r->y + filter->best_r->height / 2); |
| /* send message: |
| * if the center point is in the region of interest, OR, |
| * if the region of interest remains default as (0,0,0,0)*/ |
| if ((c.x >= filter->roi_x && c.x <= (filter->roi_x + filter->roi_width) |
| && c.y >= filter->roi_y |
| && c.y <= (filter->roi_y + filter->roi_height)) |
| || (filter->roi_x == 0 |
| && filter->roi_y == 0 |
| && filter->roi_width == 0 && filter->roi_height == 0)) { |
| /* Define structure for message post */ |
| s = gst_structure_new ("hand-gesture", |
| "gesture", G_TYPE_STRING, "palm", |
| "x", G_TYPE_UINT, |
| (guint) (filter->best_r->x + filter->best_r->width * 0.5), "y", |
| G_TYPE_UINT, |
| (guint) (filter->best_r->y + filter->best_r->height * 0.5), "width", |
| G_TYPE_UINT, (guint) filter->best_r->width, "height", G_TYPE_UINT, |
| (guint) filter->best_r->height, NULL); |
| /* Init message element */ |
| m = gst_message_new_element (GST_OBJECT (filter), s); |
| /* Send message */ |
| gst_element_post_message (GST_ELEMENT (filter), m); |
| |
| #if 0 |
| /* send event |
| * here we use mouse-move event instead of fist-move or palm-move event |
| * !!! this will CHANGE in the future !!! |
| * !!! by adding gst_navigation_send_hand_detect_event() in navigation.c !!! |
| */ |
| gst_navigation_send_mouse_event (GST_NAVIGATION (filter), |
| "mouse-move", |
| 0, |
| (double) (filter->best_r->x + filter->best_r->width * 0.5), |
| (double) (filter->best_r->y + filter->best_r->height * 0.5)); |
| |
| /* or use another way to send upstream navigation event for debug |
| * |
| * GstEvent *event = |
| * gst_event_new_navigation (gst_structure_new |
| * ("application/x-gst-navigation", "event", G_TYPE_STRING, |
| * "mouse-move", |
| * "button", G_TYPE_INT, 0, |
| * "pointer_x", G_TYPE_DOUBLE, |
| * (double) (filter->best_r->x + filter->best_r->width * 0.5), |
| * "pointer_y", G_TYPE_DOUBLE, |
| * (double) (filter->best_r->y + filter->best_r->height * 0.5), |
| * NULL)); |
| * gst_pad_send_event (GST_BASE_TRANSFORM_CAST (filter)->srcpad, event); |
| */ |
| #endif |
| } |
| /* Check filter->display, |
| * If TRUE, displaying red circle marker in the out frame */ |
| if (filter->display) { |
| CvPoint center; |
| int radius; |
| center.x = cvRound ((filter->best_r->x + filter->best_r->width * 0.5)); |
| center.y = cvRound ((filter->best_r->y + filter->best_r->height * 0.5)); |
| radius = |
| cvRound ((filter->best_r->width + filter->best_r->height) * 0.25); |
| cvCircle (img, center, radius, CV_RGB (0, 0, 200), 1, 8, 0); |
| } |
| } |
| } |
| |
| /* Push out the incoming buffer */ |
| return GST_FLOW_OK; |
| } |
| |
| static void |
| gst_handdetect_load_profile (GstHanddetect * filter) |
| { |
| GST_DEBUG_OBJECT (filter, "Loading profiles...\n"); |
| filter->cvCascade_fist = |
| (CvHaarClassifierCascade *) cvLoad (filter->profile_fist, 0, 0, 0); |
| filter->cvCascade_palm = |
| (CvHaarClassifierCascade *) cvLoad (filter->profile_palm, 0, 0, 0); |
| if (!filter->cvCascade_fist || !filter->cvCascade_palm) |
| GST_WARNING_OBJECT (filter, |
| "WARNING: Could not load HAAR classifier cascade: %s.\n", |
| filter->profile_fist); |
| else |
| GST_DEBUG_OBJECT (filter, "Loaded profile %s\n", filter->profile_fist); |
| if (!filter->cvCascade_palm) |
| GST_WARNING_OBJECT (filter, |
| "WARNING: Could not load HAAR classifier cascade: %s.\n", |
| filter->profile_palm); |
| else |
| GST_DEBUG_OBJECT (filter, "Loaded profile %s\n", filter->profile_palm); |
| } |
| |
| /* Entry point to initialize the plug-in |
| * Initialize the plug-in itself |
| * Register the element factories and other features |
| */ |
| gboolean |
| gst_handdetect_plugin_init (GstPlugin * plugin) |
| { |
| GST_DEBUG_CATEGORY_INIT (gst_handdetect_debug, |
| "handdetect", 0, "opencv hand gesture detection"); |
| return gst_element_register (plugin, "handdetect", GST_RANK_NONE, |
| GST_TYPE_HANDDETECT); |
| } |