faceblur: need to migrate to C++.

The cascade classifier changes its structure on new version of OpenCV 2.4.11.
It is need to migrate to C++ to utilize the new load method of OpenCV which
allows to load the old and new classifiers.

https://bugzilla.gnome.org/show_bug.cgi?id=753994
This commit is contained in:
Vanessa Chipirrás Navalón 2015-08-26 17:56:50 +02:00 committed by Luis de Bethencourt
parent acdcfedde2
commit 02d8a4f4e8
2 changed files with 29 additions and 25 deletions

View file

@ -62,10 +62,12 @@
#endif #endif
#include <gst/gst.h> #include <gst/gst.h>
#include <vector>
#include "gstopencvutils.h" #include "gstopencvutils.h"
#include "gstfaceblur.h" #include "gstfaceblur.h"
#include <opencv2/imgproc/imgproc_c.h> #include <opencv2/imgproc/imgproc_c.h>
#include <opencv2/imgproc/imgproc.hpp>
GST_DEBUG_CATEGORY_STATIC (gst_face_blur_debug); GST_DEBUG_CATEGORY_STATIC (gst_face_blur_debug);
#define GST_CAT_DEFAULT gst_face_blur_debug #define GST_CAT_DEFAULT gst_face_blur_debug
@ -79,6 +81,7 @@ GST_DEBUG_CATEGORY_STATIC (gst_face_blur_debug);
#define DEFAULT_MIN_SIZE_WIDTH 30 #define DEFAULT_MIN_SIZE_WIDTH 30
#define DEFAULT_MIN_SIZE_HEIGHT 30 #define DEFAULT_MIN_SIZE_HEIGHT 30
using namespace cv;
enum enum
{ {
PROP_0, PROP_0,
@ -153,7 +156,7 @@ static gboolean gst_face_blur_set_caps (GstOpencvVideoFilter * transform,
static GstFlowReturn gst_face_blur_transform_ip (GstOpencvVideoFilter * static GstFlowReturn gst_face_blur_transform_ip (GstOpencvVideoFilter *
transform, GstBuffer * buffer, IplImage * img); transform, GstBuffer * buffer, IplImage * img);
static CvHaarClassifierCascade *gst_face_blur_load_profile (GstFaceBlur * static CascadeClassifier *gst_face_blur_load_profile (GstFaceBlur *
filter, gchar * profile); filter, gchar * profile);
/* Clean up */ /* Clean up */
@ -169,7 +172,7 @@ gst_face_blur_finalize (GObject * obj)
cvReleaseMemStorage (&filter->cvStorage); cvReleaseMemStorage (&filter->cvStorage);
if (filter->cvCascade) if (filter->cvCascade)
cvReleaseHaarClassifierCascade (&filter->cvCascade); delete filter->cvCascade;
g_free (filter->profile); g_free (filter->profile);
@ -266,7 +269,7 @@ gst_face_blur_set_property (GObject * object, guint prop_id,
case PROP_PROFILE: case PROP_PROFILE:
g_free (filter->profile); g_free (filter->profile);
if (filter->cvCascade) if (filter->cvCascade)
cvReleaseHaarClassifierCascade (&filter->cvCascade); delete filter->cvCascade;
filter->profile = g_value_dup_string (value); filter->profile = g_value_dup_string (value);
filter->cvCascade = gst_face_blur_load_profile (filter, filter->profile); filter->cvCascade = gst_face_blur_load_profile (filter, filter->profile);
filter->sent_profile_load_failed_msg = FALSE; filter->sent_profile_load_failed_msg = FALSE;
@ -348,8 +351,8 @@ gst_face_blur_transform_ip (GstOpencvVideoFilter * transform,
GstBuffer * buffer, IplImage * img) GstBuffer * buffer, IplImage * img)
{ {
GstFaceBlur *filter = GST_FACE_BLUR (transform); GstFaceBlur *filter = GST_FACE_BLUR (transform);
CvSeq *faces; vector < Rect > faces;
int i; unsigned int i;
if (!filter->cvCascade) { if (!filter->cvCascade) {
if (filter->profile != NULL if (filter->profile != NULL
@ -359,41 +362,42 @@ gst_face_blur_transform_ip (GstOpencvVideoFilter * transform,
("missing faceblur profile file %s", filter->profile)); ("missing faceblur profile file %s", filter->profile));
filter->sent_profile_load_failed_msg = TRUE; filter->sent_profile_load_failed_msg = TRUE;
} }
return GST_FLOW_OK; return GST_FLOW_OK;
} }
cvCvtColor (img, filter->cvGray, CV_RGB2GRAY); cvCvtColor (img, filter->cvGray, CV_RGB2GRAY);
cvClearMemStorage (filter->cvStorage); cvClearMemStorage (filter->cvStorage);
faces = Mat image (filter->cvGray, Rect (filter->cvGray->origin,
cvHaarDetectObjects (filter->cvGray, filter->cvCascade, filter->cvGray->origin, filter->cvGray->width,
filter->cvStorage, filter->scale_factor, filter->min_neighbors, filter->cvGray->height));
filter->flags, cvSize (filter->min_size_width, filter->min_size_height), filter->cvCascade->detectMultiScale (image, faces, filter->scale_factor,
cvSize (filter->min_size_width + 2, filter->min_size_height + 2)); filter->min_neighbors, filter->flags,
cvSize (filter->min_size_width, filter->min_size_height), cvSize (0, 0));
for (i = 0; i < (faces ? faces->total : 0); i++) { if (!faces.empty ()) {
CvRect *r = (CvRect *) cvGetSeqElem (faces, i);
cvSetImageROI (img, *r); for (i = 0; i < faces.size (); ++i) {
cvSmooth (img, img, CV_BLUR, 11, 11, 0, 0); Rect *r = &faces[i];
cvSmooth (img, img, CV_GAUSSIAN, 11, 11, 0, 0); Mat roi (img, Rect (r->x, r->y, r->width, r->height));
cvResetImageROI (img); blur (roi, roi, Size (11, 11));
GaussianBlur (roi, roi, Size (11, 11), 0, 0);
}
} }
return GST_FLOW_OK; return GST_FLOW_OK;
} }
static CascadeClassifier *
static CvHaarClassifierCascade *
gst_face_blur_load_profile (GstFaceBlur * filter, gchar * profile) gst_face_blur_load_profile (GstFaceBlur * filter, gchar * profile)
{ {
CvHaarClassifierCascade *cascade; CascadeClassifier *cascade;
if (profile == NULL) cascade = new CascadeClassifier (profile);
if (cascade->empty ()) {
GST_ERROR_OBJECT (filter, "Invalid profile file: %s", profile);
delete cascade;
return NULL; return NULL;
if (!(cascade = (CvHaarClassifierCascade *) cvLoad (profile, 0, 0, 0))) {
GST_WARNING_OBJECT (filter, "Couldn't load Haar classifier cascade: %s.",
profile);
} }
return cascade; return cascade;
} }

View file

@ -83,7 +83,7 @@ struct _GstFaceBlur
gint min_size_height; gint min_size_height;
IplImage *cvGray; IplImage *cvGray;
CvHaarClassifierCascade *cvCascade; cv::CascadeClassifier *cvCascade;
CvMemStorage *cvStorage; CvMemStorage *cvStorage;
}; };