2013-01-27 17:05:27 +00:00
/*
* GStreamer hand gesture detection plugins
* Copyright ( C ) 2012 Andol Li < < andol @ andol . info > >
2013-01-30 12:37:18 +00:00
* Copyright ( C ) 2013 Sreerenj Balachandran < sreerenj . balachandran @ intel . com >
2013-01-27 17:05:27 +00:00
*
* 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 >
* | [
2013-03-01 00:10:46 +00:00
* gst - launch - 1.0 autovideosrc ! videoconvert ! " video/x-raw, formt=RGB, width=320, height=240 " ! \
* videoscale ! handdetect ! videoconvert ! xvimagesink
2013-01-27 17:05:27 +00:00
* ] |
* < / refsect2 >
*/
# ifdef HAVE_CONFIG_H
# include <config.h>
# endif
2013-01-30 12:37:18 +00:00
2013-01-27 17:05:27 +00:00
/* element header */
# include "gsthanddetect.h"
# include "gstopencvutils.h"
GST_DEBUG_CATEGORY_STATIC ( gst_handdetect_debug ) ;
# define GST_CAT_DEFAULT gst_handdetect_debug
/* define HAAR files */
2013-03-01 00:10:46 +00:00
# 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"
2013-01-27 17:05:27 +00:00
/* 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 ,
2013-01-30 12:37:18 +00:00
GST_STATIC_CAPS ( GST_VIDEO_CAPS_MAKE ( " RGB " ) )
2013-01-27 17:05:27 +00:00
) ;
static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ( " src " ,
GST_PAD_SRC ,
GST_PAD_ALWAYS ,
2013-01-30 12:37:18 +00:00
GST_STATIC_CAPS ( GST_VIDEO_CAPS_MAKE ( " RGB " ) )
2013-01-27 17:05:27 +00:00
) ;
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 ) ;
2013-01-30 12:37:18 +00:00
static void gst_handdetect_navigation_interface_init ( GstNavigationInterface *
iface ) ;
2013-01-27 17:05:27 +00:00
static void gst_handdetect_navigation_send_event ( GstNavigation * navigation ,
GstStructure * structure ) ;
2013-01-30 12:37:18 +00:00
G_DEFINE_TYPE_WITH_CODE ( GstHanddetect , gst_handdetect ,
GST_TYPE_OPENCV_VIDEO_FILTER ,
G_IMPLEMENT_INTERFACE ( GST_TYPE_NAVIGATION ,
gst_handdetect_navigation_interface_init ) ; ) ;
2013-01-27 17:05:27 +00:00
static void
2013-01-30 12:37:18 +00:00
gst_handdetect_navigation_interface_init ( GstNavigationInterface * iface )
2013-01-27 17:05:27 +00:00
{
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
2013-01-30 12:37:18 +00:00
gst_handdetect_finalize ( GObject * obj )
2013-01-27 17:05:27 +00:00
{
GstHanddetect * filter = GST_HANDDETECT ( obj ) ;
if ( filter - > cvImage )
cvReleaseImage ( & filter - > cvImage ) ;
if ( filter - > cvGray )
cvReleaseImage ( & filter - > cvGray ) ;
g_free ( filter - > profile_fist ) ;
g_free ( filter - > profile_palm ) ;
2013-01-30 12:37:18 +00:00
G_OBJECT_CLASS ( gst_handdetect_parent_class ) - > finalize ( obj ) ;
2013-01-27 17:05:27 +00:00
}
/* initialise the HANDDETECT class */
static void
gst_handdetect_class_init ( GstHanddetectClass * klass )
{
GObjectClass * gobject_class ;
GstOpencvVideoFilterClass * gstopencvbasefilter_class ;
2013-01-30 12:37:18 +00:00
GstElementClass * element_class = GST_ELEMENT_CLASS ( klass ) ;
2013-01-27 17:05:27 +00:00
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 ;
2013-01-30 12:37:18 +00:00
gobject_class - > finalize = GST_DEBUG_FUNCPTR ( gst_handdetect_finalize ) ;
2013-01-27 17:05:27 +00:00
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 )
) ;
2013-03-01 00:10:46 +00:00
/* FIXME: property name needs fixing */
2013-01-27 17:05:27 +00:00
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 \n Gestures in the defined region of interest will emit messages " ,
0 , UINT_MAX , 0 , G_PARAM_READWRITE )
) ;
2013-03-01 00:10:46 +00:00
/* FIXME: property name needs fixing */
2013-01-27 17:05:27 +00:00
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 \n Gestures in the defined region of interest will emit messages " ,
0 , UINT_MAX , 0 , G_PARAM_READWRITE )
) ;
2013-03-01 00:10:46 +00:00
/* FIXME: property name needs fixing */
2013-01-27 17:05:27 +00:00
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 \n Gestures in the defined region of interest will emit messages " ,
0 , UINT_MAX , 0 , G_PARAM_READWRITE )
) ;
2013-03-01 00:10:46 +00:00
/* FIXME: property name needs fixing */
2013-01-27 17:05:27 +00:00
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 \n Gestures in the defined region of interest will emit messages " ,
0 , UINT_MAX , 0 , G_PARAM_READWRITE )
) ;
2013-01-30 12:37:18 +00:00
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 ) ) ;
2013-01-27 17:05:27 +00:00
}
/* initialise the new element
* instantiate pads and add them to element
* set pad call - back functions
* initialise instance structure
*/
static void
2013-01-30 12:37:18 +00:00
gst_handdetect_init ( GstHanddetect * filter )
2013-01-27 17:05:27 +00:00
{
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 ) ;
if ( filter - > cvGray )
cvReleaseImage ( & filter - > cvGray ) ;
filter - > cvGray =
cvCreateImage ( cvSize ( in_width , in_height ) , IPL_DEPTH_8U , 1 ) ;
if ( filter - > cvImage )
cvReleaseImage ( & filter - > cvImage ) ;
filter - > cvImage =
cvCreateImage ( cvSize ( in_width , in_height ) , IPL_DEPTH_8U , 3 ) ;
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 ) ;
2013-01-30 12:37:18 +00:00
GstMapInfo info ;
2013-01-27 17:05:27 +00:00
CvSeq * hands ;
CvRect * r ;
GstStructure * s ;
GstMessage * m ;
int i ;
2013-01-30 12:37:18 +00:00
buffer = gst_buffer_make_writable ( buffer ) ;
gst_buffer_map ( buffer , & info , GST_MAP_READWRITE ) ;
filter - > cvImage - > imageData = ( char * ) info . data ;
2013-01-27 17:05:27 +00:00
/* 320 x 240 is with the best detect accuracy, if not, give info */
if ( filter - > cvImage - > width ! = 320 | | filter - > cvImage - > height ! = 240 )
GST_INFO_OBJECT ( filter ,
" WARNING: resize to 320 x 240 to have best detect accuracy. \n " ) ;
/* cvt to gray colour space for hand detect */
cvCvtColor ( filter - > cvImage , filter - > cvGray , CV_RGB2GRAY ) ;
cvClearMemStorage ( filter - > cvStorage ) ;
/* check detection cascades */
if ( ! filter - > cvCascade_fist | | ! filter - > cvCascade_palm )
return GST_FLOW_OK ;
/* 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 ) {
2013-01-30 12:37:18 +00:00
int min_distance , distance ;
CvRect temp_r ;
CvPoint c ;
2013-01-27 17:05:27 +00:00
/* set frame buffer writable */
if ( filter - > display ) {
buffer = gst_buffer_make_writable ( buffer ) ;
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 */
2013-01-30 12:37:18 +00:00
min_distance = filter - > cvImage - > width + filter - > cvImage - > height ;
2013-01-27 17:05:27 +00:00
/* Init filter->prev_r */
2013-01-30 12:37:18 +00:00
temp_r = cvRect ( 0 , 0 , 0 , 0 ) ;
2013-01-27 17:05:27 +00:00
if ( filter - > prev_r = = NULL )
filter - > prev_r = & temp_r ;
/* Get the best FIST gesture */
for ( i = 0 ; i < ( hands ? hands - > total : 0 ) ; i + + ) {
r = ( CvRect * ) cvGetSeqElem ( hands , i ) ;
2013-01-30 12:37:18 +00:00
distance = ( int ) sqrt ( pow ( ( r - > x - filter - > prev_r - > x ) ,
2013-01-27 17:05:27 +00:00
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 */
2013-01-30 12:37:18 +00:00
c = cvPoint ( filter - > best_r - > x + filter - > best_r - > width / 2 ,
2013-01-27 17:05:27 +00:00
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 ,
( uint ) ( filter - > best_r - > x + filter - > best_r - > width * 0.5 ) , " y " ,
G_TYPE_UINT ,
( uint ) ( filter - > best_r - > y + filter - > best_r - > height * 0.5 ) , " width " ,
G_TYPE_UINT , ( uint ) filter - > best_r - > width , " height " , G_TYPE_UINT ,
( uint ) 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 ( filter - > cvImage , 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 ) {
2013-01-30 12:37:18 +00:00
int min_distance , distance ;
CvRect temp_r ;
CvPoint c ;
2013-01-27 17:05:27 +00:00
/* 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 */
2013-01-30 12:37:18 +00:00
min_distance = filter - > cvImage - > width + filter - > cvImage - > height ;
2013-01-27 17:05:27 +00:00
/* Init filter->prev_r */
2013-01-30 12:37:18 +00:00
temp_r = cvRect ( 0 , 0 , 0 , 0 ) ;
2013-01-27 17:05:27 +00:00
if ( filter - > prev_r = = NULL )
filter - > prev_r = & temp_r ;
/* Get the best PALM gesture */
for ( i = 0 ; i < ( hands ? hands - > total : 0 ) ; i + + ) {
r = ( CvRect * ) cvGetSeqElem ( hands , i ) ;
2013-01-30 12:37:18 +00:00
distance = ( int ) sqrt ( pow ( ( r - > x - filter - > prev_r - > x ) ,
2013-01-27 17:05:27 +00:00
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 */
2013-01-30 12:37:18 +00:00
c = cvPoint ( filter - > best_r - > x + filter - > best_r - > width / 2 ,
2013-01-27 17:05:27 +00:00
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 ,
( uint ) ( filter - > best_r - > x + filter - > best_r - > width * 0.5 ) , " y " ,
G_TYPE_UINT ,
( uint ) ( filter - > best_r - > y + filter - > best_r - > height * 0.5 ) , " width " ,
G_TYPE_UINT , ( uint ) filter - > best_r - > width , " height " , G_TYPE_UINT ,
( uint ) 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 ( filter - > cvImage , center , radius , CV_RGB ( 0 , 0 , 200 ) , 1 , 8 , 0 ) ;
}
}
}
2013-01-30 12:37:18 +00:00
gst_buffer_unmap ( buffer , & info ) ;
2013-01-27 17:05:27 +00:00
/* 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
*/
2013-01-30 12:37:18 +00:00
gboolean
2013-01-27 17:05:27 +00:00
gst_handdetect_plugin_init ( GstPlugin * plugin )
{
GST_DEBUG_CATEGORY_INIT ( gst_handdetect_debug ,
2013-03-01 00:10:46 +00:00
" handdetect " , 0 , " opencv hand gesture detection " ) ;
2013-01-27 17:05:27 +00:00
return gst_element_register ( plugin , " handdetect " , GST_RANK_NONE ,
GST_TYPE_HANDDETECT ) ;
}