From 8b5f8b9a3652ace08912607090da9de8cffc0cbb Mon Sep 17 00:00:00 2001 From: Tadas Baltrusaitis Date: Wed, 9 Aug 2017 11:00:38 -0400 Subject: [PATCH] Starting to work on MTCNN C++ implementation. --- .../include/FaceDetectorMTCNN.h | 142 ++++++++++ .../include/LandmarkDetectorModel.h | 2 + .../src/FaceDetectorMTCNN.cpp | 263 ++++++++++++++++++ .../mtcnn/convert_to_cpp/PNet.dat | Bin 0 -> 35088 bytes .../convert_to_cpp/Write_CNN_to_binary.m | 70 +++++ .../mtcnn/convert_to_cpp/Write_out_mtcnn.m | 42 +++ 6 files changed, 519 insertions(+) create mode 100644 lib/local/LandmarkDetector/include/FaceDetectorMTCNN.h create mode 100644 lib/local/LandmarkDetector/src/FaceDetectorMTCNN.cpp create mode 100644 matlab_version/face_detection/mtcnn/convert_to_cpp/PNet.dat create mode 100644 matlab_version/face_detection/mtcnn/convert_to_cpp/Write_CNN_to_binary.m create mode 100644 matlab_version/face_detection/mtcnn/convert_to_cpp/Write_out_mtcnn.m diff --git a/lib/local/LandmarkDetector/include/FaceDetectorMTCNN.h b/lib/local/LandmarkDetector/include/FaceDetectorMTCNN.h new file mode 100644 index 00000000..27e1ce40 --- /dev/null +++ b/lib/local/LandmarkDetector/include/FaceDetectorMTCNN.h @@ -0,0 +1,142 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2016, Carnegie Mellon University and University of Cambridge, +// all rights reserved. +// +// THIS SOFTWARE IS PROVIDED “AS IS” FOR ACADEMIC USE ONLY AND ANY EXPRESS +// OR IMPLIED WARRANTIES WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS +// BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY. +// OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// Notwithstanding the license granted herein, Licensee acknowledges that certain components +// of the Software may be covered by so-called “open source” software licenses (“Open Source +// Components”), which means any software licenses approved as open source licenses by the +// Open Source Initiative or any substantially similar licenses, including without limitation any +// license that, as a condition of distribution of the software licensed under such license, +// requires that the distributor make the software available in source code format. Licensor shall +// provide a list of Open Source Components for a particular version of the Software upon +// Licensee’s request. Licensee will comply with the applicable terms of such licenses and to +// the extent required by the licenses covering Open Source Components, the terms of such +// licenses will apply in lieu of the terms of this Agreement. To the extent the terms of the +// licenses applicable to Open Source Components prohibit any of the restrictions in this +// License Agreement with respect to such Open Source Component, such restrictions will not +// apply to such Open Source Component. To the extent the terms of the licenses applicable to +// Open Source Components require Licensor to make an offer to provide source code or +// related information in connection with the Software, such offer is hereby made. Any request +// for source code or related information should be directed to cl-face-tracker-distribution@lists.cam.ac.uk +// Licensee acknowledges receipt of notices for the Open Source Components for the initial +// delivery of the Software. + +// * Any publications arising from the use of this software, including but +// not limited to academic journal and conference publications, technical +// reports and manuals, must cite at least one of the following works: +// +// OpenFace: an open source facial behavior analysis toolkit +// Tadas Baltrušaitis, Peter Robinson, and Louis-Philippe Morency +// in IEEE Winter Conference on Applications of Computer Vision, 2016 +// +// Rendering of Eyes for Eye-Shape Registration and Gaze Estimation +// Erroll Wood, Tadas Baltrušaitis, Xucong Zhang, Yusuke Sugano, Peter Robinson, and Andreas Bulling +// in IEEE International. Conference on Computer Vision (ICCV), 2015 +// +// Cross-dataset learning and person-speci?c normalisation for automatic Action Unit detection +// Tadas Baltrušaitis, Marwa Mahmoud, and Peter Robinson +// in Facial Expression Recognition and Analysis Challenge, +// IEEE International Conference on Automatic Face and Gesture Recognition, 2015 +// +// Constrained Local Neural Fields for robust facial landmark detection in the wild. +// Tadas Baltrušaitis, Peter Robinson, and Louis-Philippe Morency. +// in IEEE Int. Conference on Computer Vision Workshops, 300 Faces in-the-Wild Challenge, 2013. +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef __FACE_DETECTOR_MTCNN_h_ +#define __FACE_DETECTOR_MTCNN_h_ + +// OpenCV includes +#include + +// System includes +#include + +using namespace std; + +namespace LandmarkDetector +{ + class CNN + { + public: + + //========================================== + + // Default constructor + CNN() { ; } + + // Copy constructor + CNN(const CNN& other); + + // Given an image, orientation and detected landmarks output the result of the appropriate regressor + cv::Mat_ Inference(const cv::Mat_& intensity_img); + + // Reading in the model + void Read(string location); + + private: + //========================================== + // Convolutional Neural Network + + // CNN layers + // layer -> input maps -> kernels + vector > > > cnn_convolutional_layers; + // Bit ugly with so much nesting, but oh well + vector > > > > cnn_convolutional_layers_dft; + vector > cnn_convolutional_layers_bias; + vector > cnn_fully_connected_layers_weights; + vector > cnn_fully_connected_layers_biases; + vector > cnn_prelu_layer_weights; + vector > cnn_max_pooling_layers; + + // CNN: 0 - convolutional, 1 - max pooling, 2 - fully connected, 3 - prelu, 4 - sigmoid + vector cnn_layer_types; + }; + //=========================================================================== + // + // Checking if landmark detection was successful using an SVR regressor + // Using multiple validators trained add different views + // The regressor outputs -1 for ideal alignment and 1 for worst alignment + //=========================================================================== + class FaceDetectorMTCNN + { + + public: + + // Default constructor + FaceDetectorMTCNN() { ; } + + // Copy constructor + FaceDetectorMTCNN(const FaceDetectorMTCNN& other); + + // Given an image, orientation and detected landmarks output the result of the appropriate regressor + bool DetectFaces(vector >& o_regions, const cv::Mat_& intensity, std::vector& o_confidences, int min_face = 30, double t1 = 0.6, double t2 = 0.7, double t3 = 0.7); + + // Reading in the model + void Read(string location); + + private: + //========================================== + // Components of the model + + CNN PNet; + CNN RNet; + CNN ONet; + + }; + +} +#endif diff --git a/lib/local/LandmarkDetector/include/LandmarkDetectorModel.h b/lib/local/LandmarkDetector/include/LandmarkDetectorModel.h index 52ba2426..0f83b52c 100644 --- a/lib/local/LandmarkDetector/include/LandmarkDetectorModel.h +++ b/lib/local/LandmarkDetector/include/LandmarkDetectorModel.h @@ -85,6 +85,8 @@ public: //==================== Helpers for face detection and landmark detection validation ========================================= + // TODO these should be static, and loading should be made easier + // Haar cascade classifier for face detection cv::CascadeClassifier face_detector_HAAR; string face_detector_location; diff --git a/lib/local/LandmarkDetector/src/FaceDetectorMTCNN.cpp b/lib/local/LandmarkDetector/src/FaceDetectorMTCNN.cpp new file mode 100644 index 00000000..bfe4fa3f --- /dev/null +++ b/lib/local/LandmarkDetector/src/FaceDetectorMTCNN.cpp @@ -0,0 +1,263 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2016, Carnegie Mellon University and University of Cambridge, +// all rights reserved. +// +// THIS SOFTWARE IS PROVIDED “AS IS” FOR ACADEMIC USE ONLY AND ANY EXPRESS +// OR IMPLIED WARRANTIES WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS +// BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY. +// OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// Notwithstanding the license granted herein, Licensee acknowledges that certain components +// of the Software may be covered by so-called “open source” software licenses (“Open Source +// Components”), which means any software licenses approved as open source licenses by the +// Open Source Initiative or any substantially similar licenses, including without limitation any +// license that, as a condition of distribution of the software licensed under such license, +// requires that the distributor make the software available in source code format. Licensor shall +// provide a list of Open Source Components for a particular version of the Software upon +// Licensee’s request. Licensee will comply with the applicable terms of such licenses and to +// the extent required by the licenses covering Open Source Components, the terms of such +// licenses will apply in lieu of the terms of this Agreement. To the extent the terms of the +// licenses applicable to Open Source Components prohibit any of the restrictions in this +// License Agreement with respect to such Open Source Component, such restrictions will not +// apply to such Open Source Component. To the extent the terms of the licenses applicable to +// Open Source Components require Licensor to make an offer to provide source code or +// related information in connection with the Software, such offer is hereby made. Any request +// for source code or related information should be directed to cl-face-tracker-distribution@lists.cam.ac.uk +// Licensee acknowledges receipt of notices for the Open Source Components for the initial +// delivery of the Software. + +// * Any publications arising from the use of this software, including but +// not limited to academic journal and conference publications, technical +// reports and manuals, must cite at least one of the following works: +// +// OpenFace: an open source facial behavior analysis toolkit +// Tadas Baltrušaitis, Peter Robinson, and Louis-Philippe Morency +// in IEEE Winter Conference on Applications of Computer Vision, 2016 +// +// Rendering of Eyes for Eye-Shape Registration and Gaze Estimation +// Erroll Wood, Tadas Baltrušaitis, Xucong Zhang, Yusuke Sugano, Peter Robinson, and Andreas Bulling +// in IEEE International. Conference on Computer Vision (ICCV), 2015 +// +// Cross-dataset learning and person-speci?c normalisation for automatic Action Unit detection +// Tadas Baltrušaitis, Marwa Mahmoud, and Peter Robinson +// in Facial Expression Recognition and Analysis Challenge, +// IEEE International Conference on Automatic Face and Gesture Recognition, 2015 +// +// Constrained Local Neural Fields for robust facial landmark detection in the wild. +// Tadas Baltrušaitis, Peter Robinson, and Louis-Philippe Morency. +// in IEEE Int. Conference on Computer Vision Workshops, 300 Faces in-the-Wild Challenge, 2013. +// +/////////////////////////////////////////////////////////////////////////////// + +#include "stdafx.h" + +#include "FaceDetectorMTCNN.h" + +// OpenCV includes +#include +#include + +// TBB includes +#include + +// System includes +#include + +// Math includes +#define _USE_MATH_DEFINES +#include + +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + +using namespace LandmarkDetector; + +// Copy constructor +FaceDetectorMTCNN::FaceDetectorMTCNN(const FaceDetectorMTCNN& other) : PNet(other.PNet), RNet(other.RNet), ONet(other.ONet) +{ +} + +void ReadMatBin(std::ifstream& stream, cv::Mat &output_mat) +{ + // Read in the number of rows, columns and the data type + int row, col, type; + + stream.read((char*)&row, 4); + stream.read((char*)&col, 4); + stream.read((char*)&type, 4); + + output_mat = cv::Mat(row, col, type); + int size = output_mat.rows * output_mat.cols * output_mat.elemSize(); + stream.read((char *)output_mat.data, size); + +} + +void CNN::Read(string location) +{ + ifstream cnn_stream(location, ios::in | ios::binary); + if (cnn_stream.is_open()) + { + cnn_stream.seekg(0, ios::beg); + + // Reading in CNNs + + int network_depth; + cnn_stream.read((char*)&network_depth, 4); + + cnn_layer_types.resize(network_depth); + + for (int layer = 0; layer < network_depth; ++layer) + { + + int layer_type; + cnn_stream.read((char*)&layer_type, 4); + cnn_layer_types[layer] = layer_type; + + // convolutional + if (layer_type == 0) + { + + // Read the number of input maps + int num_in_maps; + cnn_stream.read((char*)&num_in_maps, 4); + + // Read the number of kernels for each input map + int num_kernels; + cnn_stream.read((char*)&num_kernels, 4); + + vector > > kernels; + vector > > > kernel_dfts; + + kernels.resize(num_in_maps); + kernel_dfts.resize(num_in_maps); + + vector biases; + for (int k = 0; k < num_kernels; ++k) + { + float bias; + cnn_stream.read((char*)&bias, 4); + biases.push_back(bias); + } + + cnn_convolutional_layers_bias.push_back(biases); + + // For every input map + for (int in = 0; in < num_in_maps; ++in) + { + kernels[in].resize(num_kernels); + kernel_dfts[in].resize(num_kernels); + + // For every kernel on that input map + for (int k = 0; k < num_kernels; ++k) + { + ReadMatBin(cnn_stream, kernels[in][k]); + + } + } + + cnn_convolutional_layers.push_back(kernels); + cnn_convolutional_layers_dft.push_back(kernel_dfts); + } + else if (layer_type == 1) + { + int kernel_x, kernel_y, stride_x, stride_y; + cnn_stream.read((char*)&kernel_x, 4); + cnn_stream.read((char*)&kernel_y, 4); + cnn_stream.read((char*)&stride_x, 4); + cnn_stream.read((char*)&stride_y, 4); + cnn_max_pooling_layers.push_back(std::tuple(kernel_x, kernel_y, stride_x, stride_y)); + } + else if (layer_type == 2) + { + cv::Mat_ biases; + ReadMatBin(cnn_stream, biases); + cnn_fully_connected_layers_biases.push_back(biases); + + // Fully connected layer + cv::Mat_ weights; + ReadMatBin(cnn_stream, weights); + cnn_fully_connected_layers_weights.push_back(weights); + } + + else if (layer_type == 4) + { + cv::Mat_ weights; + ReadMatBin(cnn_stream, weights); + cnn_prelu_layer_weights.push_back(weights); + } + } + } + else + { + cout << "WARNING: Can't find the CNN location" << endl; + } +} + +//=========================================================================== +// Read in the MTCNN detector +void FaceDetectorMTCNN::Read(string location) +{ + + cout << "Reading the MTCNN face detector from: " << location << endl; + + ifstream locations(location.c_str(), ios_base::in); + if (!locations.is_open()) + { + cout << "Couldn't open the model file, aborting" << endl; + return; + } + string line; + + // The other module locations should be defined as relative paths from the main model + boost::filesystem::path root = boost::filesystem::path(location).parent_path(); + + // The main file contains the references to other files + while (!locations.eof()) + { + getline(locations, line); + + stringstream lineStream(line); + + string module; + string location; + + // figure out which module is to be read from which file + lineStream >> module; + + lineStream >> location; + + // remove carriage return at the end for compatibility with unix systems + if (location.size() > 0 && location.at(location.size() - 1) == '\r') + { + location = location.substr(0, location.size() - 1); + } + + // append to root + location = (root / location).string(); + if (module.compare("PNet") == 0) + { + cout << "Reading the PNet module from: " << location << endl; + PNet.Read(location); + } + else if(module.compare("RNet") == 0) + { + cout << "Reading the RNet module from: " << location << endl; + RNet.Read(location); + } + else if (module.compare("ONet") == 0) + { + cout << "Reading the ONet module from: " << location << endl; + ONet.Read(location); + } + } +} + + diff --git a/matlab_version/face_detection/mtcnn/convert_to_cpp/PNet.dat b/matlab_version/face_detection/mtcnn/convert_to_cpp/PNet.dat new file mode 100644 index 0000000000000000000000000000000000000000..9550d39a0b102d016bcaafef720f603b7107d719 GIT binary patch literal 35088 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