#include #include #include cv::Ptr facemark; cv::CascadeClassifier faceDetector; cv::VideoCapture vid; cv::Mat frame, gray, small; void initCV() { //TODO: switch to DNN face detection faceDetector = cv::CascadeClassifier ("cvdata/haarcascade_frontalface_alt2.xml"); facemark = cv::face::FacemarkLBF::create(); facemark->loadModel ("cvdata/lbfmodel.yaml"); vid = cv::VideoCapture (0); } //process image and send controls to graphics void cvFrame() { vid.read(frame); cv::cvtColor (frame, gray, cv::COLOR_BGR2GRAY); //downsample image for face detection, works too slow on full res cv::pyrDown (gray, small); cv::pyrDown (small, small); std::vector faces; faceDetector.detectMultiScale(small, faces); //get biggest face int biggestFace = 0; int biggestArea = 0; for (int i = 0; i < faces.size(); i++) { //convert face region to full res, because we perform facemark on full res faces[i] = cv::Rect (faces[i].x * 4, faces[i].y * 4, faces[i].width * 4, faces[i].height * 4); int iArea = faces[i].area(); if (iArea > biggestArea) { biggestFace = i; biggestArea = iArea; } cv::rectangle (frame, faces[i], cv::Scalar (255, 255, 0)); } std::vector> landmarks; if (facemark->fit (frame, faces, landmarks)) { //for (int i = 0; i < landmarks[biggestFace].size(); i++) { // cv::circle (frame, landmarks[biggestFace][i], 2, cv::Scalar (255, 255, 255)); //} cv::circle(frame, cv::Point2f( (landmarks[biggestFace][2].x + landmarks[biggestFace][14].x) / 2, (landmarks[biggestFace][2].y + landmarks[biggestFace][14].y) / 2 ), 6, cv::Scalar(0, 0, 255)); cv::circle (frame, landmarks[biggestFace][30], 6, cv::Scalar (0, 255, 255)); cv::circle (frame, landmarks[biggestFace][66], 3, cv::Scalar (0, 255, 0)); cv::circle (frame, landmarks[biggestFace][62], 3, cv::Scalar (0, 255, 0)); //send control information to graphics float faceSize = landmarks[biggestFace][14].x - landmarks[biggestFace][2].x; updateModel( //head position glm::vec2( (landmarks[biggestFace][2].x + landmarks[biggestFace][14].x) / 2 * 2 / (float)frame.cols - 1, (landmarks[biggestFace][2].y + landmarks[biggestFace][14].y) / 2 * 2 / (float)frame.rows - 1 ), //face position glm::vec2( landmarks[biggestFace][30].x * 2 / (float)frame.cols - 1, landmarks[biggestFace][30].y * 2 / (float)frame.rows - 1 ), //rotation atanf((float)(landmarks[biggestFace][14].y - landmarks[biggestFace][2].y) / (float)(landmarks[biggestFace][2].x - landmarks[biggestFace][14].x)), //scale faceSize * 6 / (float)frame.cols, //mouth open/closed state (landmarks[biggestFace][66].y - landmarks[biggestFace][62].y) / faceSize > 0.04f); } } void cvShowFrame() { cv::imshow("Video Input", frame); cv::waitKey(32); }