mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-27 04:01:08 +00:00
facedetect: need to migrate to C++
The cascade classifier changes its structure on new version of OpenCV. The need to migrate to C++ to utilize the new load method of OpenCV which allows to load the new classifiers. https://bugzilla.gnome.org/show_bug.cgi?id=748377
This commit is contained in:
parent
9115a750f7
commit
78d0c5f01e
4 changed files with 146 additions and 139 deletions
|
@ -1,7 +1,7 @@
|
|||
plugin_LTLIBRARIES = libgstopencv.la
|
||||
|
||||
# sources used to compile this plug-in
|
||||
libgstopencv_la_SOURCES = gstopencv.c \
|
||||
libgstopencv_la_SOURCES = gstopencv.cpp \
|
||||
gstopencvvideofilter.c \
|
||||
gstopencvutils.c \
|
||||
gstcvdilate.c \
|
||||
|
@ -13,7 +13,6 @@ libgstopencv_la_SOURCES = gstopencv.c \
|
|||
gstcvsobel.c \
|
||||
gstedgedetect.c \
|
||||
gstfaceblur.c \
|
||||
gstfacedetect.c \
|
||||
gsthanddetect.c \
|
||||
gstpyramidsegment.c \
|
||||
gsttemplatematch.c \
|
||||
|
@ -21,6 +20,7 @@ libgstopencv_la_SOURCES = gstopencv.c \
|
|||
gstmotioncells.c \
|
||||
gstskindetect.c \
|
||||
gstretinex.c \
|
||||
gstfacedetect.cpp \
|
||||
gstsegmentation.cpp \
|
||||
gstgrabcut.cpp \
|
||||
gstdisparity.cpp \
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* Copyright (C) 2008 Michael Sheldon <mike@mikeasoft.com>
|
||||
* Copyright (C) 2011 Stefan Sauer <ensonic@users.sf.net>
|
||||
* Copyright (C) 2014 Robert Jobbagy <jobbagy.robert@gmail.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
|
||||
|
@ -52,8 +52,8 @@
|
|||
* If you have high cpu load you need to use videoscale with capsfilter and reduce the video resolution.
|
||||
*
|
||||
* The image is scaled down multiple times using the GstFaceDetect::scale-factor
|
||||
* until the size is <= GstFaceDetect::min-size-width or
|
||||
* GstFaceDetect::min-size-height.
|
||||
* until the size is <= GstFaceDetect::min-size-width or
|
||||
* GstFaceDetect::min-size-height.
|
||||
*
|
||||
* <refsect2>
|
||||
* <title>Example launch line</title>
|
||||
|
@ -62,7 +62,7 @@
|
|||
* ]| Detect and show faces
|
||||
* |[
|
||||
* gst-launch-1.0 autovideosrc ! video/x-raw,width=320,height=240 ! videoconvert ! facedetect min-size-width=60 min-size-height=60 ! colorspace ! xvimagesink
|
||||
* ]| Detect large faces on a smaller image
|
||||
* ]| Detect large faces on a smaller image
|
||||
*
|
||||
* </refsect2>
|
||||
*/
|
||||
|
@ -78,6 +78,7 @@
|
|||
|
||||
#include <gst/gst.h>
|
||||
#include <gst/video/gstvideometa.h>
|
||||
#include <vector>
|
||||
|
||||
#include "gstopencvutils.h"
|
||||
#include "gstfacedetect.h"
|
||||
|
@ -100,6 +101,7 @@ GST_DEBUG_CATEGORY_STATIC (gst_face_detect_debug);
|
|||
#define DEFAULT_MIN_SIZE_HEIGHT 30
|
||||
#define DEFAULT_MIN_STDDEV 0
|
||||
|
||||
using namespace cv;
|
||||
/* Filter signals and args */
|
||||
enum
|
||||
{
|
||||
|
@ -211,7 +213,7 @@ static gboolean gst_face_detect_set_caps (GstOpencvVideoFilter * transform,
|
|||
static GstFlowReturn gst_face_detect_transform_ip (GstOpencvVideoFilter * base,
|
||||
GstBuffer * buf, IplImage * img);
|
||||
|
||||
static CvHaarClassifierCascade *gst_face_detect_load_profile (GstFaceDetect *
|
||||
static CascadeClassifier *gst_face_detect_load_profile (GstFaceDetect *
|
||||
filter, gchar * profile);
|
||||
|
||||
/* Clean up */
|
||||
|
@ -221,7 +223,7 @@ gst_face_detect_finalize (GObject * obj)
|
|||
GstFaceDetect *filter = GST_FACE_DETECT (obj);
|
||||
|
||||
if (filter->cvGray)
|
||||
cvReleaseImage (&filter->cvGray);
|
||||
delete (&filter->cvGray);
|
||||
if (filter->cvStorage)
|
||||
cvReleaseMemStorage (&filter->cvStorage);
|
||||
|
||||
|
@ -231,13 +233,13 @@ gst_face_detect_finalize (GObject * obj)
|
|||
g_free (filter->eyes_profile);
|
||||
|
||||
if (filter->cvFaceDetect)
|
||||
cvReleaseHaarClassifierCascade (&filter->cvFaceDetect);
|
||||
delete (&filter->cvFaceDetect);
|
||||
if (filter->cvNoseDetect)
|
||||
cvReleaseHaarClassifierCascade (&filter->cvNoseDetect);
|
||||
delete (&filter->cvNoseDetect);
|
||||
if (filter->cvMouthDetect)
|
||||
cvReleaseHaarClassifierCascade (&filter->cvMouthDetect);
|
||||
delete (&filter->cvMouthDetect);
|
||||
if (filter->cvEyesDetect)
|
||||
cvReleaseHaarClassifierCascade (&filter->cvEyesDetect);
|
||||
delete (&filter->cvEyesDetect);
|
||||
|
||||
G_OBJECT_CLASS (gst_face_detect_parent_class)->finalize (obj);
|
||||
}
|
||||
|
@ -263,60 +265,66 @@ gst_face_detect_class_init (GstFaceDetectClass * klass)
|
|||
g_object_class_install_property (gobject_class, PROP_DISPLAY,
|
||||
g_param_spec_boolean ("display", "Display",
|
||||
"Sets whether the detected faces should be highlighted in the output",
|
||||
TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||
TRUE, (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
|
||||
|
||||
g_object_class_install_property (gobject_class, PROP_FACE_PROFILE,
|
||||
g_param_spec_string ("profile", "Face profile",
|
||||
"Location of Haar cascade file to use for face detection",
|
||||
DEFAULT_FACE_PROFILE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||
DEFAULT_FACE_PROFILE,
|
||||
(GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
|
||||
g_object_class_install_property (gobject_class, PROP_NOSE_PROFILE,
|
||||
g_param_spec_string ("nose-profile", "Nose profile",
|
||||
"Location of Haar cascade file to use for nose detection",
|
||||
DEFAULT_NOSE_PROFILE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||
DEFAULT_NOSE_PROFILE,
|
||||
(GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
|
||||
g_object_class_install_property (gobject_class, PROP_MOUTH_PROFILE,
|
||||
g_param_spec_string ("mouth-profile", "Mouth profile",
|
||||
"Location of Haar cascade file to use for mouth detection",
|
||||
DEFAULT_MOUTH_PROFILE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||
DEFAULT_MOUTH_PROFILE,
|
||||
(GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
|
||||
g_object_class_install_property (gobject_class, PROP_EYES_PROFILE,
|
||||
g_param_spec_string ("eyes-profile", "Eyes profile",
|
||||
"Location of Haar cascade file to use for eye-pair detection",
|
||||
DEFAULT_EYES_PROFILE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||
DEFAULT_EYES_PROFILE,
|
||||
(GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
|
||||
|
||||
g_object_class_install_property (gobject_class, PROP_FLAGS,
|
||||
g_param_spec_flags ("flags", "Flags", "Flags to cvHaarDetectObjects",
|
||||
GST_TYPE_OPENCV_FACE_DETECT_FLAGS, DEFAULT_FLAGS,
|
||||
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||
(GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
|
||||
g_object_class_install_property (gobject_class, PROP_SCALE_FACTOR,
|
||||
g_param_spec_double ("scale-factor", "Scale factor",
|
||||
"Factor by which the frame is scaled after each object scan",
|
||||
1.1, 10.0, DEFAULT_SCALE_FACTOR,
|
||||
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||
(GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
|
||||
g_object_class_install_property (gobject_class, PROP_MIN_NEIGHBORS,
|
||||
g_param_spec_int ("min-neighbors", "Mininum neighbors",
|
||||
"Minimum number (minus 1) of neighbor rectangles that makes up "
|
||||
"an object", 0, G_MAXINT, DEFAULT_MIN_NEIGHBORS,
|
||||
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||
(GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
|
||||
g_object_class_install_property (gobject_class, PROP_MIN_SIZE_WIDTH,
|
||||
g_param_spec_int ("min-size-width", "Minimum face width",
|
||||
"Minimum area width to be recognized as a face", 0, G_MAXINT,
|
||||
DEFAULT_MIN_SIZE_WIDTH, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||
DEFAULT_MIN_SIZE_WIDTH,
|
||||
(GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
|
||||
g_object_class_install_property (gobject_class, PROP_MIN_SIZE_HEIGHT,
|
||||
g_param_spec_int ("min-size-height", "Minimum face height",
|
||||
"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,
|
||||
(GParamFlags) (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));
|
||||
(GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
|
||||
g_object_class_install_property (gobject_class, PROP_MIN_STDDEV,
|
||||
g_param_spec_int ("min-stddev", "Minimum image standard deviation",
|
||||
"Minimum image average standard deviation: on images with standard "
|
||||
"deviation lesser than this value facedetection will not be "
|
||||
"performed. Setting this property help to save cpu and reduce "
|
||||
"false positives not performing face detection on images with "
|
||||
"little changes", 0,
|
||||
255, DEFAULT_MIN_STDDEV, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||
"little changes", 0, 255, DEFAULT_MIN_STDDEV,
|
||||
(GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
|
||||
|
||||
gst_element_class_set_static_metadata (element_class,
|
||||
"facedetect",
|
||||
|
@ -372,7 +380,7 @@ gst_face_detect_set_property (GObject * object, guint prop_id,
|
|||
case PROP_FACE_PROFILE:
|
||||
g_free (filter->face_profile);
|
||||
if (filter->cvFaceDetect)
|
||||
cvReleaseHaarClassifierCascade (&filter->cvFaceDetect);
|
||||
delete (&filter->cvFaceDetect);
|
||||
filter->face_profile = g_value_dup_string (value);
|
||||
filter->cvFaceDetect =
|
||||
gst_face_detect_load_profile (filter, filter->face_profile);
|
||||
|
@ -380,7 +388,7 @@ gst_face_detect_set_property (GObject * object, guint prop_id,
|
|||
case PROP_NOSE_PROFILE:
|
||||
g_free (filter->nose_profile);
|
||||
if (filter->cvNoseDetect)
|
||||
cvReleaseHaarClassifierCascade (&filter->cvNoseDetect);
|
||||
delete (&filter->cvNoseDetect);
|
||||
filter->nose_profile = g_value_dup_string (value);
|
||||
filter->cvNoseDetect =
|
||||
gst_face_detect_load_profile (filter, filter->nose_profile);
|
||||
|
@ -388,7 +396,7 @@ gst_face_detect_set_property (GObject * object, guint prop_id,
|
|||
case PROP_MOUTH_PROFILE:
|
||||
g_free (filter->mouth_profile);
|
||||
if (filter->cvMouthDetect)
|
||||
cvReleaseHaarClassifierCascade (&filter->cvMouthDetect);
|
||||
delete (&filter->cvMouthDetect);
|
||||
filter->mouth_profile = g_value_dup_string (value);
|
||||
filter->cvMouthDetect =
|
||||
gst_face_detect_load_profile (filter, filter->mouth_profile);
|
||||
|
@ -396,7 +404,7 @@ gst_face_detect_set_property (GObject * object, guint prop_id,
|
|||
case PROP_EYES_PROFILE:
|
||||
g_free (filter->eyes_profile);
|
||||
if (filter->cvEyesDetect)
|
||||
cvReleaseHaarClassifierCascade (&filter->cvEyesDetect);
|
||||
delete (&filter->cvEyesDetect);
|
||||
filter->eyes_profile = g_value_dup_string (value);
|
||||
filter->cvEyesDetect =
|
||||
gst_face_detect_load_profile (filter, filter->eyes_profile);
|
||||
|
@ -493,7 +501,7 @@ gst_face_detect_set_caps (GstOpencvVideoFilter * transform, gint in_width,
|
|||
filter = GST_FACE_DETECT (transform);
|
||||
|
||||
if (filter->cvGray)
|
||||
cvReleaseImage (&filter->cvGray);
|
||||
delete (&filter->cvGray);
|
||||
|
||||
filter->cvGray = cvCreateImage (cvSize (in_width, in_height), IPL_DEPTH_8U,
|
||||
1);
|
||||
|
@ -527,10 +535,10 @@ gst_face_detect_message_new (GstFaceDetect * filter, GstBuffer * buf)
|
|||
return gst_message_new_element (GST_OBJECT (filter), s);
|
||||
}
|
||||
|
||||
static CvSeq *
|
||||
static void
|
||||
gst_face_detect_run_detector (GstFaceDetect * filter,
|
||||
CvHaarClassifierCascade * detector, gint min_size_width,
|
||||
gint min_size_height)
|
||||
CascadeClassifier * detector, gint min_size_width,
|
||||
gint min_size_height, Rect r, vector<Rect> &faces)
|
||||
{
|
||||
double img_stddev = 0;
|
||||
if (filter->min_stddev > 0) {
|
||||
|
@ -539,9 +547,10 @@ gst_face_detect_run_detector (GstFaceDetect * filter,
|
|||
img_stddev = stddev.val[0];
|
||||
}
|
||||
if (img_stddev >= filter->min_stddev) {
|
||||
return cvHaarDetectObjects (filter->cvGray, detector,
|
||||
filter->cvStorage, filter->scale_factor, filter->min_neighbors,
|
||||
filter->flags, cvSize (min_size_width, min_size_height)
|
||||
Mat roi (filter->cvGray, r);
|
||||
detector->detectMultiScale (roi, faces, filter->scale_factor,
|
||||
filter->min_neighbors, filter->flags, cvSize (min_size_width,
|
||||
min_size_height)
|
||||
#if (CV_MAJOR_VERSION >= 2) && (CV_MINOR_VERSION >= 2)
|
||||
, cvSize (0, 0)
|
||||
#endif
|
||||
|
@ -550,7 +559,6 @@ gst_face_detect_run_detector (GstFaceDetect * filter,
|
|||
GST_LOG_OBJECT (filter,
|
||||
"Calculated stddev %f lesser than min_stddev %d, detection not performed",
|
||||
img_stddev, filter->min_stddev);
|
||||
return cvCreateSeq (0, sizeof (CvSeq), sizeof (CvPoint), filter->cvStorage);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -568,12 +576,15 @@ gst_face_detect_transform_ip (GstOpencvVideoFilter * base, GstBuffer * buf,
|
|||
GstStructure *s;
|
||||
GValue facelist = { 0 };
|
||||
GValue facedata = { 0 };
|
||||
CvSeq *faces;
|
||||
CvSeq *mouth = NULL, *nose = NULL, *eyes = NULL;
|
||||
gint i;
|
||||
vector<Rect> faces;
|
||||
vector<Rect> mouth;
|
||||
vector<Rect> nose;
|
||||
vector<Rect> eyes;
|
||||
gboolean do_display = FALSE;
|
||||
gboolean post_msg = FALSE;
|
||||
|
||||
Mat mtxOrg (img, false);
|
||||
|
||||
if (filter->display) {
|
||||
if (gst_buffer_is_writable (buf)) {
|
||||
do_display = TRUE;
|
||||
|
@ -585,15 +596,17 @@ gst_face_detect_transform_ip (GstOpencvVideoFilter * base, GstBuffer * buf,
|
|||
cvCvtColor (img, filter->cvGray, CV_RGB2GRAY);
|
||||
cvClearMemStorage (filter->cvStorage);
|
||||
|
||||
faces = gst_face_detect_run_detector (filter, filter->cvFaceDetect,
|
||||
filter->min_size_width, filter->min_size_height);
|
||||
gst_face_detect_run_detector (filter, filter->cvFaceDetect,
|
||||
filter->min_size_width, filter->min_size_height,
|
||||
Rect (filter->cvGray->origin, filter->cvGray->origin,
|
||||
filter->cvGray->width, filter->cvGray->height), faces);
|
||||
|
||||
switch (filter->updates) {
|
||||
case GST_FACEDETECT_UPDATES_EVERY_FRAME:
|
||||
post_msg = TRUE;
|
||||
break;
|
||||
case GST_FACEDETECT_UPDATES_ON_CHANGE:
|
||||
if (faces && faces->total > 0) {
|
||||
if (!faces.empty () && (faces.size () > 0)) {
|
||||
if (!filter->face_detected)
|
||||
post_msg = TRUE;
|
||||
} else {
|
||||
|
@ -603,7 +616,7 @@ gst_face_detect_transform_ip (GstOpencvVideoFilter * base, GstBuffer * buf,
|
|||
}
|
||||
break;
|
||||
case GST_FACEDETECT_UPDATES_ON_FACE:
|
||||
if (faces && faces->total > 0) {
|
||||
if (!faces.empty () && (faces.size () > 0)) {
|
||||
post_msg = TRUE;
|
||||
} else {
|
||||
post_msg = FALSE;
|
||||
|
@ -617,15 +630,15 @@ gst_face_detect_transform_ip (GstOpencvVideoFilter * base, GstBuffer * buf,
|
|||
break;
|
||||
}
|
||||
|
||||
filter->face_detected = faces ? faces->total > 0 : FALSE;
|
||||
filter->face_detected = !faces.empty ()? faces.size () > 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++) {
|
||||
CvRect *r = (CvRect *) cvGetSeqElem (faces, i);
|
||||
for (unsigned int i = 0; i < faces.size (); ++i) {
|
||||
Rect r = faces[i];
|
||||
guint mw = filter->min_size_width / 8;
|
||||
guint mh = filter->min_size_height / 8;
|
||||
guint rnx = 0, rny = 0, rnw, rnh;
|
||||
|
@ -636,87 +649,80 @@ gst_face_detect_transform_ip (GstOpencvVideoFilter * base, GstBuffer * buf,
|
|||
/* detect face features */
|
||||
|
||||
if (filter->cvNoseDetect) {
|
||||
rnx = r->x + r->width / 4;
|
||||
rny = r->y + r->height / 4;
|
||||
rnw = r->width / 2;
|
||||
rnh = r->height / 2;
|
||||
cvSetImageROI (filter->cvGray, cvRect (rnx, rny, rnw, rnh));
|
||||
nose =
|
||||
gst_face_detect_run_detector (filter, filter->cvNoseDetect, mw, mh);
|
||||
have_nose = (nose && nose->total);
|
||||
cvResetImageROI (filter->cvGray);
|
||||
rnx = r.x + r.width / 4;
|
||||
rny = r.y + r.height / 4;
|
||||
rnw = r.width / 2;
|
||||
rnh = r.height / 2;
|
||||
gst_face_detect_run_detector (filter, filter->cvNoseDetect, mw, mh,
|
||||
Rect (rnx, rny, rnw, rnh), nose);
|
||||
have_nose = (!nose.empty () && nose.size ());
|
||||
} else {
|
||||
have_nose = FALSE;
|
||||
}
|
||||
|
||||
if (filter->cvMouthDetect) {
|
||||
rmx = r->x;
|
||||
rmy = r->y + r->height / 2;
|
||||
rmw = r->width;
|
||||
rmh = r->height / 2;
|
||||
cvSetImageROI (filter->cvGray, cvRect (rmx, rmy, rmw, rmh));
|
||||
mouth =
|
||||
gst_face_detect_run_detector (filter, filter->cvMouthDetect, mw,
|
||||
mh);
|
||||
have_mouth = (mouth && mouth->total);
|
||||
cvResetImageROI (filter->cvGray);
|
||||
rmx = r.x;
|
||||
rmy = r.y + r.height / 2;
|
||||
rmw = r.width;
|
||||
rmh = r.height / 2;
|
||||
gst_face_detect_run_detector (filter, filter->cvMouthDetect, mw,
|
||||
mh, Rect (rmx, rmy, rmw, rmh), mouth);
|
||||
have_mouth = (!mouth.empty () && mouth.size ());
|
||||
} else {
|
||||
have_mouth = FALSE;
|
||||
}
|
||||
|
||||
if (filter->cvEyesDetect) {
|
||||
rex = r->x;
|
||||
rey = r->y;
|
||||
rew = r->width;
|
||||
reh = r->height / 2;
|
||||
cvSetImageROI (filter->cvGray, cvRect (rex, rey, rew, reh));
|
||||
eyes =
|
||||
gst_face_detect_run_detector (filter, filter->cvEyesDetect, mw, mh);
|
||||
have_eyes = (eyes && eyes->total);
|
||||
cvResetImageROI (filter->cvGray);
|
||||
rex = r.x;
|
||||
rey = r.y;
|
||||
rew = r.width;
|
||||
reh = r.height / 2;
|
||||
gst_face_detect_run_detector (filter, filter->cvEyesDetect, mw, mh,
|
||||
Rect (rex, rey, rew, reh), eyes);
|
||||
have_eyes = (!eyes.empty () && eyes.size ());
|
||||
} else {
|
||||
have_eyes = FALSE;
|
||||
}
|
||||
|
||||
GST_LOG_OBJECT (filter,
|
||||
"%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,
|
||||
"%2d/%2lu: x,y = %4u,%4u: w.h = %4u,%4u : features(e,n,m) = %d,%d,%d",
|
||||
i, faces.size (), r.x, r.y, r.width, r.height,
|
||||
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);
|
||||
"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);
|
||||
Rect sr = nose[0];
|
||||
GST_LOG_OBJECT (filter, "nose/%lu: x,y = %4u,%4u: w.h = %4u,%4u",
|
||||
nose.size (), 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);
|
||||
"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);
|
||||
Rect sr = mouth[0];
|
||||
GST_LOG_OBJECT (filter, "mouth/%lu: x,y = %4u,%4u: w.h = %4u,%4u",
|
||||
mouth.size (), 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);
|
||||
"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);
|
||||
Rect sr = eyes[0];
|
||||
GST_LOG_OBJECT (filter, "eyes/%ld: x,y = %4u,%4u: w.h = %4u,%4u",
|
||||
eyes.size (), 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);
|
||||
"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);
|
||||
|
@ -728,60 +734,59 @@ gst_face_detect_transform_ip (GstOpencvVideoFilter * base, GstBuffer * buf,
|
|||
|
||||
if (do_display) {
|
||||
CvPoint center;
|
||||
CvSize axes;
|
||||
Size axes;
|
||||
gdouble w, h;
|
||||
gint cb = 255 - ((i & 3) << 7);
|
||||
gint cg = 255 - ((i & 12) << 5);
|
||||
gint cr = 255 - ((i & 48) << 3);
|
||||
|
||||
w = r->width / 2;
|
||||
h = r->height / 2;
|
||||
center.x = cvRound ((r->x + w));
|
||||
center.y = cvRound ((r->y + h));
|
||||
w = r.width / 2;
|
||||
h = r.height / 2;
|
||||
center.x = cvRound ((r.x + w));
|
||||
center.y = cvRound ((r.y + h));
|
||||
axes.width = w;
|
||||
axes.height = h * 1.25; /* tweak for face form */
|
||||
cvEllipse (img, center, axes, 0.0, 0.0, 360.0, CV_RGB (cr, cg, cb),
|
||||
3, 8, 0);
|
||||
ellipse (mtxOrg, center, axes, 0, 0, 360, Scalar (cr, cg, cb), 3, 8, 0);
|
||||
|
||||
if (have_nose) {
|
||||
CvRect *sr = (CvRect *) cvGetSeqElem (nose, 0);
|
||||
Rect sr = nose[0];
|
||||
|
||||
w = sr->width / 2;
|
||||
h = sr->height / 2;
|
||||
center.x = cvRound ((rnx + sr->x + w));
|
||||
center.y = cvRound ((rny + sr->y + h));
|
||||
w = sr.width / 2;
|
||||
h = sr.height / 2;
|
||||
center.x = cvRound ((rnx + sr.x + w));
|
||||
center.y = cvRound ((rny + sr.y + h));
|
||||
axes.width = w;
|
||||
axes.height = h * 1.25; /* tweak for nose form */
|
||||
cvEllipse (img, center, axes, 0.0, 0.0, 360.0, CV_RGB (cr, cg, cb),
|
||||
1, 8, 0);
|
||||
ellipse (mtxOrg, center, axes, 0, 0, 360, Scalar (cr, cg, cb), 1, 8,
|
||||
0);
|
||||
}
|
||||
if (have_mouth) {
|
||||
CvRect *sr = (CvRect *) cvGetSeqElem (mouth, 0);
|
||||
Rect sr = mouth[0];
|
||||
|
||||
w = sr->width / 2;
|
||||
h = sr->height / 2;
|
||||
center.x = cvRound ((rmx + sr->x + w));
|
||||
center.y = cvRound ((rmy + sr->y + h));
|
||||
w = sr.width / 2;
|
||||
h = sr.height / 2;
|
||||
center.x = cvRound ((rmx + sr.x + w));
|
||||
center.y = cvRound ((rmy + sr.y + h));
|
||||
axes.width = w * 1.5; /* tweak for mouth form */
|
||||
axes.height = h;
|
||||
cvEllipse (img, center, axes, 0.0, 0.0, 360.0, CV_RGB (cr, cg, cb),
|
||||
1, 8, 0);
|
||||
ellipse (mtxOrg, center, axes, 0, 0, 360, Scalar (cr, cg, cb), 1, 8,
|
||||
0);
|
||||
}
|
||||
if (have_eyes) {
|
||||
CvRect *sr = (CvRect *) cvGetSeqElem (eyes, 0);
|
||||
Rect sr = eyes[0];
|
||||
|
||||
w = sr->width / 2;
|
||||
h = sr->height / 2;
|
||||
center.x = cvRound ((rex + sr->x + w));
|
||||
center.y = cvRound ((rey + sr->y + h));
|
||||
w = sr.width / 2;
|
||||
h = sr.height / 2;
|
||||
center.x = cvRound ((rex + sr.x + w));
|
||||
center.y = cvRound ((rey + sr.y + h));
|
||||
axes.width = w * 1.5; /* tweak for eyes form */
|
||||
axes.height = h;
|
||||
cvEllipse (img, center, axes, 0.0, 0.0, 360.0, CV_RGB (cr, cg, cb),
|
||||
1, 8, 0);
|
||||
ellipse (mtxOrg, center, axes, 0, 0, 360, Scalar (cr, cg, cb), 1, 8,
|
||||
0);
|
||||
}
|
||||
}
|
||||
gst_buffer_add_video_region_of_interest_meta (buf, "face",
|
||||
(guint) r->x, (guint) r->y, (guint) r->width, (guint) r->height);
|
||||
(guint) r.x, (guint) r.y, (guint) r.width, (guint) r.height);
|
||||
}
|
||||
|
||||
if (post_msg) {
|
||||
|
@ -790,20 +795,21 @@ gst_face_detect_transform_ip (GstOpencvVideoFilter * base, GstBuffer * buf,
|
|||
g_value_unset (&facelist);
|
||||
gst_element_post_message (GST_ELEMENT (filter), msg);
|
||||
}
|
||||
mtxOrg.release ();
|
||||
}
|
||||
|
||||
return GST_FLOW_OK;
|
||||
}
|
||||
|
||||
|
||||
static CvHaarClassifierCascade *
|
||||
static CascadeClassifier *
|
||||
gst_face_detect_load_profile (GstFaceDetect * filter, gchar * profile)
|
||||
{
|
||||
CvHaarClassifierCascade *cascade;
|
||||
CascadeClassifier *cascade = new CascadeClassifier (profile);
|
||||
|
||||
if (profile == NULL)
|
||||
return NULL;
|
||||
if (!(cascade = (CvHaarClassifierCascade *) cvLoad (profile, 0, 0, 0))) {
|
||||
if (!cascade) {
|
||||
GST_WARNING_OBJECT (filter, "Couldn't load Haar classifier cascade: %s.",
|
||||
profile);
|
||||
}
|
|
@ -50,6 +50,7 @@
|
|||
|
||||
#include <gst/gst.h>
|
||||
#include <opencv2/core/version.hpp>
|
||||
#include <cv.h>
|
||||
#include "gstopencvvideofilter.h"
|
||||
|
||||
#if (CV_MAJOR_VERSION >= 2) && (CV_MINOR_VERSION >= 2)
|
||||
|
@ -107,10 +108,10 @@ struct _GstFaceDetect
|
|||
gint updates;
|
||||
|
||||
IplImage *cvGray;
|
||||
CvHaarClassifierCascade *cvFaceDetect;
|
||||
CvHaarClassifierCascade *cvNoseDetect;
|
||||
CvHaarClassifierCascade *cvMouthDetect;
|
||||
CvHaarClassifierCascade *cvEyesDetect;
|
||||
cv::CascadeClassifier *cvFaceDetect;
|
||||
cv::CascadeClassifier *cvNoseDetect;
|
||||
cv::CascadeClassifier *cvMouthDetect;
|
||||
cv::CascadeClassifier *cvEyesDetect;
|
||||
CvMemStorage *cvStorage;
|
||||
};
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) <2009> Kapil Agrawal <kapil@mediamagictechnologies.com>
|
||||
*
|
||||
* gstopencv.c: plugin registering
|
||||
* gstopencv.cpp: plugin registering
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
Loading…
Reference in a new issue