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:
Vanessa Chipirrás 2015-07-31 13:45:43 +01:00 committed by Luis de Bethencourt
parent 9115a750f7
commit 78d0c5f01e
4 changed files with 146 additions and 139 deletions

View file

@ -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 \

View file

@ -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 &lt;= GstFaceDetect::min-size-width or
* GstFaceDetect::min-size-height.
* until the size is &lt;= 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);
}

View file

@ -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;
};

View file

@ -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