facedetect: new property to control bus messages updates
https://bugzilla.gnome.org/show_bug.cgi?id=655622
This commit is contained in:
parent
21ea46568b
commit
e481ecbf22
@ -113,7 +113,8 @@ enum
|
|||||||
PROP_MIN_NEIGHBORS,
|
PROP_MIN_NEIGHBORS,
|
||||||
PROP_FLAGS,
|
PROP_FLAGS,
|
||||||
PROP_MIN_SIZE_WIDTH,
|
PROP_MIN_SIZE_WIDTH,
|
||||||
PROP_MIN_SIZE_HEIGHT
|
PROP_MIN_SIZE_HEIGHT,
|
||||||
|
PROP_UPDATES
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -150,6 +151,32 @@ gst_opencv_face_detect_flags_get_type (void)
|
|||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define GST_TYPE_FACE_DETECT_UPDATES (facedetect_update_get_type ())
|
||||||
|
|
||||||
|
static GType
|
||||||
|
facedetect_update_get_type (void)
|
||||||
|
{
|
||||||
|
static GType facedetect_update_type = 0;
|
||||||
|
static const GEnumValue facedetect_update[] = {
|
||||||
|
{GST_FACEDETECT_UPDATES_EVERY_FRAME, "Send update messages on every frame",
|
||||||
|
"every_frame"},
|
||||||
|
{GST_FACEDETECT_UPDATES_ON_CHANGE,
|
||||||
|
"Send update messages on change (face detected/not detected)",
|
||||||
|
"on_change"},
|
||||||
|
{GST_FACEDETECT_UPDATES_ON_FACE,
|
||||||
|
"Send update messages when a face is detected",
|
||||||
|
"on_face"},
|
||||||
|
{GST_FACEDETECT_UPDATES_NONE, "Send no messages update", "none"},
|
||||||
|
{0, NULL, NULL},
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!facedetect_update_type) {
|
||||||
|
facedetect_update_type =
|
||||||
|
g_enum_register_static ("GstFaceDetectUpdates", facedetect_update);
|
||||||
|
}
|
||||||
|
return facedetect_update_type;
|
||||||
|
}
|
||||||
|
|
||||||
/* the capabilities of the inputs and outputs.
|
/* the capabilities of the inputs and outputs.
|
||||||
*/
|
*/
|
||||||
static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
|
static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
|
||||||
@ -270,6 +297,11 @@ gst_face_detect_class_init (GstFaceDetectClass * klass)
|
|||||||
g_param_spec_int ("min-size-height", "Minimum face height",
|
g_param_spec_int ("min-size-height", "Minimum face height",
|
||||||
"Minimum area height to be recognized as a face", 0, G_MAXINT,
|
"Minimum area height to be recognized as a face", 0, G_MAXINT,
|
||||||
DEFAULT_MIN_SIZE_HEIGHT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
DEFAULT_MIN_SIZE_HEIGHT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||||
|
g_object_class_install_property (gobject_class, PROP_UPDATES,
|
||||||
|
g_param_spec_enum ("updates", "Updates",
|
||||||
|
"When send update bus messages, if at all",
|
||||||
|
GST_TYPE_FACE_DETECT_UPDATES, GST_FACEDETECT_UPDATES_EVERY_FRAME,
|
||||||
|
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||||
|
|
||||||
gst_element_class_set_static_metadata (element_class,
|
gst_element_class_set_static_metadata (element_class,
|
||||||
"facedetect",
|
"facedetect",
|
||||||
@ -294,6 +326,7 @@ gst_face_detect_init (GstFaceDetect * filter)
|
|||||||
filter->mouth_profile = g_strdup (DEFAULT_MOUTH_PROFILE);
|
filter->mouth_profile = g_strdup (DEFAULT_MOUTH_PROFILE);
|
||||||
filter->eyes_profile = g_strdup (DEFAULT_EYES_PROFILE);
|
filter->eyes_profile = g_strdup (DEFAULT_EYES_PROFILE);
|
||||||
filter->display = TRUE;
|
filter->display = TRUE;
|
||||||
|
filter->face_detected = FALSE;
|
||||||
filter->scale_factor = DEFAULT_SCALE_FACTOR;
|
filter->scale_factor = DEFAULT_SCALE_FACTOR;
|
||||||
filter->min_neighbors = DEFAULT_MIN_NEIGHBORS;
|
filter->min_neighbors = DEFAULT_MIN_NEIGHBORS;
|
||||||
filter->flags = DEFAULT_FLAGS;
|
filter->flags = DEFAULT_FLAGS;
|
||||||
@ -310,6 +343,7 @@ gst_face_detect_init (GstFaceDetect * filter)
|
|||||||
|
|
||||||
gst_opencv_video_filter_set_in_place (GST_OPENCV_VIDEO_FILTER_CAST (filter),
|
gst_opencv_video_filter_set_in_place (GST_OPENCV_VIDEO_FILTER_CAST (filter),
|
||||||
TRUE);
|
TRUE);
|
||||||
|
filter->updates = GST_FACEDETECT_UPDATES_EVERY_FRAME;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -369,6 +403,9 @@ gst_face_detect_set_property (GObject * object, guint prop_id,
|
|||||||
case PROP_FLAGS:
|
case PROP_FLAGS:
|
||||||
filter->flags = g_value_get_flags (value);
|
filter->flags = g_value_get_flags (value);
|
||||||
break;
|
break;
|
||||||
|
case PROP_UPDATES:
|
||||||
|
filter->updates = g_value_get_enum (value);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||||
break;
|
break;
|
||||||
@ -412,6 +449,9 @@ gst_face_detect_get_property (GObject * object, guint prop_id,
|
|||||||
case PROP_FLAGS:
|
case PROP_FLAGS:
|
||||||
g_value_set_flags (value, filter->flags);
|
g_value_set_flags (value, filter->flags);
|
||||||
break;
|
break;
|
||||||
|
case PROP_UPDATES:
|
||||||
|
g_value_set_enum (value, filter->updates);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||||
break;
|
break;
|
||||||
@ -497,6 +537,7 @@ gst_face_detect_transform_ip (GstOpencvVideoFilter * base, GstBuffer * buf,
|
|||||||
CvSeq *mouth = NULL, *nose = NULL, *eyes = NULL;
|
CvSeq *mouth = NULL, *nose = NULL, *eyes = NULL;
|
||||||
gint i;
|
gint i;
|
||||||
gboolean do_display = FALSE;
|
gboolean do_display = FALSE;
|
||||||
|
gboolean post_msg = FALSE;
|
||||||
|
|
||||||
if (filter->display) {
|
if (filter->display) {
|
||||||
if (gst_buffer_is_writable (buf)) {
|
if (gst_buffer_is_writable (buf)) {
|
||||||
@ -512,8 +553,40 @@ gst_face_detect_transform_ip (GstOpencvVideoFilter * base, GstBuffer * buf,
|
|||||||
faces = gst_face_detect_run_detector (filter, filter->cvFaceDetect,
|
faces = gst_face_detect_run_detector (filter, filter->cvFaceDetect,
|
||||||
filter->min_size_width, filter->min_size_height);
|
filter->min_size_width, filter->min_size_height);
|
||||||
|
|
||||||
msg = gst_face_detect_message_new (filter, buf);
|
switch (filter->updates) {
|
||||||
g_value_init (&facelist, GST_TYPE_LIST);
|
case GST_FACEDETECT_UPDATES_EVERY_FRAME:
|
||||||
|
post_msg = TRUE;
|
||||||
|
break;
|
||||||
|
case GST_FACEDETECT_UPDATES_ON_CHANGE:
|
||||||
|
if (faces && faces->total > 0) {
|
||||||
|
post_msg = TRUE;
|
||||||
|
} else {
|
||||||
|
if (filter->face_detected) {
|
||||||
|
post_msg = TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case GST_FACEDETECT_UPDATES_ON_FACE:
|
||||||
|
if (faces && faces->total > 0) {
|
||||||
|
post_msg = TRUE;
|
||||||
|
} else {
|
||||||
|
post_msg = FALSE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case GST_FACEDETECT_UPDATES_NONE:
|
||||||
|
post_msg = FALSE;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
post_msg = TRUE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
filter->face_detected = faces ? faces->total > 0 : FALSE;
|
||||||
|
|
||||||
|
if (post_msg) {
|
||||||
|
msg = gst_face_detect_message_new (filter, buf);
|
||||||
|
g_value_init (&facelist, GST_TYPE_LIST);
|
||||||
|
}
|
||||||
|
|
||||||
for (i = 0; i < (faces ? faces->total : 0); i++) {
|
for (i = 0; i < (faces ? faces->total : 0); i++) {
|
||||||
CvRect *r = (CvRect *) cvGetSeqElem (faces, i);
|
CvRect *r = (CvRect *) cvGetSeqElem (faces, i);
|
||||||
@ -573,48 +646,49 @@ gst_face_detect_transform_ip (GstOpencvVideoFilter * base, GstBuffer * buf,
|
|||||||
"%2d/%2d: x,y = %4u,%4u: w.h = %4u,%4u : features(e,n,m) = %d,%d,%d",
|
"%2d/%2d: x,y = %4u,%4u: w.h = %4u,%4u : features(e,n,m) = %d,%d,%d",
|
||||||
i, faces->total, r->x, r->y, r->width, r->height,
|
i, faces->total, r->x, r->y, r->width, r->height,
|
||||||
have_eyes, have_nose, have_mouth);
|
have_eyes, have_nose, have_mouth);
|
||||||
|
if (post_msg) {
|
||||||
|
s = gst_structure_new ("face",
|
||||||
|
"x", G_TYPE_UINT, r->x,
|
||||||
|
"y", G_TYPE_UINT, r->y,
|
||||||
|
"width", G_TYPE_UINT, r->width,
|
||||||
|
"height", G_TYPE_UINT, r->height, NULL);
|
||||||
|
if (have_nose) {
|
||||||
|
CvRect *sr = (CvRect *) cvGetSeqElem (nose, 0);
|
||||||
|
GST_LOG_OBJECT (filter, "nose/%d: x,y = %4u,%4u: w.h = %4u,%4u",
|
||||||
|
nose->total, rnx + sr->x, rny + sr->y, sr->width, sr->height);
|
||||||
|
gst_structure_set (s,
|
||||||
|
"nose->x", G_TYPE_UINT, rnx + sr->x,
|
||||||
|
"nose->y", G_TYPE_UINT, rny + sr->y,
|
||||||
|
"nose->width", G_TYPE_UINT, sr->width,
|
||||||
|
"nose->height", G_TYPE_UINT, sr->height, NULL);
|
||||||
|
}
|
||||||
|
if (have_mouth) {
|
||||||
|
CvRect *sr = (CvRect *) cvGetSeqElem (mouth, 0);
|
||||||
|
GST_LOG_OBJECT (filter, "mouth/%d: x,y = %4u,%4u: w.h = %4u,%4u",
|
||||||
|
mouth->total, rmx + sr->x, rmy + sr->y, sr->width, sr->height);
|
||||||
|
gst_structure_set (s,
|
||||||
|
"mouth->x", G_TYPE_UINT, rmx + sr->x,
|
||||||
|
"mouth->y", G_TYPE_UINT, rmy + sr->y,
|
||||||
|
"mouth->width", G_TYPE_UINT, sr->width,
|
||||||
|
"mouth->height", G_TYPE_UINT, sr->height, NULL);
|
||||||
|
}
|
||||||
|
if (have_eyes) {
|
||||||
|
CvRect *sr = (CvRect *) cvGetSeqElem (eyes, 0);
|
||||||
|
GST_LOG_OBJECT (filter, "eyes/%d: x,y = %4u,%4u: w.h = %4u,%4u",
|
||||||
|
eyes->total, rex + sr->x, rey + sr->y, sr->width, sr->height);
|
||||||
|
gst_structure_set (s,
|
||||||
|
"eyes->x", G_TYPE_UINT, rex + sr->x,
|
||||||
|
"eyes->y", G_TYPE_UINT, rey + sr->y,
|
||||||
|
"eyes->width", G_TYPE_UINT, sr->width,
|
||||||
|
"eyes->height", G_TYPE_UINT, sr->height, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
s = gst_structure_new ("face",
|
g_value_init (&facedata, GST_TYPE_STRUCTURE);
|
||||||
"x", G_TYPE_UINT, r->x,
|
g_value_take_boxed (&facedata, s);
|
||||||
"y", G_TYPE_UINT, r->y,
|
gst_value_list_append_value (&facelist, &facedata);
|
||||||
"width", G_TYPE_UINT, r->width,
|
g_value_unset (&facedata);
|
||||||
"height", G_TYPE_UINT, r->height, NULL);
|
s = NULL;
|
||||||
if (have_nose) {
|
|
||||||
CvRect *sr = (CvRect *) cvGetSeqElem (nose, 0);
|
|
||||||
GST_LOG_OBJECT (filter, "nose/%d: x,y = %4u,%4u: w.h = %4u,%4u",
|
|
||||||
nose->total, rnx + sr->x, rny + sr->y, sr->width, sr->height);
|
|
||||||
gst_structure_set (s,
|
|
||||||
"nose->x", G_TYPE_UINT, rnx + sr->x,
|
|
||||||
"nose->y", G_TYPE_UINT, rny + sr->y,
|
|
||||||
"nose->width", G_TYPE_UINT, sr->width,
|
|
||||||
"nose->height", G_TYPE_UINT, sr->height, NULL);
|
|
||||||
}
|
}
|
||||||
if (have_mouth) {
|
|
||||||
CvRect *sr = (CvRect *) cvGetSeqElem (mouth, 0);
|
|
||||||
GST_LOG_OBJECT (filter, "mouth/%d: x,y = %4u,%4u: w.h = %4u,%4u",
|
|
||||||
mouth->total, rmx + sr->x, rmy + sr->y, sr->width, sr->height);
|
|
||||||
gst_structure_set (s,
|
|
||||||
"mouth->x", G_TYPE_UINT, rmx + sr->x,
|
|
||||||
"mouth->y", G_TYPE_UINT, rmy + sr->y,
|
|
||||||
"mouth->width", G_TYPE_UINT, sr->width,
|
|
||||||
"mouth->height", G_TYPE_UINT, sr->height, NULL);
|
|
||||||
}
|
|
||||||
if (have_eyes) {
|
|
||||||
CvRect *sr = (CvRect *) cvGetSeqElem (eyes, 0);
|
|
||||||
GST_LOG_OBJECT (filter, "eyes/%d: x,y = %4u,%4u: w.h = %4u,%4u",
|
|
||||||
eyes->total, rex + sr->x, rey + sr->y, sr->width, sr->height);
|
|
||||||
gst_structure_set (s,
|
|
||||||
"eyes->x", G_TYPE_UINT, rex + sr->x,
|
|
||||||
"eyes->y", G_TYPE_UINT, rey + sr->y,
|
|
||||||
"eyes->width", G_TYPE_UINT, sr->width,
|
|
||||||
"eyes->height", G_TYPE_UINT, sr->height, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
g_value_init (&facedata, GST_TYPE_STRUCTURE);
|
|
||||||
g_value_take_boxed (&facedata, s);
|
|
||||||
gst_value_list_append_value (&facelist, &facedata);
|
|
||||||
g_value_unset (&facedata);
|
|
||||||
s = NULL;
|
|
||||||
|
|
||||||
if (do_display) {
|
if (do_display) {
|
||||||
CvPoint center;
|
CvPoint center;
|
||||||
@ -674,10 +748,12 @@ gst_face_detect_transform_ip (GstOpencvVideoFilter * base, GstBuffer * buf,
|
|||||||
(guint) r->x, (guint) r->y, (guint) r->width, (guint) r->height);
|
(guint) r->x, (guint) r->y, (guint) r->width, (guint) r->height);
|
||||||
}
|
}
|
||||||
|
|
||||||
gst_structure_set_value ((GstStructure *) gst_message_get_structure (msg),
|
if (post_msg) {
|
||||||
"faces", &facelist);
|
gst_structure_set_value ((GstStructure *) gst_message_get_structure (msg),
|
||||||
g_value_unset (&facelist);
|
"faces", &facelist);
|
||||||
gst_element_post_message (GST_ELEMENT (filter), msg);
|
g_value_unset (&facelist);
|
||||||
|
gst_element_post_message (GST_ELEMENT (filter), msg);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return GST_FLOW_OK;
|
return GST_FLOW_OK;
|
||||||
|
@ -70,11 +70,28 @@ G_BEGIN_DECLS
|
|||||||
typedef struct _GstFaceDetect GstFaceDetect;
|
typedef struct _GstFaceDetect GstFaceDetect;
|
||||||
typedef struct _GstFaceDetectClass GstFaceDetectClass;
|
typedef struct _GstFaceDetectClass GstFaceDetectClass;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GstFaceDetectUpdates
|
||||||
|
* @GST_FACEDETECT_UPDATES_EVERY_FRAME: Send bus update messages for every frame
|
||||||
|
* @GST_FACEDETECT_UPDATES_ON_CHANGE: Send bus update messages on change (face detected/not detected)
|
||||||
|
* @GST_FACEDETECT_UPDATES_ON_FACE: Send bus update messages when a face is detected
|
||||||
|
* @GST_FACEDETECT_UPDATES_NONE: No bus update messages
|
||||||
|
*
|
||||||
|
* Bus messages update scheme
|
||||||
|
*/
|
||||||
|
enum _GstFaceDetectUpdates {
|
||||||
|
GST_FACEDETECT_UPDATES_EVERY_FRAME = 0,
|
||||||
|
GST_FACEDETECT_UPDATES_ON_CHANGE = 1,
|
||||||
|
GST_FACEDETECT_UPDATES_ON_FACE = 2,
|
||||||
|
GST_FACEDETECT_UPDATES_NONE = 3
|
||||||
|
};
|
||||||
|
|
||||||
struct _GstFaceDetect
|
struct _GstFaceDetect
|
||||||
{
|
{
|
||||||
GstOpencvVideoFilter element;
|
GstOpencvVideoFilter element;
|
||||||
|
|
||||||
gboolean display;
|
gboolean display;
|
||||||
|
gboolean face_detected;
|
||||||
|
|
||||||
gchar *face_profile;
|
gchar *face_profile;
|
||||||
gchar *nose_profile;
|
gchar *nose_profile;
|
||||||
@ -85,6 +102,7 @@ struct _GstFaceDetect
|
|||||||
gint flags;
|
gint flags;
|
||||||
gint min_size_width;
|
gint min_size_width;
|
||||||
gint min_size_height;
|
gint min_size_height;
|
||||||
|
gint updates;
|
||||||
|
|
||||||
IplImage *cvGray;
|
IplImage *cvGray;
|
||||||
CvHaarClassifierCascade *cvFaceDetect;
|
CvHaarClassifierCascade *cvFaceDetect;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user