summaryrefslogtreecommitdiff
path: root/mv_face/face/src/FaceEyeCondition.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'mv_face/face/src/FaceEyeCondition.cpp')
-rw-r--r--mv_face/face/src/FaceEyeCondition.cpp229
1 files changed, 229 insertions, 0 deletions
diff --git a/mv_face/face/src/FaceEyeCondition.cpp b/mv_face/face/src/FaceEyeCondition.cpp
new file mode 100644
index 00000000..9432d1e1
--- /dev/null
+++ b/mv_face/face/src/FaceEyeCondition.cpp
@@ -0,0 +1,229 @@
+/**
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "FaceEyeCondition.h"
+
+#include <mv_private.h>
+
+#include <vector>
+
+namespace MediaVision
+{
+namespace Face
+{
+
+void FaceEyeCondition::splitEyes(
+ const cv::Mat& grayImage,
+ mv_rectangle_s faceLocation,
+ cv::Mat& leftEye,
+ cv::Mat& rightEye)
+{
+ leftEye = grayImage.rowRange(0, grayImage.rows / 2 - grayImage.rows / 10)
+ .colRange(grayImage.cols / 2 + grayImage.cols / 10,
+ grayImage.cols)
+ .clone();
+
+ rightEye = grayImage.rowRange(grayImage.rows / 2 + grayImage.rows / 10,
+ grayImage.rows)
+ .colRange(grayImage.cols / 2 + grayImage.cols / 10,
+ grayImage.cols)
+ .clone();
+
+ const cv::Rect faceRect(
+ faceLocation.point.x,
+ faceLocation.point.y,
+ faceLocation.width,
+ faceLocation.height);
+
+ const cv::Rect eyeAreaRight(
+ faceRect.x + faceRect.width / 16,
+ (int) (faceRect.y + (faceRect.height / 4.5)),
+ (faceRect.width - 2 * faceRect.width / 16) / 2,
+ (int) (faceRect.height / 3.0));
+
+ const cv::Rect eyeAreaLeft(
+ faceRect.x + faceRect.width / 16
+ + (faceRect.width - 2 * faceRect.width / 16) / 2,
+ (int) (faceRect.y + (faceRect.height / 4.5)),
+ (faceRect.width - 2 * faceRect.width / 16) / 2,
+ (int) (faceRect.height / 3.0));
+
+ const double xLeftEyeCenter = (2 * eyeAreaLeft.x + eyeAreaLeft.width) / 2.;
+ const double yLeftEyeCenter = (2 * eyeAreaLeft.y + eyeAreaLeft.height) / 2.;
+
+ const double xRightEyeCenter = (2 * eyeAreaRight.x + eyeAreaRight.width) / 2.;
+ const double yRightEyeCenter = (2 * eyeAreaRight.y + eyeAreaRight.height) / 2.;
+
+ const cv::Rect leftEyeRect(xLeftEyeCenter - eyeAreaLeft.width / 4,
+ yLeftEyeCenter - eyeAreaLeft.height / 4,
+ eyeAreaLeft.width / 2,
+ eyeAreaLeft.height / 2);
+
+ const cv::Rect rightEyeRect(xRightEyeCenter - eyeAreaRight.width / 4,
+ yRightEyeCenter - eyeAreaRight.height / 4,
+ eyeAreaRight.width / 2,
+ eyeAreaRight.height / 2);
+
+ cv::resize(
+ grayImage(leftEyeRect),
+ leftEye,
+ leftEye.size());
+ cv::resize(
+ grayImage(rightEyeRect),
+ rightEye,
+ rightEye.size());
+}
+
+int FaceEyeCondition::isEyeOpen(const cv::Mat& eye)
+{
+ int isOpen = MV_FACE_EYES_CLOSED;
+
+ cv::Mat eyeEqualized;
+ cv::equalizeHist(eye, eyeEqualized);
+
+ const int thresold = 8;
+ eyeEqualized = eyeEqualized < thresold;
+
+ std::vector<std::vector<cv::Point> > contours;
+ std::vector<cv::Vec4i> hierarchy;
+
+ cv::findContours(
+ eyeEqualized,
+ contours,
+ hierarchy,
+ CV_RETR_CCOMP,
+ CV_CHAIN_APPROX_SIMPLE);
+
+ const size_t contoursSize = contours.size();
+
+ if (!contoursSize)
+ {
+ return MV_FACE_EYES_NOT_FOUND;
+ }
+
+ const int xCenter = eyeEqualized.cols / 2;
+ const int yCenter = eyeEqualized.rows / 2;
+ const int width = eyeEqualized.cols / 2.5;
+ const int height = eyeEqualized.rows / 2.5;
+
+ const cv::Rect boundThresold(xCenter - width, yCenter - height, 2 * width, 2 * height);
+
+ const int widthHeightRatio = 3;
+ const double areaRatio = 0.005;
+ const double areaSmallRatio = 0.0005;
+ size_t rectanglesInsideCount = 0u;
+
+ for (size_t i = 0; i < contoursSize; ++i)
+ {
+ const cv::Rect currentRect = cv::boundingRect(contours[i]);
+ const double currentArea = cv::contourArea(contours[i]);
+
+ if (boundThresold.contains(currentRect.br()) &&
+ boundThresold.contains(currentRect.tl()) &&
+ currentArea > areaRatio * boundThresold.area() &&
+ currentRect.width < widthHeightRatio * currentRect.height)
+ {
+ isOpen = MV_FACE_EYES_OPEN;
+ }
+ else if (boundThresold.contains(currentRect.br()) &&
+ boundThresold.contains(currentRect.tl()) &&
+ currentArea > areaSmallRatio * boundThresold.area())
+ {
+ ++rectanglesInsideCount;
+ }
+ }
+
+ if (rectanglesInsideCount > 8u)
+ {
+ isOpen = MV_FACE_EYES_CLOSED;
+ }
+
+ return isOpen;
+}
+
+int FaceEyeCondition::recognizeEyeCondition(
+ const cv::Mat& grayImage,
+ mv_rectangle_s faceLocation,
+ mv_face_eye_condition_e *eyeCondition)
+{
+ if (grayImage.empty())
+ {
+ *eyeCondition = MV_FACE_EYES_NOT_FOUND;
+
+ LOGE("Input image is empty. Eye condition recognition failed.");
+ return MEDIA_VISION_ERROR_NO_DATA;
+ }
+
+ if (faceLocation.height <= 0 || faceLocation.width <= 0 ||
+ faceLocation.point.x < 0 || faceLocation.point.y < 0 ||
+ (faceLocation.point.x + faceLocation.width) > grayImage.cols ||
+ (faceLocation.point.y + faceLocation.height) > grayImage.rows)
+ {
+ *eyeCondition = MV_FACE_EYES_NOT_FOUND;
+
+ LOGE("Input face location is wrong. Eye condition recognition failed.");
+ return MEDIA_VISION_ERROR_INVALID_PARAMETER;
+ }
+
+ if (NULL == eyeCondition)
+ {
+ *eyeCondition = MV_FACE_EYES_NOT_FOUND;
+
+ LOGE("Output eye condition is NULL. Eye condition recognition failed.");
+ return MEDIA_VISION_ERROR_INVALID_PARAMETER;
+ }
+
+ // split left and right eyes
+ cv::Mat leftEye;
+ cv::Mat rightEye;
+ splitEyes(grayImage, faceLocation, leftEye, rightEye);
+
+ // recognize eyes conditions
+ const int isOpenLeft = isEyeOpen(leftEye);
+
+ if (isOpenLeft == MV_FACE_EYES_CLOSED)
+ {
+ *eyeCondition = MV_FACE_EYES_CLOSED;
+
+ return MEDIA_VISION_ERROR_NONE;
+ }
+ else if (isOpenLeft == MV_FACE_EYES_NOT_FOUND)
+ {
+ *eyeCondition = MV_FACE_EYES_NOT_FOUND;
+
+ return MEDIA_VISION_ERROR_NONE;
+ }
+
+ const int isOpenRight = isEyeOpen(rightEye);
+
+ if (isOpenRight == MV_FACE_EYES_OPEN)
+ {
+ *eyeCondition = MV_FACE_EYES_OPEN;
+ }
+ else if (isOpenRight == MV_FACE_EYES_CLOSED)
+ {
+ *eyeCondition = MV_FACE_EYES_CLOSED;
+ }
+ else
+ {
+ *eyeCondition = MV_FACE_EYES_NOT_FOUND;
+ }
+
+ return MEDIA_VISION_ERROR_NONE;
+}
+
+} /* Face */
+} /* MediaVision */