Skip to content

Commit

Permalink
Switched to an OpenCV deep neural network for detecting faces
Browse files Browse the repository at this point in the history
  • Loading branch information
PierreFritsch committed Jul 2, 2018
1 parent 9bcf63e commit 7410614
Show file tree
Hide file tree
Showing 8 changed files with 1,871 additions and 26,188 deletions.
11 changes: 1 addition & 10 deletions Heartbeat.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -179,14 +179,6 @@ int main(int argc, char * argv[]) {
downsample = DEFAULT_DOWNSAMPLE;
}

const string CLASSIFIER_PATH = "haarcascade_frontalface_alt.xml";

std::ifstream test(CLASSIFIER_PATH);
if (!test) {
std::cout << "Face classifier xml not found!" << std::endl;
exit(0);
}

bool offlineMode = input != "";

VideoCapture cap;
Expand Down Expand Up @@ -230,8 +222,7 @@ int main(int argc, char * argv[]) {
WIDTH, HEIGHT, TIME_BASE, downsample,
samplingFrequency, rescanFrequency,
minSignalSize, maxSignalSize,
LOG_PATH, CLASSIFIER_PATH,
log, gui);
LOG_PATH, log, gui);

// Load baseline if necessary
Baseline baseline = Baseline();
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ Compile the source code for your system, providing a number of required linker f
This works with opencv 3.4.1 on macOS:

```sh
$ g++ -std=c++11 -lopencv_core -lopencv_highgui -lopencv_imgcodecs -lopencv_imgproc -lopencv_objdetect -lopencv_video -lopencv_videoio -lavcodec Heartbeat.cpp opencv.cpp RPPG.cpp Baseline.cpp -o Heartbeat
$ g++ -std=c++11 -lopencv_core -lopencv_dnn -lopencv_highgui -lopencv_imgcodecs -lopencv_imgproc -lopencv_objdetect -lopencv_video -lopencv_videoio -lavcodec Heartbeat.cpp opencv.cpp RPPG.cpp Baseline.cpp -o Heartbeat
```

Alternative compilation for Ubuntu. Works with opencv 3.1:
Expand Down
44 changes: 33 additions & 11 deletions RPPG.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include "opencv.hpp"

using namespace cv;
using namespace dnn;
using namespace std;

#define LOW_BPM 42
Expand All @@ -31,8 +32,7 @@ bool RPPG::load(const rPPGAlgorithm algorithm,
const int width, const int height, const double timeBase, const int downsample,
const double samplingFrequency, const double rescanFrequency,
const int minSignalSize, const int maxSignalSize,
const string &logPath, const string &classifierPath,
const bool log, const bool gui) {
const string &logPath, const bool log, const bool gui) {

this->algorithm = algorithm;
this->guiMode = gui;
Expand All @@ -46,8 +46,8 @@ bool RPPG::load(const rPPGAlgorithm algorithm,
this->samplingFrequency = samplingFrequency;
this->timeBase = timeBase;

// Load classifiers
classifier.load(classifierPath);
// Load face detector
faceDetectNet = readNetFromCaffe("opencv/deploy.prototxt", "opencv/res10_300x300_ssd_iter_140000.caffemodel");

// Setting up logfilepath
ostringstream path_1;
Expand Down Expand Up @@ -86,14 +86,14 @@ void RPPG::processFrame(Mat &frameRGB, Mat &frameGray, int time) {
cout << "Not valid, finding a new face" << endl;

lastScanTime = time;
detectFace(frameGray);
detectFace(frameRGB, frameGray);

} else if ((time - lastScanTime) * timeBase >= 1/rescanFrequency) {

cout << "Valid, but rescanning face" << endl;

lastScanTime = time;
detectFace(frameGray);
detectFace(frameRGB, frameGray);
rescanFlag = true;

} else {
Expand Down Expand Up @@ -167,13 +167,35 @@ void RPPG::processFrame(Mat &frameRGB, Mat &frameGray, int time) {
frameGray.copyTo(lastFrameGray);
}

void RPPG::detectFace(Mat &frameGray) {
void RPPG::detectFace(Mat &frameRGB, Mat &frameGray) {

cout << "Scanning for faces…" << endl;

// Detect faces with Haar classifier
vector<Rect> boxes;
classifier.detectMultiScale(frameGray, boxes, 1.1, 2, CV_HAAR_SCALE_IMAGE, minFaceSize);
// Detect faces with DNN
Mat resize300;
cv::resize(frameRGB, resize300, Size(300, 300));
Mat blob = blobFromImage(resize300, 1.0, Size(300, 300), Scalar(104.0, 177.0, 123.0));
faceDetectNet.setInput(blob);
Mat detection = faceDetectNet.forward();
Mat detectionMat(detection.size[2], detection.size[3], CV_32F, detection.ptr<float>());
float confidenceThreshold = 0.5;
vector<Rect> boxes = {};

for (int i = 0; i < detectionMat.rows; i++) {
float confidence = detectionMat.at<float>(i, 2);

if (confidence > confidenceThreshold) {
int xLeftBottom = static_cast<int>(detectionMat.at<float>(i, 3) * frameRGB.cols);
int yLeftBottom = static_cast<int>(detectionMat.at<float>(i, 4) * frameRGB.rows);
int xRightTop = static_cast<int>(detectionMat.at<float>(i, 5) * frameRGB.cols);
int yRightTop = static_cast<int>(detectionMat.at<float>(i, 6) * frameRGB.rows);

Rect object((int)xLeftBottom, (int)yLeftBottom,
(int)(xRightTop - xLeftBottom),
(int)(yRightTop - yLeftBottom));
boxes.push_back(object);
}
}

if (boxes.size() > 0) {

Expand Down Expand Up @@ -625,4 +647,4 @@ void RPPG::draw(cv::Mat &frameRGB) {
line(frameRGB, Point(corners[i].x-5,corners[i].y), Point(corners[i].x+5,corners[i].y), GREEN, 1);
line(frameRGB, Point(corners[i].x,corners[i].y-5), Point(corners[i].x,corners[i].y+5), GREEN, 1);
}
}
}
11 changes: 6 additions & 5 deletions RPPG.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,12 @@
#include <fstream>
#include <string>
#include <opencv2/objdetect/objdetect.hpp>
#include <opencv2/dnn.hpp>

#include <stdio.h>

using namespace cv;
using namespace dnn;
using namespace std;

enum rPPGAlgorithm { g, pca, xminay };
Expand All @@ -32,8 +34,7 @@ class RPPG {
const int width, const int height, const double timeBase, const int downsample,
const double samplingFrequency, const double rescanFrequency,
const int minSignalSize, const int maxSignalSize,
const string &logPath, const string &classifierPath,
const bool log, const bool gui);
const string &logPath, const bool log, const bool gui);

void processFrame(Mat &frameRGB, Mat &frameGray, int time);

Expand All @@ -43,7 +44,7 @@ class RPPG {

private:

void detectFace(Mat &frameGray);
void detectFace(Mat &frameRGB, Mat &frameGray);
void setNearestBox(vector<Rect> boxes);
void detectCorners(Mat &frameGray);
void trackFace(Mat &frameGray);
Expand All @@ -60,8 +61,8 @@ class RPPG {
// The algorithm
rPPGAlgorithm algorithm;

// The classifiers
CascadeClassifier classifier;
// The face detector
Net faceDetectNet;

// Settings
Size minFaceSize;
Expand Down
Loading

0 comments on commit 7410614

Please sign in to comment.