facedetect: detect face features

Also detect mouth, nose and eyes. Drop faces that don't have them. Fixes leaking the
cascades. Adds more docs.
This commit is contained in:
Stefan Sauer 2011-11-16 20:53:13 +01:00
parent a857c90590
commit fefa1df8b9
2 changed files with 287 additions and 55 deletions

View File

@ -3,6 +3,7 @@
* Copyright (C) 2005 Thomas Vander Stichele <thomas@apestaart.org> * Copyright (C) 2005 Thomas Vander Stichele <thomas@apestaart.org>
* Copyright (C) 2005 Ronald S. Bultje <rbultje@ronald.bitfreak.net> * Copyright (C) 2005 Ronald S. Bultje <rbultje@ronald.bitfreak.net>
* Copyright (C) 2008 Michael Sheldon <mike@mikeasoft.com> * Copyright (C) 2008 Michael Sheldon <mike@mikeasoft.com>
* Copyright (C) 2011 Stefan Sauer <ensonic@users.sf.net>
* *
* Permission is hereby granted, free of charge, to any person obtaining a * Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"), * copy of this software and associated documentation files (the "Software"),
@ -48,14 +49,27 @@
* *
* Performs face detection on videos and images. * Performs face detection on videos and images.
* *
* 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.
*
* <refsect2> * <refsect2>
* <title>Example launch line</title> * <title>Example launch line</title>
* |[ * |[
* gst-launch-0.10 autovideosrc ! decodebin2 ! colorspace ! facedetect ! colorspace ! xvimagesink * gst-launch-0.10 autovideosrc ! decodebin2 ! colorspace ! facedetect ! colorspace ! xvimagesink
* ]| * ]| Detect and show faces
* |[
* gst-launch-0.10 autovideosrc ! video/x-raw-yuv,width=320,height=240 ! colorspace ! facedetect min-size-width=60 min-size-height=60 ! colorspace ! xvimagesink
* ]| Detect large faces on a smaller image
*
* </refsect2> * </refsect2>
*/ */
/* FIXME: development version of OpenCV has CV_HAAR_FIND_BIGGEST_OBJECT which
* we might want to use if available
* see https://code.ros.org/svn/opencv/trunk/opencv/modules/objdetect/src/haar.cpp
*/
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
# include <config.h> # include <config.h>
#endif #endif
@ -67,7 +81,10 @@
GST_DEBUG_CATEGORY_STATIC (gst_facedetect_debug); GST_DEBUG_CATEGORY_STATIC (gst_facedetect_debug);
#define GST_CAT_DEFAULT gst_facedetect_debug #define GST_CAT_DEFAULT gst_facedetect_debug
#define DEFAULT_PROFILE "/usr/share/opencv/haarcascades/haarcascade_frontalface_default.xml" #define DEFAULT_FACE_PROFILE "/usr/share/opencv/haarcascades/haarcascade_frontalface_default.xml"
#define DEFAULT_NOSE_PROFILE "/usr/share/opencv/haarcascades/haarcascade_mcs_nose.xml"
#define DEFAULT_MOUTH_PROFILE "/usr/share/opencv/haarcascades/haarcascade_mcs_mouth.xml"
#define DEFAULT_EYES_PROFILE "/usr/share/opencv/haarcascades/haarcascade_mcs_eyepair_small.xml"
#define DEFAULT_SCALE_FACTOR 1.1 #define DEFAULT_SCALE_FACTOR 1.1
#define DEFAULT_FLAGS 0 #define DEFAULT_FLAGS 0
#define DEFAULT_MIN_NEIGHBORS 3 #define DEFAULT_MIN_NEIGHBORS 3
@ -85,7 +102,10 @@ enum
{ {
PROP_0, PROP_0,
PROP_DISPLAY, PROP_DISPLAY,
PROP_PROFILE, PROP_FACE_PROFILE,
PROP_NOSE_PROFILE,
PROP_MOUTH_PROFILE,
PROP_EYES_PROFILE,
PROP_SCALE_FACTOR, PROP_SCALE_FACTOR,
PROP_MIN_NEIGHBORS, PROP_MIN_NEIGHBORS,
PROP_FLAGS, PROP_FLAGS,
@ -155,7 +175,8 @@ static gboolean gst_facedetect_set_caps (GstOpencvVideoFilter * transform,
static GstFlowReturn gst_facedetect_transform_ip (GstOpencvVideoFilter * base, static GstFlowReturn gst_facedetect_transform_ip (GstOpencvVideoFilter * base,
GstBuffer * buf, IplImage * img); GstBuffer * buf, IplImage * img);
static void gst_facedetect_load_profile (GstFacedetect * filter); static CvHaarClassifierCascade *gst_facedetect_load_profile (GstFacedetect *
filter, gchar * profile);
/* Clean up */ /* Clean up */
static void static void
@ -163,14 +184,24 @@ gst_facedetect_finalize (GObject * obj)
{ {
GstFacedetect *filter = GST_FACEDETECT (obj); GstFacedetect *filter = GST_FACEDETECT (obj);
if (filter->cvGray) { if (filter->cvGray)
cvReleaseImage (&filter->cvGray); cvReleaseImage (&filter->cvGray);
} if (filter->cvStorage)
if (filter->cvStorage) {
cvReleaseMemStorage (&filter->cvStorage); cvReleaseMemStorage (&filter->cvStorage);
}
g_free (filter->profile); g_free (filter->face_profile);
g_free (filter->nose_profile);
g_free (filter->mouth_profile);
g_free (filter->eyes_profile);
if (filter->cvFaceDetect)
cvReleaseHaarClassifierCascade (&filter->cvFaceDetect);
if (filter->cvNoseDetect)
cvReleaseHaarClassifierCascade (&filter->cvNoseDetect);
if (filter->cvMouthDetect)
cvReleaseHaarClassifierCascade (&filter->cvMouthDetect);
if (filter->cvEyesDetect)
cvReleaseHaarClassifierCascade (&filter->cvEyesDetect);
G_OBJECT_CLASS (parent_class)->finalize (obj); G_OBJECT_CLASS (parent_class)->finalize (obj);
} }
@ -215,10 +246,24 @@ gst_facedetect_class_init (GstFacedetectClass * klass)
g_param_spec_boolean ("display", "Display", g_param_spec_boolean ("display", "Display",
"Sets whether the detected faces should be highlighted in the output", "Sets whether the detected faces should be highlighted in the output",
TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_PROFILE,
g_param_spec_string ("profile", "Profile", 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", "Location of Haar cascade file to use for face detection",
DEFAULT_PROFILE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); DEFAULT_FACE_PROFILE, 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));
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));
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));
g_object_class_install_property (gobject_class, PROP_FLAGS, g_object_class_install_property (gobject_class, PROP_FLAGS,
g_param_spec_flags ("flags", "Flags", "Flags to cvHaarDetectObjects", g_param_spec_flags ("flags", "Flags", "Flags to cvHaarDetectObjects",
GST_TYPE_OPENCV_FACE_DETECT_FLAGS, DEFAULT_FLAGS, GST_TYPE_OPENCV_FACE_DETECT_FLAGS, DEFAULT_FLAGS,
@ -244,21 +289,29 @@ gst_facedetect_class_init (GstFacedetectClass * klass)
} }
/* initialize the new element /* initialize the new element
* instantiate pads and add them to element
* set pad calback functions
* initialize instance structure * initialize instance structure
*/ */
static void static void
gst_facedetect_init (GstFacedetect * filter, GstFacedetectClass * gclass) gst_facedetect_init (GstFacedetect * filter, GstFacedetectClass * gclass)
{ {
filter->profile = g_strdup (DEFAULT_PROFILE); filter->face_profile = g_strdup (DEFAULT_FACE_PROFILE);
filter->nose_profile = g_strdup (DEFAULT_NOSE_PROFILE);
filter->mouth_profile = g_strdup (DEFAULT_MOUTH_PROFILE);
filter->eyes_profile = g_strdup (DEFAULT_EYES_PROFILE);
filter->display = TRUE; filter->display = TRUE;
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;
filter->min_size_width = DEFAULT_MIN_SIZE_WIDTH; filter->min_size_width = DEFAULT_MIN_SIZE_WIDTH;
filter->min_size_height = DEFAULT_MIN_SIZE_HEIGHT; filter->min_size_height = DEFAULT_MIN_SIZE_HEIGHT;
gst_facedetect_load_profile (filter); filter->cvFaceDetect =
gst_facedetect_load_profile (filter, filter->face_profile);
filter->cvNoseDetect =
gst_facedetect_load_profile (filter, filter->nose_profile);
filter->cvMouthDetect =
gst_facedetect_load_profile (filter, filter->mouth_profile);
filter->cvEyesDetect =
gst_facedetect_load_profile (filter, filter->eyes_profile);
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);
@ -271,10 +324,37 @@ gst_facedetect_set_property (GObject * object, guint prop_id,
GstFacedetect *filter = GST_FACEDETECT (object); GstFacedetect *filter = GST_FACEDETECT (object);
switch (prop_id) { switch (prop_id) {
case PROP_PROFILE: case PROP_FACE_PROFILE:
g_free (filter->profile); g_free (filter->face_profile);
filter->profile = g_value_dup_string (value); if (filter->cvFaceDetect)
gst_facedetect_load_profile (filter); cvReleaseHaarClassifierCascade (&filter->cvFaceDetect);
filter->face_profile = g_value_dup_string (value);
filter->cvFaceDetect =
gst_facedetect_load_profile (filter, filter->face_profile);
break;
case PROP_NOSE_PROFILE:
g_free (filter->nose_profile);
if (filter->cvNoseDetect)
cvReleaseHaarClassifierCascade (&filter->cvNoseDetect);
filter->nose_profile = g_value_dup_string (value);
filter->cvNoseDetect =
gst_facedetect_load_profile (filter, filter->nose_profile);
break;
case PROP_MOUTH_PROFILE:
g_free (filter->mouth_profile);
if (filter->cvMouthDetect)
cvReleaseHaarClassifierCascade (&filter->cvMouthDetect);
filter->mouth_profile = g_value_dup_string (value);
filter->cvMouthDetect =
gst_facedetect_load_profile (filter, filter->mouth_profile);
break;
case PROP_EYES_PROFILE:
g_free (filter->eyes_profile);
if (filter->cvEyesDetect)
cvReleaseHaarClassifierCascade (&filter->cvEyesDetect);
filter->eyes_profile = g_value_dup_string (value);
filter->cvEyesDetect =
gst_facedetect_load_profile (filter, filter->eyes_profile);
break; break;
case PROP_DISPLAY: case PROP_DISPLAY:
filter->display = g_value_get_boolean (value); filter->display = g_value_get_boolean (value);
@ -307,8 +387,17 @@ gst_facedetect_get_property (GObject * object, guint prop_id,
GstFacedetect *filter = GST_FACEDETECT (object); GstFacedetect *filter = GST_FACEDETECT (object);
switch (prop_id) { switch (prop_id) {
case PROP_PROFILE: case PROP_FACE_PROFILE:
g_value_set_string (value, filter->profile); g_value_set_string (value, filter->face_profile);
break;
case PROP_NOSE_PROFILE:
g_value_set_string (value, filter->nose_profile);
break;
case PROP_MOUTH_PROFILE:
g_value_set_string (value, filter->mouth_profile);
break;
case PROP_EYES_PROFILE:
g_value_set_string (value, filter->eyes_profile);
break; break;
case PROP_DISPLAY: case PROP_DISPLAY:
g_value_set_boolean (value, filter->display); g_value_set_boolean (value, filter->display);
@ -391,17 +480,27 @@ gst_facedetect_transform_ip (GstOpencvVideoFilter * base, GstBuffer * buf,
{ {
GstFacedetect *filter = GST_FACEDETECT (base); GstFacedetect *filter = GST_FACEDETECT (base);
if (filter->cvCascade) { if (filter->cvFaceDetect) {
GstMessage *msg = NULL; GstMessage *msg = NULL;
GValue facelist = { 0 }; GValue facelist = { 0 };
CvSeq *faces; CvSeq *faces;
CvSeq *mouth, *nose, *eyes;
gint i; gint i;
gboolean do_display = FALSE;
if (filter->display) {
if (gst_buffer_is_writable (buf)) {
do_display = TRUE;
} else {
GST_LOG_OBJECT (filter, "Buffer is not writable, not drawing faces.");
}
}
cvCvtColor (img, filter->cvGray, CV_RGB2GRAY); cvCvtColor (img, filter->cvGray, CV_RGB2GRAY);
cvClearMemStorage (filter->cvStorage); cvClearMemStorage (filter->cvStorage);
faces = faces =
cvHaarDetectObjects (filter->cvGray, filter->cvCascade, cvHaarDetectObjects (filter->cvGray, filter->cvFaceDetect,
filter->cvStorage, filter->scale_factor, filter->min_neighbors, filter->cvStorage, filter->scale_factor, filter->min_neighbors,
filter->flags, cvSize (filter->min_size_width, filter->min_size_height) filter->flags, cvSize (filter->min_size_width, filter->min_size_height)
#if (CV_MAJOR_VERSION >= 2) && (CV_MINOR_VERSION >= 2) #if (CV_MAJOR_VERSION >= 2) && (CV_MINOR_VERSION >= 2)
@ -417,43 +516,167 @@ gst_facedetect_transform_ip (GstOpencvVideoFilter * base, GstBuffer * buf,
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);
GValue value = { 0 }; GValue value = { 0 };
GstStructure *s = gst_structure_new ("face", GstStructure *s;
guint mw = filter->min_size_width / 8;
guint mh = filter->min_size_height / 8;
guint rnx, rny, rnw, rnh;
guint rmx, rmy, rmw, rmh;
guint rex, rey, rew, reh;
gboolean have_nose, have_mouth, have_eyes;
/* detect face features */
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 =
cvHaarDetectObjects (filter->cvGray, filter->cvNoseDetect,
filter->cvStorage, filter->scale_factor, filter->min_neighbors,
filter->flags, cvSize (mw, mh)
#if (CV_MAJOR_VERSION >= 2) && (CV_MINOR_VERSION >= 2)
, cvSize (mw + 2, mh + 2)
#endif
);
have_nose = (nose && nose->total);
cvResetImageROI (filter->cvGray);
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 =
cvHaarDetectObjects (filter->cvGray, filter->cvMouthDetect,
filter->cvStorage, filter->scale_factor, filter->min_neighbors,
filter->flags, cvSize (mw, mh)
#if (CV_MAJOR_VERSION >= 2) && (CV_MINOR_VERSION >= 2)
, cvSize (mw + 2, mh + 2)
#endif
);
have_mouth = (mouth && mouth->total);
cvResetImageROI (filter->cvGray);
rex = r->x;
rey = r->y;
rew = r->width;
reh = r->height / 2;
cvSetImageROI (filter->cvGray, cvRect (rex, rey, rew, reh));
eyes =
cvHaarDetectObjects (filter->cvGray, filter->cvEyesDetect,
filter->cvStorage, filter->scale_factor, filter->min_neighbors,
filter->flags, cvSize (mw, mh)
#if (CV_MAJOR_VERSION >= 2) && (CV_MINOR_VERSION >= 2)
, cvSize (mw + 2, mh + 2)
#endif
);
have_eyes = (eyes && eyes->total);
cvResetImageROI (filter->cvGray);
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,
have_eyes, have_nose, have_mouth);
/* ignore 'face' where we don't fix mount/nose/eyes ? */
if (!(have_eyes && have_nose && have_mouth))
continue;
s = gst_structure_new ("face",
"x", G_TYPE_UINT, r->x, "x", G_TYPE_UINT, r->x,
"y", G_TYPE_UINT, r->y, "y", G_TYPE_UINT, r->y,
"width", G_TYPE_UINT, r->width, "width", G_TYPE_UINT, r->width,
"height", G_TYPE_UINT, r->height, NULL); "height", G_TYPE_UINT, r->height, NULL);
if (nose && nose->total) {
GST_LOG_OBJECT (filter, "%2d/%2d: x,y = %4u,%4u: w.h = %4u,%4u", i, CvRect *sr = (CvRect *) cvGetSeqElem (nose, 0);
faces->total, r->x, r->y, r->width, r->height); 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 (mouth && mouth->total) {
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 (eyes && eyes->total) {
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 (&value, GST_TYPE_STRUCTURE); g_value_init (&value, GST_TYPE_STRUCTURE);
gst_value_set_structure (&value, s); gst_value_set_structure (&value, s);
gst_value_list_append_value (&facelist, &value); gst_value_list_append_value (&facelist, &value);
g_value_unset (&value); g_value_unset (&value);
}
if (filter->display) {
if (gst_buffer_is_writable (buf)) {
/* draw colored circles for each face */
for (i = 0; i < (faces ? faces->total : 0); i++) {
CvRect *r = (CvRect *) cvGetSeqElem (faces, i);
CvPoint center;
CvSize axes;
gdouble w = r->width * 0.5;
gdouble h = r->height * 0.6; /* tweak for face form */
gint cb = 255 - ((i & 3) << 7);
gint cg = 255 - ((i & 12) << 5);
gint cr = 255 - ((i & 48) << 3);
center.x = cvRound ((r->x + w)); if (do_display) {
center.y = cvRound ((r->y + h)); CvPoint center;
CvSize 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));
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);
if (nose && nose->total) {
CvRect *sr = (CvRect *) cvGetSeqElem (nose, 0);
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.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);
}
if (mouth && mouth->total) {
CvRect *sr = (CvRect *) cvGetSeqElem (mouth, 0);
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; axes.height = h;
cvEllipse (img, center, axes, 0.0, 0.0, 360.0, CV_RGB (cr, cg, cb), cvEllipse (img, center, axes, 0.0, 0.0, 360.0, CV_RGB (cr, cg, cb),
3, 8, 0); 1, 8, 0);
}
if (eyes && eyes->total) {
CvRect *sr = (CvRect *) cvGetSeqElem (eyes, 0);
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);
} }
} else {
GST_LOG_OBJECT (filter, "Buffer is not writable, not drawing "
"circles for faces");
} }
} }
@ -468,14 +691,16 @@ gst_facedetect_transform_ip (GstOpencvVideoFilter * base, GstBuffer * buf,
} }
static void static CvHaarClassifierCascade *
gst_facedetect_load_profile (GstFacedetect * filter) gst_facedetect_load_profile (GstFacedetect * filter, gchar * profile)
{ {
filter->cvCascade = CvHaarClassifierCascade *cascade;
(CvHaarClassifierCascade *) cvLoad (filter->profile, 0, 0, 0);
if (!filter->cvCascade) { if (!(cascade = (CvHaarClassifierCascade *) cvLoad (profile, 0, 0, 0))) {
GST_WARNING ("Couldn't load Haar classifier cascade: %s.", filter->profile); GST_WARNING_OBJECT (filter, "Couldn't load Haar classifier cascade: %s.",
profile);
} }
return cascade;
} }

View File

@ -3,6 +3,7 @@
* Copyright (C) 2005 Thomas Vander Stichele <thomas@apestaart.org> * Copyright (C) 2005 Thomas Vander Stichele <thomas@apestaart.org>
* Copyright (C) 2005 Ronald S. Bultje <rbultje@ronald.bitfreak.net> * Copyright (C) 2005 Ronald S. Bultje <rbultje@ronald.bitfreak.net>
* Copyright (C) 2008 Michael Sheldon <mike@mikeasoft.com> * Copyright (C) 2008 Michael Sheldon <mike@mikeasoft.com>
* Copyright (C) 2011 Stefan Sauer <ensonic@users.sf.net>
* *
* Permission is hereby granted, free of charge, to any person obtaining a * Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"), * copy of this software and associated documentation files (the "Software"),
@ -75,7 +76,10 @@ struct _GstFacedetect
gboolean display; gboolean display;
gchar *profile; gchar *face_profile;
gchar *nose_profile;
gchar *mouth_profile;
gchar *eyes_profile;
gdouble scale_factor; gdouble scale_factor;
gint min_neighbors; gint min_neighbors;
gint flags; gint flags;
@ -83,7 +87,10 @@ struct _GstFacedetect
gint min_size_height; gint min_size_height;
IplImage *cvGray; IplImage *cvGray;
CvHaarClassifierCascade *cvCascade; CvHaarClassifierCascade *cvFaceDetect;
CvHaarClassifierCascade *cvNoseDetect;
CvHaarClassifierCascade *cvMouthDetect;
CvHaarClassifierCascade *cvEyesDetect;
CvMemStorage *cvStorage; CvMemStorage *cvStorage;
}; };