summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorReynaldo H. Verdejo Pinochet <reynaldo@osg.samsung.com>2017-11-15 10:30:46 -0800
committerReynaldo H. Verdejo Pinochet <reynaldo@osg.samsung.com>2017-12-21 16:32:22 -0800
commit5e8bd0fa3f741aac9923872546b0bf4e25cc6ddf (patch)
treef31f1499636750444c6d479d2d50d3a36efd5402
parent191c8742d3cfde62ef837760fb5ca6d4bc226f1e (diff)
opencv: facedetect: DO NOT UPSTREAM: Rebased mods to facedetect
-rw-r--r--ext/opencv/gstfacedetect.cpp188
-rw-r--r--ext/opencv/gstfacedetect.h4
2 files changed, 169 insertions, 23 deletions
diff --git a/ext/opencv/gstfacedetect.cpp b/ext/opencv/gstfacedetect.cpp
index 503b9e70f..05227faa2 100644
--- a/ext/opencv/gstfacedetect.cpp
+++ b/ext/opencv/gstfacedetect.cpp
@@ -91,10 +91,12 @@ GST_DEBUG_CATEGORY_STATIC (gst_face_detect_debug);
#define HAAR_CASCADES_DIR OPENCV_PREFIX G_DIR_SEPARATOR_S "share" \
G_DIR_SEPARATOR_S OPENCV_PATH_NAME G_DIR_SEPARATOR_S "haarcascades" \
G_DIR_SEPARATOR_S
-#define DEFAULT_FACE_PROFILE HAAR_CASCADES_DIR "haarcascade_frontalface_default.xml"
-#define DEFAULT_NOSE_PROFILE HAAR_CASCADES_DIR "haarcascade_mcs_nose.xml"
-#define DEFAULT_MOUTH_PROFILE HAAR_CASCADES_DIR "haarcascade_mcs_mouth.xml"
-#define DEFAULT_EYES_PROFILE HAAR_CASCADES_DIR "haarcascade_mcs_eyepair_small.xml"
+#define DEFAULT_FACE_PROFILE "haarcascade_frontalface_default.xml"
+#define DEFAULT_NOSE_PROFILE "haarcascade_mcs_nose.xml"
+#define DEFAULT_MOUTH_PROFILE "haarcascade_mcs_mouth.xml"
+#define DEFAULT_EYES_PROFILE "haarcascade_mcs_eyepair_small.xml"
+#define DEFAULT_EAR_L_PROFILE "haarcascade_mcs_leftear.xml"
+#define DEFAULT_EAR_R_PROFILE "haarcascade_mcs_rightear.xml"
#define DEFAULT_SCALE_FACTOR 1.25
#define DEFAULT_FLAGS CV_HAAR_DO_CANNY_PRUNING
#define DEFAULT_MIN_NEIGHBORS 3
@@ -127,6 +129,12 @@ enum
PROP_MIN_STDDEV
};
+enum
+{
+ DIRECTION_INCONCLUSIVE = 0,
+ DIRECTION_RIGHT,
+ DIRECTION_LEFT
+};
/*
* GstOpencvFaceDetectFlags:
@@ -252,6 +260,8 @@ gst_face_detect_finalize (GObject * obj)
g_free (filter->nose_profile);
g_free (filter->mouth_profile);
g_free (filter->eyes_profile);
+ g_free (filter->ear_l_profile);
+ g_free (filter->ear_r_profile);
if (filter->cvFaceDetect)
delete (filter->cvFaceDetect);
@@ -261,6 +271,10 @@ gst_face_detect_finalize (GObject * obj)
delete (filter->cvMouthDetect);
if (filter->cvEyesDetect)
delete (filter->cvEyesDetect);
+ if (filter->cvEarLDetect)
+ delete (filter->cvEarLDetect);
+ if (filter->cvEarRDetect)
+ delete (filter->cvEarRDetect);
G_OBJECT_CLASS (gst_face_detect_parent_class)->finalize (obj);
}
@@ -291,22 +305,22 @@ gst_face_detect_class_init (GstFaceDetectClass * klass)
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,
+ HAAR_CASCADES_DIR 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,
+ HAAR_CASCADES_DIR 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,
+ HAAR_CASCADES_DIR 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,
+ HAAR_CASCADES_DIR DEFAULT_EYES_PROFILE,
(GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
g_object_class_install_property (gobject_class, PROP_FLAGS,
@@ -363,10 +377,17 @@ gst_face_detect_class_init (GstFaceDetectClass * klass)
static void
gst_face_detect_init (GstFaceDetect * filter)
{
- 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);
+
+ const gchar *haar_path;
+ haar_path = g_getenv ("GST_HAAR_CASCADES_PATH")?
+ g_getenv ("GST_HAAR_CASCADES_PATH") : HAAR_CASCADES_DIR;
+
+ filter->face_profile = g_strconcat (haar_path, DEFAULT_FACE_PROFILE, NULL);
+ filter->nose_profile = g_strconcat (haar_path, DEFAULT_NOSE_PROFILE, NULL);
+ filter->mouth_profile = g_strconcat (haar_path, DEFAULT_MOUTH_PROFILE, NULL);
+ filter->eyes_profile = g_strconcat (haar_path, DEFAULT_EYES_PROFILE, NULL);
+ filter->ear_r_profile = g_strconcat (haar_path, DEFAULT_EAR_R_PROFILE, NULL);
+ filter->ear_l_profile = g_strconcat (haar_path, DEFAULT_EAR_L_PROFILE, NULL);
filter->display = TRUE;
filter->face_detected = FALSE;
filter->scale_factor = DEFAULT_SCALE_FACTOR;
@@ -383,6 +404,10 @@ gst_face_detect_init (GstFaceDetect * filter)
gst_face_detect_load_profile (filter, filter->mouth_profile);
filter->cvEyesDetect =
gst_face_detect_load_profile (filter, filter->eyes_profile);
+ filter->cvEarLDetect =
+ gst_face_detect_load_profile (filter, filter->ear_l_profile);
+ filter->cvEarRDetect =
+ gst_face_detect_load_profile (filter, filter->ear_r_profile);
gst_opencv_video_filter_set_in_place (GST_OPENCV_VIDEO_FILTER_CAST (filter),
TRUE);
@@ -572,6 +597,37 @@ gst_face_detect_run_detector (GstFaceDetect * filter,
}
}
+/**
+ * Delta percentaje after wich position is considered off-center
+ */
+#define LINEAR_DAMPING_FACTOR 5
+
+/**
+ * @gst_face_detect_get_leaning_side
+ *
+ * Figures out what side of a reference a certain cuantity falls into
+ * @pos: Object x coordinate
+ * @ref_pos: Reference x coordinate
+ * @side: result. DIRECTION_RIGHT or DIRECTION_LEFT. Untouched if inconclusive
+ * @displacement: Magnitude of min to max ramp
+ */
+static inline void
+gst_face_detect_get_leaning_side (guint *side, gint reference, gint position,
+ guint displacement) {
+
+ g_assert (side);
+
+ displacement = displacement * LINEAR_DAMPING_FACTOR / 100;
+
+ if ((guint)ABS (position - reference) <= displacement)
+ return;
+
+ if (position > reference)
+ *side = DIRECTION_LEFT;
+ else if (position < reference)
+ *side = DIRECTION_RIGHT;
+}
+
/*
* Performs the face detection
*/
@@ -590,6 +646,8 @@ gst_face_detect_transform_ip (GstOpencvVideoFilter * base, GstBuffer * buf,
vector < Rect > mouth;
vector < Rect > nose;
vector < Rect > eyes;
+ vector < Rect > r_ears;
+ vector < Rect > l_ears;
gboolean post_msg = FALSE;
Mat mtxOrg (cv::cvarrToMat (img));
@@ -644,8 +702,10 @@ gst_face_detect_transform_ip (GstOpencvVideoFilter * base, GstBuffer * buf,
guint rnx = 0, rny = 0, rnw, rnh;
guint rmx = 0, rmy = 0, rmw, rmh;
guint rex = 0, rey = 0, rew, reh;
+ guint relx = 0, rely = 0, relw, relh;
+ guint rerx = 0, rery = 0, rerw, rerh;
guint rhh = r.height / 2;
- gboolean have_nose, have_mouth, have_eyes;
+ gboolean have_nose, have_mouth, have_eyes, have_l_ears, have_r_ears;
/* detect face features */
@@ -685,11 +745,35 @@ gst_face_detect_transform_ip (GstOpencvVideoFilter * base, GstBuffer * buf,
have_eyes = FALSE;
}
+ if (filter->cvEarLDetect) {
+ relx = r.x;
+ rely = r.y;
+ relw = r.width;
+ relh = rhh;
+ gst_face_detect_run_detector (filter, filter->cvEarLDetect, mw, mh,
+ Rect (relx, rely, relw, relh), l_ears);
+ have_l_ears = !l_ears.empty ();
+ } else {
+ have_l_ears = FALSE;
+ }
+
+ if (filter->cvEarRDetect) {
+ rerx = r.x;
+ rery = r.y;
+ rerw = r.width;
+ rerh = rhh;
+ gst_face_detect_run_detector (filter, filter->cvEarRDetect, mw, mh,
+ Rect (rerx, rery, rerw, rerh), r_ears);
+ have_r_ears = !r_ears.empty ();
+ } else {
+ have_r_ears = FALSE;
+ }
+
GST_LOG_OBJECT (filter,
"%2d/%2" G_GSIZE_FORMAT
- ": 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);
+ ": x,y = %4u,%4u: w.h = %4u,%4u : features(e,n,m) = %d,%d,%d,%d,%d",
+ i, faces.size (), r.x, r.y, r.width, r.height, have_eyes, have_nose,
+ have_mouth, have_r_ears, have_l_ears);
if (post_msg) {
s = gst_structure_new ("face",
"x", G_TYPE_UINT, r.x,
@@ -702,6 +786,10 @@ gst_face_detect_transform_ip (GstOpencvVideoFilter * base, GstBuffer * buf,
structure_and_message (mouth, "mouth", rmx, rmy, filter, s);
if (have_eyes)
structure_and_message (eyes, "eyes", rex, rey, filter, s);
+ if (have_l_ears)
+ structure_and_message (l_ears, "left ears", relx, rely, filter, s);
+ if (have_r_ears)
+ structure_and_message (r_ears, "right ears", rerx, rery, filter, s);
g_value_init (&facedata, GST_TYPE_STRUCTURE);
g_value_take_boxed (&facedata, s);
@@ -711,20 +799,21 @@ gst_face_detect_transform_ip (GstOpencvVideoFilter * base, GstBuffer * buf,
}
if (filter->display) {
- CvPoint center;
- Size axes;
+ CvPoint f_center, center;
+ Size f_axes, axes;
gdouble w, h;
+ guint aim = DIRECTION_INCONCLUSIVE;
+
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 */
- ellipse (mtxOrg, center, axes, 0, 0, 360, Scalar (cr, cg, cb), 3, 8, 0);
+ f_center.x = cvRound ((r.x + w));
+ f_center.y = cvRound ((r.y + h));
+ f_axes.width = w;
+ f_axes.height = h * 1.25; /* tweak for face form */
if (have_nose) {
Rect sr = nose[0];
@@ -733,11 +822,17 @@ gst_face_detect_transform_ip (GstOpencvVideoFilter * base, GstBuffer * buf,
h = sr.height / 2;
center.x = cvRound ((rnx + sr.x + w));
center.y = cvRound ((rny + sr.y + h));
+
+ /* left/right toggle */
+ gst_face_detect_get_leaning_side (&aim, f_center.x, center.x,
+ r.width);
+
axes.width = w;
axes.height = h * 1.25; /* tweak for nose form */
ellipse (mtxOrg, center, axes, 0, 0, 360, Scalar (cr, cg, cb), 1, 8,
0);
}
+
if (have_mouth) {
Rect sr = mouth[0];
@@ -745,11 +840,34 @@ gst_face_detect_transform_ip (GstOpencvVideoFilter * base, GstBuffer * buf,
h = sr.height / 2;
center.x = cvRound ((rmx + sr.x + w));
center.y = cvRound ((rmy + sr.y + h));
+
+ if (!aim) {
+ gst_face_detect_get_leaning_side (&aim, f_center.x, center.x,
+ r.width);
+ }
+
axes.width = w * 1.5; /* tweak for mouth form */
axes.height = h;
ellipse (mtxOrg, center, axes, 0, 0, 360, Scalar (cr, cg, cb), 1, 8,
0);
}
+
+ /* Face ellipse */
+ switch (aim) {
+ case DIRECTION_RIGHT:
+ ellipse (mtxOrg, f_center, f_axes, 0, 0, 360, Scalar (cr, 0, 0),
+ 3, 8, 0);
+ break;
+ case DIRECTION_LEFT:
+ ellipse (mtxOrg, f_center, f_axes, 0, 0, 360, Scalar (0, 0, cb),
+ 3, 8, 0);
+ break;
+ case DIRECTION_INCONCLUSIVE:
+ default:
+ ellipse (mtxOrg, f_center, f_axes, 0, 0, 360, Scalar (cr, cg, cb),
+ 3, 8, 0);
+ }
+
if (have_eyes) {
Rect sr = eyes[0];
@@ -762,6 +880,30 @@ gst_face_detect_transform_ip (GstOpencvVideoFilter * base, GstBuffer * buf,
ellipse (mtxOrg, center, axes, 0, 0, 360, Scalar (cr, cg, cb), 1, 8,
0);
}
+ if (have_r_ears) {
+ Rect sr = r_ears[0];
+
+ w = sr.width / 2;
+ h = sr.height / 2;
+ center.x = cvRound ((rerx + sr.x + w));
+ center.y = cvRound ((rery + sr.y + h));
+ axes.width = w * 1.25; /* tweak for ears form */
+ axes.height = h;
+ ellipse (mtxOrg, center, axes, 0, 0, 360, Scalar (cr, cg, cb), 1, 8,
+ 0);
+ }
+ if (have_l_ears) {
+ Rect sr = l_ears[0];
+
+ w = sr.width / 2;
+ h = sr.height / 2;
+ center.x = cvRound ((relx + sr.x + w));
+ center.y = cvRound ((rely + sr.y + h));
+ axes.width = w * 1.25; /* tweak for ears form */
+ axes.height = h;
+ 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);
diff --git a/ext/opencv/gstfacedetect.h b/ext/opencv/gstfacedetect.h
index 03cf81c2e..81477d8fc 100644
--- a/ext/opencv/gstfacedetect.h
+++ b/ext/opencv/gstfacedetect.h
@@ -96,6 +96,8 @@ struct _GstFaceDetect
gchar *nose_profile;
gchar *mouth_profile;
gchar *eyes_profile;
+ gchar *ear_l_profile;
+ gchar *ear_r_profile;
gdouble scale_factor;
gint min_neighbors;
gint flags;
@@ -109,6 +111,8 @@ struct _GstFaceDetect
cv::CascadeClassifier *cvNoseDetect;
cv::CascadeClassifier *cvMouthDetect;
cv::CascadeClassifier *cvEyesDetect;
+ cv::CascadeClassifier *cvEarLDetect;
+ cv::CascadeClassifier *cvEarRDetect;
};
struct _GstFaceDetectClass