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 .
*
2019-05-29 20:58:08 +00:00
* # # Example launch line
*
2013-01-27 17:05:27 +00:00
* | [
2017-12-14 21:31:33 +00:00
* gst - launch - 1.0 autovideosrc ! videoconvert ! " video/x-raw, format=RGB, width=320, height=240 " ! \
2013-03-01 00:10:46 +00:00
* videoscale ! handdetect ! videoconvert ! xvimagesink
2013-01-27 17:05:27 +00:00
* ] |
*/
# 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"
2018-07-13 18:42:28 +00:00
# include <opencv2/imgproc.hpp>
2013-01-27 17:05:27 +00:00
GST_DEBUG_CATEGORY_STATIC ( gst_handdetect_debug ) ;
# define GST_CAT_DEFAULT gst_handdetect_debug
2018-11-25 19:27:25 +00:00
# if (CV_MAJOR_VERSION < 4)
# define CASCADE_DO_CANNY_PRUNING CV_HAAR_DO_CANNY_PRUNING
# endif
2013-01-27 17:05:27 +00:00
/* 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
2015-10-02 15:22:36 +00:00
using namespace cv ;
2016-01-27 14:51:37 +00:00
using namespace std ;
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 ,
2018-12-01 21:48:53 +00:00
gint in_width , gint in_height , int in_cv_type ,
gint out_width , gint out_height , int out_cv_type ) ;
2013-01-27 17:05:27 +00:00
static GstFlowReturn gst_handdetect_transform_ip ( GstOpencvVideoFilter *
2018-12-01 21:48:53 +00:00
transform , GstBuffer * buffer , Mat img ) ;
2013-01-27 17:05:27 +00:00
2015-10-02 15:22:36 +00:00
static CascadeClassifier * gst_handdetect_load_profile ( GstHanddetect * filter ,
gchar * profile ) ;
2013-01-27 17:05:27 +00:00
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 ) ;
2018-12-01 21:48:53 +00:00
filter - > cvGray . release ( ) ;
2013-01-27 17:05:27 +00:00
g_free ( filter - > profile_fist ) ;
g_free ( filter - > profile_palm ) ;
2015-10-20 11:24:11 +00:00
delete ( filter - > best_r ) ;
2018-12-01 21:48:53 +00:00
if ( filter - > cvCascade_fist )
delete filter - > cvCascade_fist ;
if ( filter - > cvCascade_palm )
delete filter - > cvCascade_palm ;
2013-01-27 17:05:27 +00:00
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 " ,
2018-11-25 15:12:40 +00:00
TRUE , ( GParamFlags ) G_PARAM_READWRITE )
2013-01-27 17:05:27 +00:00
) ;
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) " ,
2018-11-25 15:12:40 +00:00
HAAR_FILE_FIST , ( GParamFlags ) G_PARAM_READWRITE )
2013-01-27 17:05:27 +00:00
) ;
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) " ,
2018-11-25 15:12:40 +00:00
HAAR_FILE_PALM , ( GParamFlags ) G_PARAM_READWRITE )
2013-01-27 17:05:27 +00:00
) ;
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 ,
2015-10-02 16:02:42 +00:00
g_param_spec_int ( " ROI_X " ,
2013-01-27 17:05:27 +00:00
" ROI_X " ,
" X of left-top pointer in region of interest \n Gestures in the defined region of interest will emit messages " ,
2018-11-25 15:12:40 +00:00
0 , INT_MAX , 0 , ( GParamFlags ) G_PARAM_READWRITE )
2013-01-27 17:05:27 +00:00
) ;
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 ,
2015-10-02 16:02:42 +00:00
g_param_spec_int ( " ROI_Y " ,
2013-01-27 17:05:27 +00:00
" ROI_Y " ,
" Y of left-top pointer in region of interest \n Gestures in the defined region of interest will emit messages " ,
2018-11-25 15:12:40 +00:00
0 , INT_MAX , 0 , ( GParamFlags ) G_PARAM_READWRITE )
2013-01-27 17:05:27 +00:00
) ;
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 ,
2015-10-02 16:02:42 +00:00
g_param_spec_int ( " ROI_WIDTH " ,
2013-01-27 17:05:27 +00:00
" ROI_WIDTH " ,
" WIDTH of left-top pointer in region of interest \n Gestures in the defined region of interest will emit messages " ,
2018-11-25 15:12:40 +00:00
0 , INT_MAX , 0 , ( GParamFlags ) G_PARAM_READWRITE )
2013-01-27 17:05:27 +00:00
) ;
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 ,
2015-10-02 16:02:42 +00:00
g_param_spec_int ( " ROI_HEIGHT " ,
2013-01-27 17:05:27 +00:00
" ROI_HEIGHT " ,
" HEIGHT of left-top pointer in region of interest \n Gestures in the defined region of interest will emit messages " ,
2018-11-25 15:12:40 +00:00
0 , INT_MAX , 0 , ( GParamFlags ) G_PARAM_READWRITE )
2013-01-27 17:05:27 +00:00
) ;
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> " ) ;
2016-03-04 06:50:26 +00:00
gst_element_class_add_static_pad_template ( element_class , & src_factory ) ;
gst_element_class_add_static_pad_template ( element_class , & sink_factory ) ;
2013-01-30 12:37:18 +00:00
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
{
2015-09-29 16:00:22 +00:00
const gchar * haar_path ;
haar_path = g_getenv ( " GST_HAAR_CASCADES_PATH " ) ;
if ( haar_path ) {
filter - > profile_fist = g_build_filename ( haar_path , " fist.xml " , NULL ) ;
filter - > profile_palm = g_build_filename ( haar_path , " palm.xml " , NULL ) ;
} else {
filter - > profile_fist = g_strdup ( HAAR_FILE_FIST ) ;
filter - > profile_palm = g_strdup ( HAAR_FILE_PALM ) ;
}
2013-01-27 17:05:27 +00:00
filter - > roi_x = 0 ;
filter - > roi_y = 0 ;
filter - > roi_width = 0 ;
filter - > roi_height = 0 ;
filter - > display = TRUE ;
2015-08-17 15:47:42 +00:00
filter - > cvCascade_fist =
gst_handdetect_load_profile ( filter , filter - > profile_fist ) ;
filter - > cvCascade_palm =
gst_handdetect_load_profile ( filter , filter - > profile_palm ) ;
2013-01-27 17:05:27 +00:00
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 ) ;
2015-08-17 16:02:28 +00:00
if ( filter - > cvCascade_fist )
2015-10-02 15:22:36 +00:00
delete filter - > cvCascade_fist ;
2013-01-27 17:05:27 +00:00
filter - > profile_fist = g_value_dup_string ( value ) ;
2015-08-17 15:47:42 +00:00
filter - > cvCascade_fist =
gst_handdetect_load_profile ( filter , filter - > profile_fist ) ;
2013-01-27 17:05:27 +00:00
break ;
case PROP_PROFILE_PALM :
g_free ( filter - > profile_palm ) ;
2015-08-17 16:02:28 +00:00
if ( filter - > cvCascade_palm )
2015-10-02 15:22:36 +00:00
delete filter - > cvCascade_palm ;
2013-01-27 17:05:27 +00:00
filter - > profile_palm = g_value_dup_string ( value ) ;
2015-08-17 15:47:42 +00:00
filter - > cvCascade_palm =
gst_handdetect_load_profile ( filter , filter - > profile_palm ) ;
2013-01-27 17:05:27 +00:00
break ;
case PROP_DISPLAY :
filter - > display = g_value_get_boolean ( value ) ;
break ;
case PROP_ROI_X :
2015-10-02 16:02:42 +00:00
filter - > roi_x = g_value_get_int ( value ) ;
2013-01-27 17:05:27 +00:00
break ;
case PROP_ROI_Y :
2015-10-02 16:02:42 +00:00
filter - > roi_y = g_value_get_int ( value ) ;
2013-01-27 17:05:27 +00:00
break ;
case PROP_ROI_WIDTH :
2015-10-02 16:02:42 +00:00
filter - > roi_width = g_value_get_int ( value ) ;
2013-01-27 17:05:27 +00:00
break ;
case PROP_ROI_HEIGHT :
2015-10-02 16:02:42 +00:00
filter - > roi_height = g_value_get_int ( value ) ;
2013-01-27 17:05:27 +00:00
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 :
2015-10-02 16:02:42 +00:00
g_value_set_int ( value , filter - > roi_x ) ;
2013-01-27 17:05:27 +00:00
break ;
case PROP_ROI_Y :
2015-10-02 16:02:42 +00:00
g_value_set_int ( value , filter - > roi_y ) ;
2013-01-27 17:05:27 +00:00
break ;
case PROP_ROI_WIDTH :
2015-10-02 16:02:42 +00:00
g_value_set_int ( value , filter - > roi_width ) ;
2013-01-27 17:05:27 +00:00
break ;
case PROP_ROI_HEIGHT :
2015-10-02 16:02:42 +00:00
g_value_set_int ( value , filter - > roi_height ) ;
2013-01-27 17:05:27 +00:00
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 ,
2018-12-01 21:48:53 +00:00
gint in_width , gint in_height , int in_cv_type ,
gint out_width , gint out_height , int out_cv_type )
2013-01-27 17:05:27 +00:00
{
GstHanddetect * filter ;
filter = GST_HANDDETECT ( transform ) ;
2014-07-05 00:39:49 +00:00
/* 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 " ) ;
2018-12-01 21:48:53 +00:00
filter - > cvGray . create ( Size ( in_width , in_height ) , CV_8UC1 ) ;
2013-01-27 17:05:27 +00:00
return TRUE ;
}
/* Hand detection function
* This function does the actual processing ' of hand detect and display '
*/
static GstFlowReturn
gst_handdetect_transform_ip ( GstOpencvVideoFilter * transform ,
2018-12-01 21:48:53 +00:00
GstBuffer * buffer , Mat img )
2013-01-27 17:05:27 +00:00
{
GstHanddetect * filter = GST_HANDDETECT ( transform ) ;
2015-10-02 15:22:36 +00:00
Rect * r ;
2013-01-27 17:05:27 +00:00
GstStructure * s ;
GstMessage * m ;
2015-10-02 15:22:36 +00:00
unsigned int i ;
vector < Rect > hands ;
2013-01-27 17:05:27 +00:00
/* check detection cascades */
2015-10-02 15:22:36 +00:00
if ( filter - > cvCascade_fist & & filter - > cvCascade_palm ) {
2018-11-25 15:12:40 +00:00
/* cvt to gray colour space for hand detect */
2018-12-01 21:48:53 +00:00
cvtColor ( img , filter - > cvGray , COLOR_RGB2GRAY ) ;
2015-10-02 15:22:36 +00:00
/* detect FIST gesture fist */
2018-12-01 21:48:53 +00:00
Mat roi ( filter - > cvGray , Rect ( 0 ,
0 , filter - > cvGray . size ( ) . width , filter - > cvGray . size ( ) . height ) ) ;
2018-11-25 15:13:28 +00:00
filter - > cvCascade_fist - > detectMultiScale ( roi , hands , 1.1 , 2 ,
2018-12-01 21:48:53 +00:00
CASCADE_DO_CANNY_PRUNING , Size ( 24 , 24 ) , Size ( 0 , 0 ) ) ;
2015-10-02 15:22:36 +00:00
/* if FIST gesture detected */
if ( ! hands . empty ( ) ) {
2013-01-27 17:05:27 +00:00
2013-01-30 12:37:18 +00:00
int min_distance , distance ;
2015-10-02 15:22:36 +00:00
Rect temp_r ;
2018-12-01 21:48:53 +00:00
Point c ;
2015-10-02 15:22:36 +00:00
/* Go through all detected FIST gestures to get the best one
2013-01-27 17:05:27 +00:00
* prev_r = > previous hand
* best_r = > best hand in this frame
*/
2015-10-02 15:22:36 +00:00
/* set min_distance for init comparison */
2018-12-01 21:48:53 +00:00
min_distance = img . size ( ) . width + img . size ( ) . height ;
2013-01-27 17:05:27 +00:00
/* Init filter->prev_r */
2015-10-02 15:22:36 +00:00
temp_r = Rect ( 0 , 0 , 0 , 0 ) ;
2013-01-27 17:05:27 +00:00
if ( filter - > prev_r = = NULL )
filter - > prev_r = & temp_r ;
2015-10-02 15:22:36 +00:00
/* Get the best FIST gesture */
2018-11-25 15:12:40 +00:00
for ( i = 0 ; i < hands . size ( ) ; i + + ) {
2015-10-02 15:22:36 +00:00
r = & 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 ;
2015-10-20 11:24:11 +00:00
delete ( filter - > best_r ) ;
2015-10-02 15:22:36 +00:00
filter - > best_r = new Rect ( * r ) ;
2013-01-27 17:05:27 +00:00
}
}
/* Save best_r as prev_r for next frame comparison */
2015-10-02 15:22:36 +00:00
filter - > prev_r = filter - > best_r ;
2013-01-27 17:05:27 +00:00
/* send msg to app/bus if the detected gesture falls in the region of interest */
/* get center point of gesture */
2018-12-01 21:48:53 +00:00
c = Point ( 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 " ,
2015-10-02 15:22:36 +00:00
" gesture " , G_TYPE_STRING , " fist " ,
2015-10-02 16:02:42 +00:00
" x " , G_TYPE_INT ,
( gint ) ( filter - > best_r - > x + filter - > best_r - > width * 0.5 ) , " y " ,
G_TYPE_INT ,
( gint ) ( filter - > best_r - > y + filter - > best_r - > height * 0.5 ) , " width " ,
G_TYPE_INT , ( gint ) filter - > best_r - > width , " height " , G_TYPE_INT ,
( gint ) filter - > best_r - > height , NULL ) ;
2013-01-27 17:05:27 +00:00
/* 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 ) {
2018-12-01 21:48:53 +00:00
Point center ;
2013-01-27 17:05:27 +00:00
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 ) ;
2018-12-01 21:48:53 +00:00
circle ( img , center , radius , CV_RGB ( 0 , 0 , 200 ) , 1 , 8 , 0 ) ;
2013-01-27 17:05:27 +00:00
}
2015-10-02 15:22:36 +00:00
} else {
2018-11-25 15:12:40 +00:00
/* if NO FIST gesture, detecting PALM gesture */
2015-10-02 15:22:36 +00:00
filter - > cvCascade_palm - > detectMultiScale ( roi , hands , 1.1 , 2 ,
2018-12-01 21:48:53 +00:00
CASCADE_DO_CANNY_PRUNING , Size ( 24 , 24 ) , Size ( 0 , 0 ) ) ;
2015-10-02 15:22:36 +00:00
/* if PALM detected */
if ( ! hands . empty ( ) ) {
int min_distance , distance ;
Rect temp_r ;
2018-12-01 21:48:53 +00:00
Point c ;
2015-10-21 15:51:10 +00:00
2015-10-02 15:22:36 +00:00
if ( filter - > display ) {
GST_DEBUG_OBJECT ( filter , " %d PALM gestures detected \n " ,
( int ) hands . size ( ) ) ;
}
/* 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 */
2018-12-01 21:48:53 +00:00
min_distance = img . size ( ) . width + img . size ( ) . height ;
2015-10-02 15:22:36 +00:00
/* Init filter->prev_r */
temp_r = Rect ( 0 , 0 , 0 , 0 ) ;
2018-11-25 15:12:40 +00:00
if ( filter - > prev_r = = NULL )
2015-10-02 15:22:36 +00:00
filter - > prev_r = & temp_r ;
/* Get the best PALM gesture */
for ( i = 0 ; i < hands . size ( ) ; + + i ) {
r = & 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 ;
2015-10-20 11:24:11 +00:00
delete ( filter - > best_r ) ;
2015-10-02 15:22:36 +00:00
filter - > best_r = new Rect ( * r ) ;
}
}
/* Save best_r as prev_r for next frame comparison */
filter - > prev_r = filter - > best_r ;
/* send msg to app/bus if the detected gesture falls in the region of interest */
/* get center point of gesture */
2018-12-01 21:48:53 +00:00
c = Point ( filter - > best_r - > x + filter - > best_r - > width / 2 ,
2015-10-02 15:22:36 +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 ) */
2015-10-02 16:02:42 +00:00
if ( ( ( gint ) c . x > = filter - > roi_x
& & ( gint ) c . x < = ( filter - > roi_x + filter - > roi_width )
& & ( gint ) c . y > = filter - > roi_y
& & ( gint ) c . y < = ( filter - > roi_y + filter - > roi_height ) )
2015-10-02 15:22:36 +00:00
| | ( 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 " ,
2015-10-02 16:02:42 +00:00
" x " , G_TYPE_INT ,
( gint ) ( filter - > best_r - > x + filter - > best_r - > width * 0.5 ) , " y " ,
G_TYPE_INT ,
( gint ) ( filter - > best_r - > y + filter - > best_r - > height * 0.5 ) ,
" width " , G_TYPE_INT , ( gint ) filter - > best_r - > width , " height " ,
G_TYPE_INT , ( gint ) filter - > best_r - > height , NULL ) ;
2015-10-02 15:22:36 +00:00
/* 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 ) {
2018-12-01 21:48:53 +00:00
Point center ;
2015-10-02 15:22:36 +00:00
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 ) ;
2018-12-01 21:48:53 +00:00
circle ( img , center , radius , CV_RGB ( 0 , 0 , 200 ) , 1 , 8 , 0 ) ;
2015-10-02 15:22:36 +00:00
}
}
2013-01-27 17:05:27 +00:00
}
}
2014-07-05 00:55:11 +00:00
2013-01-27 17:05:27 +00:00
/* Push out the incoming buffer */
return GST_FLOW_OK ;
}
2015-10-02 15:22:36 +00:00
static CascadeClassifier *
2015-08-17 15:47:42 +00:00
gst_handdetect_load_profile ( GstHanddetect * filter , gchar * profile )
2013-01-27 17:05:27 +00:00
{
2015-10-02 15:22:36 +00:00
CascadeClassifier * cascade ;
2015-08-17 15:47:42 +00:00
2015-10-02 15:22:36 +00:00
cascade = new CascadeClassifier ( profile ) ;
if ( cascade - > empty ( ) ) {
GST_ERROR_OBJECT ( filter , " Invalid profile file: %s " , profile ) ;
delete cascade ;
2015-08-17 15:47:42 +00:00
return NULL ;
}
2015-10-02 15:22:36 +00:00
2015-08-17 15:47:42 +00:00
return cascade ;
2013-01-27 17:05:27 +00:00
}
/* 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 ) ;
}