├── .gitignore ├── test_data ├── test.out ├── test.jpg └── boxes.out ├── nms.hpp ├── mtcnn ├── test1.jpg ├── test2.jpg ├── model │ ├── det1.png │ ├── det2.png │ ├── det3.png │ ├── det1.caffemodel │ ├── det2.caffemodel │ ├── det3.caffemodel │ ├── det1.prototxt │ ├── det2.prototxt │ └── det3.prototxt ├── imglist_win.txt ├── imglist.txt ├── file - 副本.txt └── file.txt ├── nms.h ├── eigenplus.h ├── readme.md ├── License.txt ├── headlayer.h ├── caffeplus.h ├── main.cpp ├── nms.cpp ├── mtcnn.h ├── eigenplus.cpp ├── mtcnn.pro ├── caffeplus.cpp ├── test_utility.cpp ├── mtcnn.pro.user ├── utility.hpp ├── test_nms.cpp └── mtcnn.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | mtcnn/positive 2 | *.png 3 | *.user -------------------------------------------------------------------------------- /test_data/test.out: -------------------------------------------------------------------------------- 1 | 1.0000e+00 2.0000e+00 3.0000e+00 2 | -------------------------------------------------------------------------------- /nms.hpp: -------------------------------------------------------------------------------- 1 | #ifndef NMS_HPP 2 | #define NMS_HPP 3 | 4 | #endif // NMS_HPP 5 | -------------------------------------------------------------------------------- /mtcnn/test1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DuinoDu/mtcnn_cpp/HEAD/mtcnn/test1.jpg -------------------------------------------------------------------------------- /mtcnn/test2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DuinoDu/mtcnn_cpp/HEAD/mtcnn/test2.jpg -------------------------------------------------------------------------------- /mtcnn/model/det1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DuinoDu/mtcnn_cpp/HEAD/mtcnn/model/det1.png -------------------------------------------------------------------------------- /mtcnn/model/det2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DuinoDu/mtcnn_cpp/HEAD/mtcnn/model/det2.png -------------------------------------------------------------------------------- /mtcnn/model/det3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DuinoDu/mtcnn_cpp/HEAD/mtcnn/model/det3.png -------------------------------------------------------------------------------- /test_data/test.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DuinoDu/mtcnn_cpp/HEAD/test_data/test.jpg -------------------------------------------------------------------------------- /mtcnn/imglist_win.txt: -------------------------------------------------------------------------------- 1 | H:/project/qt/mtcnn_cpp/mtcnn/test1.jpg 2 | H:/project/qt/mtcnn_cpp/mtcnn/test2.jpg -------------------------------------------------------------------------------- /mtcnn/model/det1.caffemodel: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DuinoDu/mtcnn_cpp/HEAD/mtcnn/model/det1.caffemodel -------------------------------------------------------------------------------- /mtcnn/model/det2.caffemodel: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DuinoDu/mtcnn_cpp/HEAD/mtcnn/model/det2.caffemodel -------------------------------------------------------------------------------- /mtcnn/model/det3.caffemodel: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DuinoDu/mtcnn_cpp/HEAD/mtcnn/model/det3.caffemodel -------------------------------------------------------------------------------- /mtcnn/imglist.txt: -------------------------------------------------------------------------------- 1 | /home/duino/project/iactive/mtcnn/mtcnn/test1.jpg 2 | /home/duino/project/iactive/mtcnn/mtcnn/test2.jpg 3 | -------------------------------------------------------------------------------- /nms.h: -------------------------------------------------------------------------------- 1 | #ifndef NMS_HPP 2 | #define NMS_HPP 3 | 4 | #include "eigenplus.h" 5 | using namespace std; 6 | using namespace Eigen; 7 | 8 | void nms(MatrixXd &boundingbox, float threshold, string type, vector& pick); 9 | 10 | #endif // NMS_HPP 11 | -------------------------------------------------------------------------------- /eigenplus.h: -------------------------------------------------------------------------------- 1 | #ifndef EIGENPLUS_H 2 | #define EIGENPLUS_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | 10 | using namespace std; 11 | using namespace Eigen; 12 | 13 | VectorXi _find(MatrixXd A, MatrixXd B); 14 | VectorXi _find(MatrixXd A, double b); 15 | void _find(vector& A, double b, vector& C); 16 | 17 | void _fix(MatrixXd &M); 18 | 19 | MatrixXd subOneRow(MatrixXd M, int index); 20 | 21 | MatrixXd subOneRowRerange(MatrixXd &M, vector &I); 22 | 23 | void npwhere_vec(vector &index, const vector &value, const double threshold); 24 | 25 | void _select(MatrixXd &src, MatrixXd &dst, const vector &pick); 26 | 27 | 28 | #endif // EIGENPLUS_H 29 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # mtcnn 2 | 3 | It a cpp version of [mtcnn](https://github.com/kpzhang93/MTCNN_face_detection_alignment), which is a face detection using cnn. 4 | 5 | ### Requirement 6 | 0. ubuntu (I make it in ubuntu, windows should work fine.) 7 | 1. caffe: [https://github.com/BVLC/caffe](https://github.com/BVLC/caffe), [my csdn](http://blog.csdn.net/duinodu/article/details/52760587) 8 | 2. opencv: [my csdn](http://blog.csdn.net/duinodu/article/details/51804642) 9 | 3. eigen: [http://eigen.tuxfamily.org](https://eigen.tuxfamily.org/index.php?title=Main_Page) 10 | 4. libigl: [https://github.com/libigl/libigl](https://github.com/libigl/libigl/) 11 | 5. qmake 12 | 6. gtest(optional) 13 | 14 | ### Compile and run 15 | 1. 16 | ``` 17 | git clone https://github.com/DuinoDu/mtcnnc_cpp && cd mtcnn_cpp 18 | qtcreator mtcnn.pro 19 | ``` 20 | 21 | 2. Edit mtcnn.pro and set correct lib path. 22 | 23 | 3. Set run line arguments in **Projects** tab, such as */home/duino/project/iactive/mtcnn/mtcnn*. It should contain test images. 24 | 25 | 4. Build && Run 26 | 27 | BTW, you can find python version [here](https://github.com/DuinoDu/mtcnn). 28 | -------------------------------------------------------------------------------- /License.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Duino 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /headlayer.h: -------------------------------------------------------------------------------- 1 | #ifndef HAEDLAYER_H 2 | #define HAEDLAYER_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | namespace caffe 16 | { 17 | extern INSTANTIATE_CLASS(InputLayer); 18 | extern INSTANTIATE_CLASS(InnerProductLayer); 19 | extern INSTANTIATE_CLASS(DropoutLayer); 20 | extern INSTANTIATE_CLASS(ConvolutionLayer); 21 | REGISTER_LAYER_CLASS(Convolution); 22 | extern INSTANTIATE_CLASS(ReLULayer); 23 | REGISTER_LAYER_CLASS(ReLU); 24 | extern INSTANTIATE_CLASS(PReLULayer); 25 | extern INSTANTIATE_CLASS(PoolingLayer); 26 | REGISTER_LAYER_CLASS(Pooling); 27 | extern INSTANTIATE_CLASS(LRNLayer); 28 | REGISTER_LAYER_CLASS(LRN); 29 | extern INSTANTIATE_CLASS(SoftmaxLayer); 30 | REGISTER_LAYER_CLASS(Softmax); 31 | } 32 | 33 | #endif // HAEDLAYER_H 34 | -------------------------------------------------------------------------------- /caffeplus.h: -------------------------------------------------------------------------------- 1 | #ifndef CAFFEPLUS_H 2 | #define CAFFEPLUS_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | using namespace std; 15 | using namespace Eigen; 16 | //using namespace cv; 17 | using cv::Mat; 18 | 19 | void convertToMatrix(caffe::Blob* prob, caffe::Blob* conv, MatrixXd &map, vector ®); 20 | 21 | void convertToVector(caffe::Blob* prob, vector &score); 22 | 23 | void filter(MatrixXd &total_boxes, VectorXi &pass_t, MatrixXd &score); 24 | 25 | void filter(MatrixXd &total_boxes, vector &pass_t, vector &score); 26 | 27 | void getMV(caffe::Blob* conv, MatrixXd &mv, vector &pass_t); 28 | 29 | void debug_blob(caffe::Blob* blob); 30 | 31 | void printMatrix(const MatrixXd &M, const string &name); 32 | 33 | template 34 | void printVector(T &vec, const string &name) 35 | { 36 | cout << endl << name << endl << "size: " << vec.size() << endl; 37 | for(auto i : vec) cout << i << " "; 38 | cout << endl; 39 | } 40 | 41 | #endif // CAFFEPLUS_H 42 | -------------------------------------------------------------------------------- /main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include "mtcnn.h" 15 | #ifndef __linux__ 16 | #include "headlayer.h" 17 | #endif 18 | using namespace cv; 19 | 20 | //#include 21 | 22 | #ifndef IN_TEST 23 | int main(int argc, char* argv[]) 24 | { 25 | if(argc == 1){ 26 | std::cout << "Usage: ./mtcnn.exe [model path]" << std::endl; 27 | return -1; 28 | } 29 | std::cout << argv[1] << std::endl; 30 | FaceDetector detector; 31 | detector.initialize(argv[1]); 32 | 33 | ifstream imgfile; 34 | string imgpath; 35 | #ifndef __linux__ 36 | imgfile.open("H:/project/qt/mtcnn_cpp/mtcnn/imglist_win.txt"); 37 | #else 38 | imgfile.open("/home/duino/project/iactive/mtcnn/mtcnn/imglist.txt"); 39 | #endif 40 | if (imgfile.is_open()){ 41 | while (!imgfile.eof()){ 42 | imgfile >> imgpath; 43 | cout << imgpath << endl; 44 | 45 | Mat img = imread(imgpath); 46 | vector> boxes; 47 | vector> points; 48 | detector.detect(img, boxes, points); 49 | drawBoxes(img, boxes); 50 | drawPoints(img, points); 51 | imshow("test", img); 52 | waitKey(0); 53 | } 54 | } 55 | imgfile.close(); 56 | return 0; 57 | } 58 | #else 59 | #include 60 | int main(int args, char *argv[]) 61 | { 62 | testing::InitGoogleTest(&args, argv); 63 | return RUN_ALL_TESTS(); 64 | } 65 | #endif 66 | -------------------------------------------------------------------------------- /nms.cpp: -------------------------------------------------------------------------------- 1 | #ifndef NMS_HPP 2 | #define NMS_HPP 3 | 4 | #include "nms.h" 5 | #include "eigenplus.h" 6 | using namespace std; 7 | using namespace Eigen; 8 | 9 | void nms(MatrixXd &boundingbox, float threshold, string type, vector& pick) 10 | { 11 | assert(boundingbox.cols() == 5 || boundingbox.cols() == 9); 12 | if (boundingbox.rows() < 1) return; 13 | 14 | MatrixXd x1 = MatrixXd(boundingbox.col(0)); 15 | MatrixXd y1 = MatrixXd(boundingbox.col(1)); 16 | MatrixXd x2 = MatrixXd(boundingbox.col(2)); 17 | MatrixXd y2 = MatrixXd(boundingbox.col(3)); 18 | MatrixXd s = MatrixXd(boundingbox.col(4)); 19 | MatrixXd one_vector = MatrixXd::Ones(x1.rows(), 1); 20 | MatrixXd area = (x2 - x1 + one_vector).cwiseProduct(y2 - y1 + one_vector); 21 | MatrixXd _vals; 22 | MatrixXi _I; 23 | igl::sort(s, 1, true, _vals, _I); 24 | vector I(_I.data(), _I.data() + _I.rows()*_I.cols()); 25 | 26 | while (I.size() > 0){ 27 | //xx1 = max(x1(i), x1(I(1:last-1))); 28 | MatrixXd x1_powerful = MatrixXd(I.size() - 1, 1); 29 | x1_powerful.fill(x1(I.back())); 30 | MatrixXd xx1 = x1_powerful.cwiseMax(subOneRowRerange(x1, I)); 31 | 32 | MatrixXd y1_powerful = MatrixXd(I.size() - 1, 1); 33 | y1_powerful.fill(y1(I.back())); 34 | MatrixXd yy1 = y1_powerful.cwiseMax(subOneRowRerange(y1, I)); 35 | 36 | MatrixXd x2_powerful = MatrixXd(I.size() - 1, 1); 37 | x2_powerful.fill(x2(I.back())); 38 | MatrixXd xx2 = x2_powerful.cwiseMin(subOneRowRerange(x2, I)); 39 | 40 | MatrixXd y2_powerful = MatrixXd(I.size() - 1, 1); 41 | y2_powerful.fill(y2(I.back())); 42 | MatrixXd yy2 = y2_powerful.cwiseMin(subOneRowRerange(y2, I)); 43 | 44 | auto w = MatrixXd::Zero(I.size() - 1, 1).cwiseMax(xx2-xx1+MatrixXd::Ones(I.size()-1,1)); 45 | auto h = MatrixXd::Zero(I.size() - 1, 1).cwiseMax(yy2-yy1+MatrixXd::Ones(I.size()-1,1)); 46 | auto inter = w.cwiseProduct(h); 47 | 48 | MatrixXd o; 49 | MatrixXd area_powerful = MatrixXd(I.size() - 1, 1); 50 | area_powerful.fill(area(I.back())); 51 | if (type == "Min"){ 52 | o = inter.cwiseQuotient(area_powerful.cwiseMin(subOneRowRerange(area, I))); 53 | } 54 | else{ 55 | MatrixXd tmp = area_powerful + subOneRowRerange(area, I) - inter; 56 | o = inter.cwiseQuotient(tmp); 57 | } 58 | 59 | pick.push_back(I.back()); 60 | 61 | // I = I[np.where( o <= threshold )] 62 | vector o_list(o.data(), o.data() + o.rows()*o.cols()); 63 | npwhere_vec(I, o_list, threshold); 64 | } 65 | } 66 | 67 | #endif // NMS_HPP 68 | -------------------------------------------------------------------------------- /mtcnn.h: -------------------------------------------------------------------------------- 1 | #ifndef _MTCNN_HPP 2 | #define _MTCNN_HPP 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #include "eigenplus.h" 20 | #include "caffeplus.h" 21 | #include "nms.h" 22 | 23 | using namespace std; 24 | using namespace Eigen; 25 | //using namespace cv; 26 | using cv::Mat; 27 | using cv::Point; 28 | using cv::Scalar; 29 | using cv::Size; 30 | using cv::Range; 31 | 32 | void bbreg(MatrixXd &boundingbox, MatrixXd ®); 33 | 34 | void denormalize(MatrixXd &boundingbox, MatrixXd &points); 35 | 36 | void pad(MatrixXd &boundingbox, double w, double h, MatrixXd &result); 37 | 38 | void rerec(MatrixXd &boundingbox); 39 | 40 | void generateBoundingBox(MatrixXd &map, vector ®, double scale, double threshold, MatrixXd &boxes); 41 | 42 | void drawBoxes(Mat &im, MatrixXd &boxes); 43 | 44 | void drawBoxes(Mat &im, vector> &boxes); 45 | 46 | void drawPoints(Mat &im, MatrixXd &points); 47 | 48 | void drawPoints(Mat &im, vector> &points); 49 | 50 | void _prepareData(shared_ptr>& net, const Mat& img); 51 | 52 | void _prepareData2(shared_ptr>& net, const vector& imgs); 53 | 54 | void _stage1(Mat &img_mat, int minsize, shared_ptr> PNet, 55 | vector &threshold, bool fastresize, float factor, MatrixXd &total_boxes); 56 | 57 | void _stage2(Mat &img_mat, shared_ptr> RNet, 58 | vector &threshold, MatrixXd &total_boxes); 59 | 60 | void _stage3(Mat &img_mat, shared_ptr> ONet, 61 | vector &threshold, MatrixXd &total_boxes, MatrixXd &total_points); 62 | 63 | void detect_face(Mat &img_mat, int minsize, 64 | shared_ptr> PNet, shared_ptr> RNet, shared_ptr> ONet, 65 | vector threshold, bool fastresize, float factor, MatrixXd &boxes, MatrixXd &points); 66 | 67 | class FaceDetector 68 | { 69 | public: 70 | FaceDetector(){} 71 | void initialize(const string& _model_path){ model_path = _model_path; init(); } 72 | void detect(Mat& _img, vector>& boxes, vector>& points); 73 | 74 | private: 75 | void init(); 76 | string model_path; 77 | vector threshold; 78 | float factor; 79 | int minsize; 80 | bool fastresize; 81 | shared_ptr> PNet, RNet, ONet; 82 | }; 83 | 84 | #endif 85 | -------------------------------------------------------------------------------- /eigenplus.cpp: -------------------------------------------------------------------------------- 1 | #include "eigenplus.h" 2 | 3 | VectorXi _find(MatrixXd A, MatrixXd B){ 4 | // find index where A > B 5 | Matrix C = A.array() > B.array(); 6 | VectorXi I = VectorXi::LinSpaced(C.size(), 0, C.size() - 1); 7 | I.conservativeResize(std::stable_partition( 8 | I.data(), I.data() + I.size(), [&C](int i){return C(i); }) - I.data()); 9 | return I; 10 | } 11 | 12 | VectorXi _find(MatrixXd A, double b){ 13 | MatrixXd B = MatrixXd(A.rows(), A.cols()); 14 | B.fill(b); 15 | Matrix C = A.array() > B.array(); 16 | VectorXi I = VectorXi::LinSpaced(C.size(), 0, C.size() - 1); 17 | I.conservativeResize(std::stable_partition( 18 | I.data(), I.data() + I.size(), [&C](int i){return C(i); }) - I.data()); 19 | return I; 20 | } 21 | 22 | void _find(vector& A, double b, vector& C) 23 | { 24 | for (int i = 0; i < A.size(); i++){ 25 | if (A.at(i) > b){ 26 | C.push_back(i); 27 | } 28 | } 29 | } 30 | 31 | void _fix(MatrixXd &M){ 32 | for (int i = 0; i < M.cols(); i++){ 33 | for (int j = 0; j < M.rows(); j++){ 34 | 35 | int temp = (int)M(j, i); 36 | 37 | if (temp > M(j, i)) temp--; 38 | else if (M(j, i) - temp > 0.9) temp++; 39 | 40 | M(j, i) = (double)temp; 41 | } 42 | } 43 | } 44 | 45 | MatrixXd subOneRow(MatrixXd M, int index){ 46 | assert(M.rows() > index); 47 | MatrixXd out(M.rows() - 1, M.cols()); 48 | for (int i = 0, j = 0; i < M.rows(), j < out.rows(); ){ 49 | if (i != index){ 50 | out.row(j) = M.row(i); 51 | i++; 52 | j++; 53 | } 54 | else 55 | i++; 56 | } 57 | return out; 58 | } 59 | 60 | MatrixXd subOneRowRerange(MatrixXd &M, vector &I) 61 | { 62 | MatrixXd out(I.size() - 1, M.cols()); 63 | for (int i = 0; i < I.size() - 1; i++){ 64 | out.row(i) = M.row(I[i]); 65 | } 66 | return out; 67 | } 68 | 69 | void npwhere_vec(vector &index, const vector &value, const double threshold) 70 | { 71 | vector out; 72 | auto i = index.begin(); 73 | auto j = value.begin(); 74 | for (; i != index.end(), j != value.end(); i++, j++){ 75 | if (*j <= threshold){ 76 | out.push_back(*i); 77 | } 78 | } 79 | index.resize(out.size()); 80 | index = out; 81 | } 82 | 83 | void _select(MatrixXd &src, MatrixXd &dst, const vector &pick) 84 | { 85 | MatrixXd _src = src.replicate(1,1); 86 | int new_height = pick.size(); 87 | int new_width = src.cols(); 88 | dst.resize(new_height, new_width); 89 | for(int i=0; i < pick.size(); i++){ 90 | dst.row(i) = _src.row(pick[i]); 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /mtcnn/model/det1.prototxt: -------------------------------------------------------------------------------- 1 | name: "PNet" 2 | input: "data" 3 | input_dim: 1 4 | input_dim: 3 5 | input_dim: 12 6 | input_dim: 12 7 | 8 | layer { 9 | name: "conv1" 10 | type: "Convolution" 11 | bottom: "data" 12 | top: "conv1" 13 | param { 14 | lr_mult: 1 15 | decay_mult: 1 16 | } 17 | param { 18 | lr_mult: 2 19 | decay_mult: 0 20 | } 21 | convolution_param { 22 | num_output: 10 23 | kernel_size: 3 24 | stride: 1 25 | weight_filler { 26 | type: "xavier" 27 | } 28 | bias_filler { 29 | type: "constant" 30 | value: 0 31 | } 32 | } 33 | } 34 | layer { 35 | name: "PReLU1" 36 | type: "PReLU" 37 | bottom: "conv1" 38 | top: "conv1" 39 | } 40 | layer { 41 | name: "pool1" 42 | type: "Pooling" 43 | bottom: "conv1" 44 | top: "pool1" 45 | pooling_param { 46 | pool: MAX 47 | kernel_size: 2 48 | stride: 2 49 | } 50 | } 51 | 52 | layer { 53 | name: "conv2" 54 | type: "Convolution" 55 | bottom: "pool1" 56 | top: "conv2" 57 | param { 58 | lr_mult: 1 59 | decay_mult: 1 60 | } 61 | param { 62 | lr_mult: 2 63 | decay_mult: 0 64 | } 65 | convolution_param { 66 | num_output: 16 67 | kernel_size: 3 68 | stride: 1 69 | weight_filler { 70 | type: "xavier" 71 | } 72 | bias_filler { 73 | type: "constant" 74 | value: 0 75 | } 76 | } 77 | } 78 | layer { 79 | name: "PReLU2" 80 | type: "PReLU" 81 | bottom: "conv2" 82 | top: "conv2" 83 | } 84 | 85 | layer { 86 | name: "conv3" 87 | type: "Convolution" 88 | bottom: "conv2" 89 | top: "conv3" 90 | param { 91 | lr_mult: 1 92 | decay_mult: 1 93 | } 94 | param { 95 | lr_mult: 2 96 | decay_mult: 0 97 | } 98 | convolution_param { 99 | num_output: 32 100 | kernel_size: 3 101 | stride: 1 102 | weight_filler { 103 | type: "xavier" 104 | } 105 | bias_filler { 106 | type: "constant" 107 | value: 0 108 | } 109 | } 110 | } 111 | layer { 112 | name: "PReLU3" 113 | type: "PReLU" 114 | bottom: "conv3" 115 | top: "conv3" 116 | } 117 | 118 | 119 | layer { 120 | name: "conv4-1" 121 | type: "Convolution" 122 | bottom: "conv3" 123 | top: "conv4-1" 124 | param { 125 | lr_mult: 1 126 | decay_mult: 1 127 | } 128 | param { 129 | lr_mult: 2 130 | decay_mult: 0 131 | } 132 | convolution_param { 133 | num_output: 2 134 | kernel_size: 1 135 | stride: 1 136 | weight_filler { 137 | type: "xavier" 138 | } 139 | bias_filler { 140 | type: "constant" 141 | value: 0 142 | } 143 | } 144 | } 145 | 146 | layer { 147 | name: "conv4-2" 148 | type: "Convolution" 149 | bottom: "conv3" 150 | top: "conv4-2" 151 | param { 152 | lr_mult: 1 153 | decay_mult: 1 154 | } 155 | param { 156 | lr_mult: 2 157 | decay_mult: 0 158 | } 159 | convolution_param { 160 | num_output: 4 161 | kernel_size: 1 162 | stride: 1 163 | weight_filler { 164 | type: "xavier" 165 | } 166 | bias_filler { 167 | type: "constant" 168 | value: 0 169 | } 170 | } 171 | } 172 | layer { 173 | name: "prob1" 174 | type: "Softmax" 175 | bottom: "conv4-1" 176 | top: "prob1" 177 | } 178 | -------------------------------------------------------------------------------- /test_data/boxes.out: -------------------------------------------------------------------------------- 1 | 1.8500e+02 9.5000e+01 2.0300e+02 1.1300e+02 6.7337e-01 8.4182e-02 -4.8847e-02 7.5039e-02 9.4326e-02 2 | 1.8800e+02 9.5000e+01 2.0600e+02 1.1300e+02 6.4645e-01 -3.2234e-02 -1.0333e-01 7.5169e-02 1.5039e-01 3 | 1.9100e+02 9.5000e+01 2.1000e+02 1.1300e+02 8.9502e-01 -4.3463e-02 -1.0086e-01 1.8985e-02 1.0482e-01 4 | 2.0100e+02 9.5000e+01 2.2000e+02 1.1300e+02 6.6408e-01 -8.1766e-02 -1.4017e-01 2.2918e-02 1.4339e-01 5 | 3.5800e+02 1.1500e+02 3.7600e+02 1.3300e+02 6.5924e-01 -9.6915e-02 -5.1017e-02 -1.3730e-01 1.8958e-01 6 | 2.4500e+02 1.2100e+02 2.6300e+02 1.4000e+02 7.2534e-01 -4.3955e-02 -1.2307e-01 4.4887e-02 2.0344e-01 7 | 2.4800e+02 1.2100e+02 2.6600e+02 1.4000e+02 7.3202e-01 -3.9066e-02 -1.0162e-01 7.3377e-02 2.2607e-01 8 | 2.7800e+02 1.2800e+02 2.9600e+02 1.4600e+02 7.0513e-01 -6.4167e-02 -1.7475e-02 -5.7921e-02 2.0534e-01 9 | 2.7500e+02 1.3100e+02 2.9300e+02 1.5000e+02 7.2066e-01 -5.2986e-02 -3.4252e-02 -6.9207e-02 1.9705e-01 10 | 2.7800e+02 1.3100e+02 2.9600e+02 1.5000e+02 6.7700e-01 -5.7652e-02 -4.1613e-02 -1.5257e-01 1.1546e-01 11 | 2.7500e+02 1.3500e+02 2.9300e+02 1.5300e+02 7.0630e-01 -6.7691e-02 -1.1766e-01 -2.3220e-02 1.2937e-01 12 | 2.7800e+02 1.3500e+02 2.9600e+02 1.5300e+02 9.3361e-01 -8.2015e-02 -7.1894e-02 -1.6538e-01 7.9455e-02 13 | 3.5500e+02 1.3500e+02 3.7300e+02 1.5300e+02 6.5844e-01 -2.7697e-02 -1.4134e-01 -5.5226e-02 7.0944e-02 14 | 3.5500e+02 1.3800e+02 3.7300e+02 1.5600e+02 6.4071e-01 -5.3183e-02 -2.2084e-01 -4.2528e-02 5.3963e-02 15 | 2.3100e+02 1.4100e+02 2.5000e+02 1.6000e+02 6.9477e-01 1.7754e-04 -1.9412e-02 -6.7537e-02 1.9853e-01 16 | 3.5500e+02 1.4100e+02 3.7300e+02 1.6000e+02 7.6116e-01 -2.6806e-02 -2.5388e-01 1.7989e-02 6.7516e-02 17 | 2.5100e+02 1.4500e+02 2.7000e+02 1.6300e+02 8.0596e-01 2.9329e-02 -9.1032e-02 2.5109e-02 4.7030e-02 18 | 2.5500e+02 1.4500e+02 2.7300e+02 1.6300e+02 6.2010e-01 -7.1788e-02 -9.5555e-02 -1.0744e-02 1.1235e-01 19 | 2.1500e+02 1.4800e+02 2.3300e+02 1.6600e+02 6.0467e-01 -5.7800e-02 -7.9364e-02 -3.0056e-02 1.4566e-01 20 | 3.5500e+02 1.4800e+02 3.7300e+02 1.6600e+02 6.0878e-01 4.0163e-02 -1.8100e-01 -4.3903e-04 3.8861e-02 21 | 3.5500e+02 1.6100e+02 3.7300e+02 1.8000e+02 7.1229e-01 6.1695e-02 -1.3469e-01 -2.1435e-02 6.0637e-02 22 | 3.5800e+02 1.6100e+02 3.7600e+02 1.8000e+02 7.7211e-01 3.6195e-03 -5.9673e-02 -7.9618e-02 8.7435e-02 23 | 3.5800e+02 1.6500e+02 3.7600e+02 1.8300e+02 8.2662e-01 -4.9907e-03 -9.6630e-02 -5.3381e-02 5.8396e-02 24 | 3.6100e+02 1.7100e+02 3.8000e+02 1.9000e+02 7.0146e-01 -6.1419e-02 -1.5427e-01 -5.6818e-02 8.0965e-02 25 | 2.4500e+02 2.2100e+02 2.6300e+02 2.4000e+02 6.2759e-01 4.5683e-02 -3.0852e-02 -7.1883e-03 5.2055e-02 26 | 2.7100e+02 2.4100e+02 2.9000e+02 2.6000e+02 6.8139e-01 -1.0852e-01 -2.5096e-01 -1.1302e-02 6.9533e-02 27 | 1.2100e+02 2.5500e+02 1.4000e+02 2.7300e+02 6.6459e-01 4.2268e-02 -5.9729e-02 -8.6850e-03 9.5601e-02 28 | 2.3500e+02 2.6100e+02 2.5300e+02 2.8000e+02 6.2167e-01 -1.3534e-02 -2.8014e-01 8.1984e-02 4.6258e-02 29 | 2.4500e+02 3.4800e+02 2.6300e+02 3.6600e+02 7.3506e-01 1.4446e-01 -7.4538e-02 8.7610e-02 1.2414e-01 30 | 2.5500e+02 3.4800e+02 2.7300e+02 3.6600e+02 7.3041e-01 -1.4210e-01 -1.6089e-01 -5.3675e-03 1.9273e-01 31 | 2.5100e+02 3.5100e+02 2.7000e+02 3.7000e+02 8.1321e-01 -1.3766e-01 -2.6086e-01 3.3631e-02 1.1466e-01 32 | 2.5500e+02 3.5100e+02 2.7300e+02 3.7000e+02 8.4511e-01 -1.7021e-01 -2.7787e-01 1.6933e-03 1.0585e-01 33 | -------------------------------------------------------------------------------- /mtcnn/file - 副本.txt: -------------------------------------------------------------------------------- 1 | positive/2.jpg 2 | 3 | positive/4.jpg 4 | 5 | positive/5.jpg 6 | 7 | positive/6.jpg 8 | 9 | positive/7.jpg 10 | 11 | positive/8.jpg 12 | 13 | positive/22.jpg 14 | 15 | positive/23.jpg 16 | 17 | positive/24.jpg 18 | 19 | positive/25.jpg 20 | 21 | positive/26.jpg 22 | 23 | positive/28.jpg 24 | 25 | positive/32.jpg 26 | 27 | positive/34.jpg 28 | 29 | positive/35.jpg 30 | 31 | positive/36.jpg 32 | 33 | positive/37.jpg 34 | 35 | positive/38.jpg 36 | 37 | positive/39.jpg 38 | 39 | positive/40.jpg 40 | 41 | positive/41.jpg 42 | 43 | positive/42.jpg 44 | 45 | positive/43.jpg 46 | 47 | positive/48.jpg 48 | 49 | positive/49.jpg 50 | 51 | positive/50.jpg 52 | 53 | positive/51.jpg 54 | 55 | positive/52.jpg 56 | 57 | positive/54.jpg 58 | 59 | positive/55.jpg 60 | 61 | positive/56.jpg 62 | 63 | positive/57.jpg 64 | 65 | positive/58.jpg 66 | 67 | positive/61.jpg 68 | 69 | positive/62.jpg 70 | 71 | positive/63.jpg 72 | 73 | positive/100.jpg 74 | 75 | positive/102.jpg 76 | 77 | positive/104.jpg 78 | 79 | positive/144.jpg 80 | 81 | positive/145.jpg 82 | 83 | positive/146.jpg 84 | 85 | positive/147.jpg 86 | 87 | positive/148.jpg 88 | 89 | positive/150.jpg 90 | 91 | positive/151.jpg 92 | 93 | positive/153.jpg 94 | 95 | positive/154.jpg 96 | 97 | positive/155.jpg 98 | 99 | positive/156.jpg 100 | 101 | positive/157.jpg 102 | 103 | positive/159.jpg 104 | 105 | positive/165.jpg 106 | 107 | positive/166.jpg 108 | 109 | positive/167.jpg 110 | 111 | positive/168.jpg 112 | 113 | positive/171.jpg 114 | 115 | positive/172.jpg 116 | 117 | positive/173.jpg 118 | 119 | positive/174.jpg 120 | 121 | positive/175.jpg 122 | 123 | positive/183.jpg 124 | 125 | positive/184.jpg 126 | 127 | positive/185.jpg 128 | 129 | positive/186.jpg 130 | 131 | positive/235.jpg 132 | 133 | positive/236.jpg 134 | 135 | positive/237.jpg 136 | 137 | positive/238.jpg 138 | 139 | positive/239.jpg 140 | 141 | positive/240.jpg 142 | 143 | positive/241.jpg 144 | 145 | positive/242.jpg 146 | 147 | positive/243.jpg 148 | 149 | positive/244.jpg 150 | 151 | positive/287.jpg 152 | 153 | positive/288.jpg 154 | 155 | positive/289.jpg 156 | 157 | positive/290.jpg 158 | 159 | positive/291.jpg 160 | 161 | positive/293.jpg 162 | 163 | positive/295.jpg 164 | 165 | positive/297.jpg 166 | 167 | positive/312.jpg 168 | 169 | positive/314.jpg 170 | 171 | positive/316.jpg 172 | 173 | positive/318.jpg 174 | 175 | positive/320.jpg 176 | 177 | positive/321.jpg 178 | 179 | positive/322.jpg 180 | 181 | positive/323.jpg 182 | 183 | positive/324.jpg 184 | 185 | positive/325.jpg 186 | 187 | positive/332.jpg 188 | 189 | positive/333.jpg 190 | 191 | positive/334.jpg 192 | 193 | positive/335.jpg 194 | 195 | positive/336.jpg 196 | 197 | positive/337.jpg 198 | 199 | positive/339.jpg 200 | 201 | positive/340.jpg 202 | 203 | positive/342.jpg 204 | 205 | positive/343.jpg 206 | 207 | positive/344.jpg 208 | 209 | positive/345.jpg 210 | 211 | positive/346.jpg 212 | 213 | positive/347.jpg 214 | 215 | positive/368.jpg 216 | 217 | positive/387.jpg 218 | 219 | positive/388.jpg 220 | 221 | positive/389.jpg 222 | 223 | positive/390.jpg 224 | 225 | positive/391.jpg 226 | 227 | positive/392.jpg 228 | 229 | positive/393.jpg 230 | 231 | positive/394.jpg 232 | 233 | positive/395.jpg 234 | 235 | positive/396.jpg 236 | 237 | positive/402.jpg 238 | 239 | positive/403.jpg 240 | 241 | positive/404.jpg 242 | 243 | positive/405.jpg 244 | 245 | positive/406.jpg 246 | 247 | positive/407.jpg 248 | 249 | positive/482.jpg 250 | 251 | positive/483.jpg -------------------------------------------------------------------------------- /mtcnn.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = app 2 | TARGET = mtcnn 3 | INCLUDEPATH += . 4 | DEFINES += USE_OPENCV CPU_ONLY 5 | 6 | # Input 7 | HEADERS += mtcnn.h \ 8 | nms.h \ 9 | eigenplus.h \ 10 | caffeplus.h \ 11 | headlayer.h 12 | 13 | SOURCES += \ 14 | #test_utility.cpp \ 15 | #test_nms.cpp \ 16 | mtcnn.cpp \ 17 | nms.cpp \ 18 | eigenplus.cpp \ 19 | caffeplus.cpp \ 20 | main.cpp 21 | 22 | unix:!macx{ 23 | # caffe 24 | INCLUDEPATH += /home/duino/project/py-faster-rcnn/caffe-fast-rcnn/include 25 | LIBS += -L/home/duino/project/py-faster-rcnn/caffe-fast-rcnn/build/lib \ 26 | -lcaffe 27 | # opencv 28 | INCLUDEPATH += /usr/local/include 29 | LIBS += -L/usr/local/lib \ 30 | -lopencv_core -lopencv_highgui -lopencv_imgproc -lopencv_imgcodecs 31 | # glog, boost 32 | LIBS += -lglog -lboost_system 33 | # eigen, libigl 34 | INCLUDEPATH += /usr/local/include/eigen 35 | INCLUDEPATH += /usr/local/include/libigl/include 36 | # gtest 37 | LIBS += -lgtest -lgtest_main -lpthread 38 | } 39 | 40 | win32{ 41 | # opencv 42 | PATH_OPENCV_INCLUDE = "H:\3rdparty\OpenCV\opencv310\build\include" 43 | PATH_OPENCV_LIBRARIES = "H:\3rdparty\OpenCV\opencv310\build\x64\vc12\lib" 44 | VERSION_OPENCV = 310 45 | INCLUDEPATH += $${PATH_OPENCV_INCLUDE} 46 | CONFIG(debug, debug|release){ 47 | LIBS += -L$${PATH_OPENCV_LIBRARIES} -lopencv_core$${VERSION_OPENCV}d 48 | LIBS += -L$${PATH_OPENCV_LIBRARIES} -lopencv_highgui$${VERSION_OPENCV}d 49 | LIBS += -L$${PATH_OPENCV_LIBRARIES} -lopencv_imgcodecs$${VERSION_OPENCV}d 50 | LIBS += -L$${PATH_OPENCV_LIBRARIES} -lopencv_imgproc$${VERSION_OPENCV}d 51 | } 52 | CONFIG(release, debug|release){ 53 | LIBS += -L$${PATH_OPENCV_LIBRARIES} -lopencv_core$${VERSION_OPENCV} 54 | LIBS += -L$${PATH_OPENCV_LIBRARIES} -lopencv_highgui$${VERSION_OPENCV} 55 | LIBS += -L$${PATH_OPENCV_LIBRARIES} -lopencv_imgcodecs$${VERSION_OPENCV} 56 | LIBS += -L$${PATH_OPENCV_LIBRARIES} -lopencv_imgproc$${VERSION_OPENCV} 57 | } 58 | #glog 59 | INCLUDEPATH += H:\3rdparty\glog\include 60 | LIBS += -LH:\3rdparty\glog\lib\x64\v120\Debug\dynamic -llibglog 61 | #boost 62 | INCLUDEPATH += H:\3rdparty\boost\boost_1_59_0 63 | CONFIG(debug, debug|release): BOOST_VERSION = "-vc120-mt-gd-1_59" 64 | CONFIG(release, debug|release): BOOST_VERSION = "-vc120-mt-1_59" 65 | LIBS += -LH:\3rdparty\boost\boost_1_59_0\lib64-msvc-12.0 \ 66 | -llibboost_system$${BOOST_VERSION} \ 67 | -llibboost_date_time$${BOOST_VERSION} \ 68 | -llibboost_filesystem$${BOOST_VERSION} \ 69 | -llibboost_thread$${BOOST_VERSION} \ 70 | -llibboost_regex$${BOOST_VERSION} 71 | #gflags 72 | INCLUDEPATH += H:\3rdparty\gflags\include 73 | CONFIG(debug, debug|release): LIBS += -LH:\3rdparty\gflags\x64\v120\dynamic\Lib -lgflagsd 74 | CONFIG(release, debug|release): LIBS += -LH:\3rdparty\gflags\x64\v120\dynamic\Lib -lgflags 75 | #protobuf 76 | INCLUDEPATH += H:\3rdparty\protobuf\include 77 | CONFIG(debug, debug|release): LIBS += -LH:\3rdparty\protobuf\lib\x64\v120\Debug -llibprotobuf 78 | CONFIG(release, debug|release): LIBS += -LH:\3rdparty\protobuf\lib\x64\v120\Release -llibprotobuf 79 | # hdf5 80 | INCLUDEPATH += H:\3rdparty\hdf5\include 81 | LIBS += -LH:\3rdparty\hdf5\lib\x64 -lhdf5 -lhdf5_hl -lhdf5_tools -lhdf5_cpp 82 | # levelDb 83 | INCLUDEPATH += H:\3rdparty\LevelDB\include 84 | CONFIG(debug, debug|release): LIBS += -LH:\3rdparty\LevelDB\lib\x64\v120\Debug -lLevelDb 85 | CONFIG(release, debug|release): LIBS += -LH:\3rdparty\LevelDB\lib\x64\v120\Release -lLevelDb 86 | # lmdb 87 | INCLUDEPATH += H:\3rdparty\lmdb\include 88 | CONFIG(debug, debug|release): LIBS += -LH:\3rdparty\lmdb\lib\x64 -llmdbD 89 | CONFIG(release, debug|release): LIBS += -LH:\3rdparty\lmdb\lib\x64 -llmdb 90 | #openblas 91 | INCLUDEPATH += H:\3rdparty\openblas\include 92 | LIBS += -LH:\3rdparty\openblas\lib\x64 -llibopenblas 93 | # caffe 94 | INCLUDEPATH += H:\3rdparty\caffe\include 95 | CONFIG(debug, debug|release): LIBS += -LH:\3rdparty\caffe\lib\x64 -llibcaffed 96 | CONFIG(release, debug|release): LIBS += -LH:\3rdparty\caffe\lib\x64 -llibcaffe 97 | 98 | #eigen, igl 99 | INCLUDEPATH += H:\3rdparty\eigen 100 | INCLUDEPATH += H:\3rdparty\libigl\include 101 | # gtest 102 | INCLUDEPATH += H:\3rdparty\gtest\include\ 103 | LIBS += H:\3rdparty\gtest\x64 -lgtest -lgtest_main 104 | } 105 | 106 | 107 | #QMAKE_CXXFLAGS += -pg 108 | #LIBS += -pg 109 | -------------------------------------------------------------------------------- /mtcnn/model/det2.prototxt: -------------------------------------------------------------------------------- 1 | name: "RNet" 2 | input: "data" 3 | input_dim: 1 4 | input_dim: 3 5 | input_dim: 24 6 | input_dim: 24 7 | 8 | 9 | ########################## 10 | ###################### 11 | layer { 12 | name: "conv1" 13 | type: "Convolution" 14 | bottom: "data" 15 | top: "conv1" 16 | param { 17 | lr_mult: 0 18 | decay_mult: 0 19 | } 20 | param { 21 | lr_mult: 0 22 | decay_mult: 0 23 | } 24 | convolution_param { 25 | num_output: 28 26 | kernel_size: 3 27 | stride: 1 28 | weight_filler { 29 | type: "xavier" 30 | } 31 | bias_filler { 32 | type: "constant" 33 | value: 0 34 | } 35 | } 36 | } 37 | layer { 38 | name: "prelu1" 39 | type: "PReLU" 40 | bottom: "conv1" 41 | top: "conv1" 42 | propagate_down: true 43 | } 44 | layer { 45 | name: "pool1" 46 | type: "Pooling" 47 | bottom: "conv1" 48 | top: "pool1" 49 | pooling_param { 50 | pool: MAX 51 | kernel_size: 3 52 | stride: 2 53 | } 54 | } 55 | 56 | layer { 57 | name: "conv2" 58 | type: "Convolution" 59 | bottom: "pool1" 60 | top: "conv2" 61 | param { 62 | lr_mult: 0 63 | decay_mult: 0 64 | } 65 | param { 66 | lr_mult: 0 67 | decay_mult: 0 68 | } 69 | convolution_param { 70 | num_output: 48 71 | kernel_size: 3 72 | stride: 1 73 | weight_filler { 74 | type: "xavier" 75 | } 76 | bias_filler { 77 | type: "constant" 78 | value: 0 79 | } 80 | } 81 | } 82 | layer { 83 | name: "prelu2" 84 | type: "PReLU" 85 | bottom: "conv2" 86 | top: "conv2" 87 | propagate_down: true 88 | } 89 | layer { 90 | name: "pool2" 91 | type: "Pooling" 92 | bottom: "conv2" 93 | top: "pool2" 94 | pooling_param { 95 | pool: MAX 96 | kernel_size: 3 97 | stride: 2 98 | } 99 | } 100 | #################################### 101 | 102 | ################################## 103 | layer { 104 | name: "conv3" 105 | type: "Convolution" 106 | bottom: "pool2" 107 | top: "conv3" 108 | param { 109 | lr_mult: 0 110 | decay_mult: 0 111 | } 112 | param { 113 | lr_mult: 0 114 | decay_mult: 0 115 | } 116 | convolution_param { 117 | num_output: 64 118 | kernel_size: 2 119 | stride: 1 120 | weight_filler { 121 | type: "xavier" 122 | } 123 | bias_filler { 124 | type: "constant" 125 | value: 0 126 | } 127 | } 128 | } 129 | layer { 130 | name: "prelu3" 131 | type: "PReLU" 132 | bottom: "conv3" 133 | top: "conv3" 134 | propagate_down: true 135 | } 136 | ############################### 137 | 138 | ############################### 139 | 140 | layer { 141 | name: "conv4" 142 | type: "InnerProduct" 143 | bottom: "conv3" 144 | top: "conv4" 145 | param { 146 | lr_mult: 0 147 | decay_mult: 0 148 | } 149 | param { 150 | lr_mult: 0 151 | decay_mult: 0 152 | } 153 | inner_product_param { 154 | num_output: 128 155 | weight_filler { 156 | type: "xavier" 157 | } 158 | bias_filler { 159 | type: "constant" 160 | value: 0 161 | } 162 | } 163 | } 164 | layer { 165 | name: "prelu4" 166 | type: "PReLU" 167 | bottom: "conv4" 168 | top: "conv4" 169 | } 170 | 171 | layer { 172 | name: "conv5-1" 173 | type: "InnerProduct" 174 | bottom: "conv4" 175 | top: "conv5-1" 176 | param { 177 | lr_mult: 0 178 | decay_mult: 0 179 | } 180 | param { 181 | lr_mult: 0 182 | decay_mult: 0 183 | } 184 | inner_product_param { 185 | num_output: 2 186 | #kernel_size: 1 187 | #stride: 1 188 | weight_filler { 189 | type: "xavier" 190 | } 191 | bias_filler { 192 | type: "constant" 193 | value: 0 194 | } 195 | } 196 | } 197 | layer { 198 | name: "conv5-2" 199 | type: "InnerProduct" 200 | bottom: "conv4" 201 | top: "conv5-2" 202 | param { 203 | lr_mult: 1 204 | decay_mult: 1 205 | } 206 | param { 207 | lr_mult: 2 208 | decay_mult: 1 209 | } 210 | inner_product_param { 211 | num_output: 4 212 | #kernel_size: 1 213 | #stride: 1 214 | weight_filler { 215 | type: "xavier" 216 | } 217 | bias_filler { 218 | type: "constant" 219 | value: 0 220 | } 221 | } 222 | } 223 | layer { 224 | name: "prob1" 225 | type: "Softmax" 226 | bottom: "conv5-1" 227 | top: "prob1" 228 | } -------------------------------------------------------------------------------- /caffeplus.cpp: -------------------------------------------------------------------------------- 1 | #include "caffeplus.h" 2 | #include "eigenplus.h" 3 | 4 | void convertToMatrix(caffe::Blob* prob, caffe::Blob* conv, MatrixXd &map, vector ®) 5 | { 6 | int height = prob->height(); 7 | int width = prob->width(); 8 | 9 | // convert to map 10 | float* data = prob->mutable_cpu_data() + height * width; 11 | Mat prob_mat(height, width, CV_32FC1, data); 12 | cv2eigen(prob_mat, map); 13 | 14 | //for (int i = 0; i < 20; i++) cout << "prob " << i << ": " << *(data + i) << endl; 15 | 16 | // convert to reg 17 | data = conv->mutable_cpu_data(); 18 | MatrixXd eachReg; 19 | eachReg.resize(height, width); 20 | for(int i=0; i < conv->channels(); i++){ 21 | Mat reg_mat(height, width, CV_32FC1, data); 22 | cv2eigen(reg_mat, eachReg); 23 | reg.push_back(eachReg); 24 | //cout << "===\n"; 25 | //for (int j = 0; j < 20; j++) cout << i << " conv " << j << ": " << *(data + j) << endl; 26 | data += height * width; 27 | } 28 | } 29 | 30 | void convertToVector(caffe::Blob* prob, vector &score) 31 | { 32 | 33 | #ifdef DEBUG_MTCNN 34 | debug_blob(prob); 35 | #endif 36 | 37 | assert(prob->channels() == 2); 38 | int num = prob->num(); 39 | 40 | // convert to score 41 | float* data = prob->mutable_cpu_data(); 42 | data++; 43 | for (int i = 0; i < num; i++){ 44 | #ifdef DEBUG_MTCNN 45 | cout << *data << endl; // for speed up 46 | #endif 47 | score.push_back(*data); 48 | data += 2; 49 | } 50 | } 51 | 52 | void filter(MatrixXd &total_boxes, VectorXi &pass_t, MatrixXd &score) 53 | { 54 | MatrixXd new_boxes; 55 | new_boxes.resize(pass_t.size(), 5); 56 | for (int i = 0; i < pass_t.size(); i++){ 57 | MatrixXd tmp; 58 | tmp.resize(1, 5); 59 | tmp << total_boxes(pass_t(i), 0), total_boxes(pass_t(i), 1), total_boxes(pass_t(i), 2), total_boxes(pass_t(i), 3), score(pass_t(i)); 60 | new_boxes.row(i) = tmp; 61 | } 62 | total_boxes.resize(pass_t.size(), 5); 63 | total_boxes << new_boxes; 64 | } 65 | 66 | void filter(MatrixXd &total_boxes, vector &pass_t, vector &score) 67 | { 68 | MatrixXd new_boxes; 69 | new_boxes.resize(pass_t.size(), 5); 70 | for (int i = 0; i < pass_t.size(); i++){ 71 | MatrixXd tmp; 72 | tmp.resize(1, 5); 73 | tmp << total_boxes(pass_t.at(i), 0), total_boxes(pass_t.at(i), 1), total_boxes(pass_t.at(i), 2), total_boxes(pass_t.at(i), 3), score.at(pass_t.at(i)); 74 | new_boxes.row(i) = tmp; 75 | } 76 | total_boxes.resize(pass_t.size(), 5); 77 | total_boxes << new_boxes; 78 | } 79 | 80 | void getMV(caffe::Blob* conv, MatrixXd &mv, vector &pass_t) 81 | { 82 | int num = conv->num(); 83 | int channels = conv->channels(); 84 | 85 | // convert to MatrixXd 86 | MatrixXd conv_m; 87 | float* data = conv->mutable_cpu_data(); 88 | Mat conv_mat(num, channels, CV_32FC1, data); 89 | cv2eigen(conv_mat, conv_m); 90 | _select(conv_m, mv, pass_t); 91 | } 92 | 93 | void debug_blob(caffe::Blob* blob){ 94 | int num = blob->num(); 95 | int channels = blob->channels(); 96 | int height = blob->height(); 97 | int width = blob->width(); 98 | cout << "\n\nnum:" << num << endl; 99 | cout << "channels:" << channels << endl; 100 | cout << "height:" << height << endl; 101 | cout << "width:" << width << endl; 102 | 103 | float* data = blob->mutable_cpu_data(); 104 | for (int i = 0; i < std::min(num, 3); i++){ 105 | cout << "##########" << endl; 106 | cout << "# num " << i << " #"; 107 | cout << "\n##########" << endl; 108 | for (int j = 0; j < std::min(channels, 3); j++){ 109 | cout << "*****************channels " << j << " *****************" << endl; 110 | for (int k = 0; k < std::min(width, 3); k++){ 111 | for (int m = 0; m < std::min(height, 3); m++){ 112 | cout << *(data + m + k*width + j*width*height + i*channels*width*height) << " "; 113 | } 114 | cout << endl; 115 | } 116 | } 117 | } 118 | } 119 | 120 | void printMatrix(const MatrixXd &M, const string &name) 121 | { 122 | cout << name << endl << "size: " << M.rows() << "*" << M.cols() << endl; 123 | cout << M << endl; 124 | } 125 | 126 | -------------------------------------------------------------------------------- /mtcnn/model/det3.prototxt: -------------------------------------------------------------------------------- 1 | name: "ONet" 2 | input: "data" 3 | input_dim: 1 4 | input_dim: 3 5 | input_dim: 48 6 | input_dim: 48 7 | ################################## 8 | layer { 9 | name: "conv1" 10 | type: "Convolution" 11 | bottom: "data" 12 | top: "conv1" 13 | param { 14 | lr_mult: 1 15 | decay_mult: 1 16 | } 17 | param { 18 | lr_mult: 2 19 | decay_mult: 1 20 | } 21 | convolution_param { 22 | num_output: 32 23 | kernel_size: 3 24 | stride: 1 25 | weight_filler { 26 | type: "xavier" 27 | } 28 | bias_filler { 29 | type: "constant" 30 | value: 0 31 | } 32 | } 33 | } 34 | layer { 35 | name: "prelu1" 36 | type: "PReLU" 37 | bottom: "conv1" 38 | top: "conv1" 39 | } 40 | layer { 41 | name: "pool1" 42 | type: "Pooling" 43 | bottom: "conv1" 44 | top: "pool1" 45 | pooling_param { 46 | pool: MAX 47 | kernel_size: 3 48 | stride: 2 49 | } 50 | } 51 | layer { 52 | name: "conv2" 53 | type: "Convolution" 54 | bottom: "pool1" 55 | top: "conv2" 56 | param { 57 | lr_mult: 1 58 | decay_mult: 1 59 | } 60 | param { 61 | lr_mult: 2 62 | decay_mult: 1 63 | } 64 | convolution_param { 65 | num_output: 64 66 | kernel_size: 3 67 | stride: 1 68 | weight_filler { 69 | type: "xavier" 70 | } 71 | bias_filler { 72 | type: "constant" 73 | value: 0 74 | } 75 | } 76 | } 77 | 78 | layer { 79 | name: "prelu2" 80 | type: "PReLU" 81 | bottom: "conv2" 82 | top: "conv2" 83 | } 84 | layer { 85 | name: "pool2" 86 | type: "Pooling" 87 | bottom: "conv2" 88 | top: "pool2" 89 | pooling_param { 90 | pool: MAX 91 | kernel_size: 3 92 | stride: 2 93 | } 94 | } 95 | 96 | layer { 97 | name: "conv3" 98 | type: "Convolution" 99 | bottom: "pool2" 100 | top: "conv3" 101 | param { 102 | lr_mult: 1 103 | decay_mult: 1 104 | } 105 | param { 106 | lr_mult: 2 107 | decay_mult: 1 108 | } 109 | convolution_param { 110 | num_output: 64 111 | kernel_size: 3 112 | weight_filler { 113 | type: "xavier" 114 | } 115 | bias_filler { 116 | type: "constant" 117 | value: 0 118 | } 119 | } 120 | } 121 | layer { 122 | name: "prelu3" 123 | type: "PReLU" 124 | bottom: "conv3" 125 | top: "conv3" 126 | } 127 | layer { 128 | name: "pool3" 129 | type: "Pooling" 130 | bottom: "conv3" 131 | top: "pool3" 132 | pooling_param { 133 | pool: MAX 134 | kernel_size: 2 135 | stride: 2 136 | } 137 | } 138 | layer { 139 | name: "conv4" 140 | type: "Convolution" 141 | bottom: "pool3" 142 | top: "conv4" 143 | param { 144 | lr_mult: 1 145 | decay_mult: 1 146 | } 147 | param { 148 | lr_mult: 2 149 | decay_mult: 1 150 | } 151 | convolution_param { 152 | num_output: 128 153 | kernel_size: 2 154 | weight_filler { 155 | type: "xavier" 156 | } 157 | bias_filler { 158 | type: "constant" 159 | value: 0 160 | } 161 | } 162 | } 163 | layer { 164 | name: "prelu4" 165 | type: "PReLU" 166 | bottom: "conv4" 167 | top: "conv4" 168 | } 169 | 170 | 171 | layer { 172 | name: "conv5" 173 | type: "InnerProduct" 174 | bottom: "conv4" 175 | top: "conv5" 176 | param { 177 | lr_mult: 1 178 | decay_mult: 1 179 | } 180 | param { 181 | lr_mult: 2 182 | decay_mult: 1 183 | } 184 | inner_product_param { 185 | #kernel_size: 3 186 | num_output: 256 187 | weight_filler { 188 | type: "xavier" 189 | } 190 | bias_filler { 191 | type: "constant" 192 | value: 0 193 | } 194 | } 195 | } 196 | 197 | layer { 198 | name: "drop5" 199 | type: "Dropout" 200 | bottom: "conv5" 201 | top: "conv5" 202 | dropout_param { 203 | dropout_ratio: 0.25 204 | } 205 | } 206 | layer { 207 | name: "prelu5" 208 | type: "PReLU" 209 | bottom: "conv5" 210 | top: "conv5" 211 | } 212 | 213 | 214 | layer { 215 | name: "conv6-1" 216 | type: "InnerProduct" 217 | bottom: "conv5" 218 | top: "conv6-1" 219 | param { 220 | lr_mult: 1 221 | decay_mult: 1 222 | } 223 | param { 224 | lr_mult: 2 225 | decay_mult: 1 226 | } 227 | inner_product_param { 228 | #kernel_size: 1 229 | num_output: 2 230 | weight_filler { 231 | type: "xavier" 232 | } 233 | bias_filler { 234 | type: "constant" 235 | value: 0 236 | } 237 | } 238 | } 239 | layer { 240 | name: "conv6-2" 241 | type: "InnerProduct" 242 | bottom: "conv5" 243 | top: "conv6-2" 244 | param { 245 | lr_mult: 1 246 | decay_mult: 1 247 | } 248 | param { 249 | lr_mult: 2 250 | decay_mult: 1 251 | } 252 | inner_product_param { 253 | #kernel_size: 1 254 | num_output: 4 255 | weight_filler { 256 | type: "xavier" 257 | } 258 | bias_filler { 259 | type: "constant" 260 | value: 0 261 | } 262 | } 263 | } 264 | layer { 265 | name: "conv6-3" 266 | type: "InnerProduct" 267 | bottom: "conv5" 268 | top: "conv6-3" 269 | param { 270 | lr_mult: 1 271 | decay_mult: 1 272 | } 273 | param { 274 | lr_mult: 2 275 | decay_mult: 1 276 | } 277 | inner_product_param { 278 | #kernel_size: 1 279 | num_output: 10 280 | weight_filler { 281 | type: "xavier" 282 | } 283 | bias_filler { 284 | type: "constant" 285 | value: 0 286 | } 287 | } 288 | } 289 | layer { 290 | name: "prob1" 291 | type: "Softmax" 292 | bottom: "conv6-1" 293 | top: "prob1" 294 | } 295 | -------------------------------------------------------------------------------- /mtcnn/file.txt: -------------------------------------------------------------------------------- 1 | /home/duino/project/iactive/mtcnn/mtcnn/positive/2.jpg 2 | /home/duino/project/iactive/mtcnn/mtcnn/positive/4.jpg 3 | /home/duino/project/iactive/mtcnn/mtcnn/positive/5.jpg 4 | /home/duino/project/iactive/mtcnn/mtcnn/positive/6.jpg 5 | /home/duino/project/iactive/mtcnn/mtcnn/positive/7.jpg 6 | /home/duino/project/iactive/mtcnn/mtcnn/positive/8.jpg 7 | /home/duino/project/iactive/mtcnn/mtcnn/positive/22.jpg 8 | /home/duino/project/iactive/mtcnn/mtcnn/positive/23.jpg 9 | /home/duino/project/iactive/mtcnn/mtcnn/positive/24.jpg 10 | /home/duino/project/iactive/mtcnn/mtcnn/positive/25.jpg 11 | /home/duino/project/iactive/mtcnn/mtcnn/positive/26.jpg 12 | /home/duino/project/iactive/mtcnn/mtcnn/positive/28.jpg 13 | /home/duino/project/iactive/mtcnn/mtcnn/positive/32.jpg 14 | /home/duino/project/iactive/mtcnn/mtcnn/positive/34.jpg 15 | /home/duino/project/iactive/mtcnn/mtcnn/positive/35.jpg 16 | /home/duino/project/iactive/mtcnn/mtcnn/positive/36.jpg 17 | /home/duino/project/iactive/mtcnn/mtcnn/positive/37.jpg 18 | /home/duino/project/iactive/mtcnn/mtcnn/positive/38.jpg 19 | /home/duino/project/iactive/mtcnn/mtcnn/positive/39.jpg 20 | /home/duino/project/iactive/mtcnn/mtcnn/positive/40.jpg 21 | /home/duino/project/iactive/mtcnn/mtcnn/positive/41.jpg 22 | /home/duino/project/iactive/mtcnn/mtcnn/positive/42.jpg 23 | /home/duino/project/iactive/mtcnn/mtcnn/positive/43.jpg 24 | /home/duino/project/iactive/mtcnn/mtcnn/positive/48.jpg 25 | /home/duino/project/iactive/mtcnn/mtcnn/positive/49.jpg 26 | /home/duino/project/iactive/mtcnn/mtcnn/positive/50.jpg 27 | /home/duino/project/iactive/mtcnn/mtcnn/positive/51.jpg 28 | /home/duino/project/iactive/mtcnn/mtcnn/positive/52.jpg 29 | /home/duino/project/iactive/mtcnn/mtcnn/positive/54.jpg 30 | /home/duino/project/iactive/mtcnn/mtcnn/positive/55.jpg 31 | /home/duino/project/iactive/mtcnn/mtcnn/positive/56.jpg 32 | /home/duino/project/iactive/mtcnn/mtcnn/positive/57.jpg 33 | /home/duino/project/iactive/mtcnn/mtcnn/positive/58.jpg 34 | /home/duino/project/iactive/mtcnn/mtcnn/positive/61.jpg 35 | /home/duino/project/iactive/mtcnn/mtcnn/positive/62.jpg 36 | /home/duino/project/iactive/mtcnn/mtcnn/positive/63.jpg 37 | /home/duino/project/iactive/mtcnn/mtcnn/positive/100.jpg 38 | /home/duino/project/iactive/mtcnn/mtcnn/positive/102.jpg 39 | /home/duino/project/iactive/mtcnn/mtcnn/positive/104.jpg 40 | /home/duino/project/iactive/mtcnn/mtcnn/positive/144.jpg 41 | /home/duino/project/iactive/mtcnn/mtcnn/positive/145.jpg 42 | /home/duino/project/iactive/mtcnn/mtcnn/positive/146.jpg 43 | /home/duino/project/iactive/mtcnn/mtcnn/positive/147.jpg 44 | /home/duino/project/iactive/mtcnn/mtcnn/positive/148.jpg 45 | /home/duino/project/iactive/mtcnn/mtcnn/positive/150.jpg 46 | /home/duino/project/iactive/mtcnn/mtcnn/positive/151.jpg 47 | /home/duino/project/iactive/mtcnn/mtcnn/positive/153.jpg 48 | /home/duino/project/iactive/mtcnn/mtcnn/positive/154.jpg 49 | /home/duino/project/iactive/mtcnn/mtcnn/positive/155.jpg 50 | /home/duino/project/iactive/mtcnn/mtcnn/positive/156.jpg 51 | /home/duino/project/iactive/mtcnn/mtcnn/positive/157.jpg 52 | /home/duino/project/iactive/mtcnn/mtcnn/positive/159.jpg 53 | /home/duino/project/iactive/mtcnn/mtcnn/positive/165.jpg 54 | /home/duino/project/iactive/mtcnn/mtcnn/positive/166.jpg 55 | /home/duino/project/iactive/mtcnn/mtcnn/positive/167.jpg 56 | /home/duino/project/iactive/mtcnn/mtcnn/positive/168.jpg 57 | /home/duino/project/iactive/mtcnn/mtcnn/positive/171.jpg 58 | /home/duino/project/iactive/mtcnn/mtcnn/positive/172.jpg 59 | /home/duino/project/iactive/mtcnn/mtcnn/positive/173.jpg 60 | /home/duino/project/iactive/mtcnn/mtcnn/positive/174.jpg 61 | /home/duino/project/iactive/mtcnn/mtcnn/positive/175.jpg 62 | /home/duino/project/iactive/mtcnn/mtcnn/positive/183.jpg 63 | /home/duino/project/iactive/mtcnn/mtcnn/positive/184.jpg 64 | /home/duino/project/iactive/mtcnn/mtcnn/positive/185.jpg 65 | /home/duino/project/iactive/mtcnn/mtcnn/positive/186.jpg 66 | /home/duino/project/iactive/mtcnn/mtcnn/positive/235.jpg 67 | /home/duino/project/iactive/mtcnn/mtcnn/positive/236.jpg 68 | /home/duino/project/iactive/mtcnn/mtcnn/positive/237.jpg 69 | /home/duino/project/iactive/mtcnn/mtcnn/positive/238.jpg 70 | /home/duino/project/iactive/mtcnn/mtcnn/positive/239.jpg 71 | /home/duino/project/iactive/mtcnn/mtcnn/positive/240.jpg 72 | /home/duino/project/iactive/mtcnn/mtcnn/positive/241.jpg 73 | /home/duino/project/iactive/mtcnn/mtcnn/positive/242.jpg 74 | /home/duino/project/iactive/mtcnn/mtcnn/positive/243.jpg 75 | /home/duino/project/iactive/mtcnn/mtcnn/positive/244.jpg 76 | /home/duino/project/iactive/mtcnn/mtcnn/positive/287.jpg 77 | /home/duino/project/iactive/mtcnn/mtcnn/positive/288.jpg 78 | /home/duino/project/iactive/mtcnn/mtcnn/positive/289.jpg 79 | /home/duino/project/iactive/mtcnn/mtcnn/positive/290.jpg 80 | /home/duino/project/iactive/mtcnn/mtcnn/positive/291.jpg 81 | /home/duino/project/iactive/mtcnn/mtcnn/positive/293.jpg 82 | /home/duino/project/iactive/mtcnn/mtcnn/positive/295.jpg 83 | /home/duino/project/iactive/mtcnn/mtcnn/positive/297.jpg 84 | /home/duino/project/iactive/mtcnn/mtcnn/positive/312.jpg 85 | /home/duino/project/iactive/mtcnn/mtcnn/positive/314.jpg 86 | /home/duino/project/iactive/mtcnn/mtcnn/positive/316.jpg 87 | /home/duino/project/iactive/mtcnn/mtcnn/positive/318.jpg 88 | /home/duino/project/iactive/mtcnn/mtcnn/positive/320.jpg 89 | /home/duino/project/iactive/mtcnn/mtcnn/positive/321.jpg 90 | /home/duino/project/iactive/mtcnn/mtcnn/positive/322.jpg 91 | /home/duino/project/iactive/mtcnn/mtcnn/positive/323.jpg 92 | /home/duino/project/iactive/mtcnn/mtcnn/positive/324.jpg 93 | /home/duino/project/iactive/mtcnn/mtcnn/positive/325.jpg 94 | /home/duino/project/iactive/mtcnn/mtcnn/positive/332.jpg 95 | /home/duino/project/iactive/mtcnn/mtcnn/positive/333.jpg 96 | /home/duino/project/iactive/mtcnn/mtcnn/positive/334.jpg 97 | /home/duino/project/iactive/mtcnn/mtcnn/positive/335.jpg 98 | /home/duino/project/iactive/mtcnn/mtcnn/positive/336.jpg 99 | /home/duino/project/iactive/mtcnn/mtcnn/positive/337.jpg 100 | /home/duino/project/iactive/mtcnn/mtcnn/positive/339.jpg 101 | /home/duino/project/iactive/mtcnn/mtcnn/positive/340.jpg 102 | /home/duino/project/iactive/mtcnn/mtcnn/positive/342.jpg 103 | /home/duino/project/iactive/mtcnn/mtcnn/positive/343.jpg 104 | /home/duino/project/iactive/mtcnn/mtcnn/positive/344.jpg 105 | /home/duino/project/iactive/mtcnn/mtcnn/positive/345.jpg 106 | /home/duino/project/iactive/mtcnn/mtcnn/positive/346.jpg 107 | /home/duino/project/iactive/mtcnn/mtcnn/positive/347.jpg 108 | /home/duino/project/iactive/mtcnn/mtcnn/positive/368.jpg 109 | /home/duino/project/iactive/mtcnn/mtcnn/positive/387.jpg 110 | /home/duino/project/iactive/mtcnn/mtcnn/positive/388.jpg 111 | /home/duino/project/iactive/mtcnn/mtcnn/positive/389.jpg 112 | /home/duino/project/iactive/mtcnn/mtcnn/positive/390.jpg 113 | /home/duino/project/iactive/mtcnn/mtcnn/positive/391.jpg 114 | /home/duino/project/iactive/mtcnn/mtcnn/positive/392.jpg 115 | /home/duino/project/iactive/mtcnn/mtcnn/positive/393.jpg 116 | /home/duino/project/iactive/mtcnn/mtcnn/positive/394.jpg 117 | /home/duino/project/iactive/mtcnn/mtcnn/positive/395.jpg 118 | /home/duino/project/iactive/mtcnn/mtcnn/positive/396.jpg 119 | /home/duino/project/iactive/mtcnn/mtcnn/positive/402.jpg 120 | /home/duino/project/iactive/mtcnn/mtcnn/positive/403.jpg 121 | /home/duino/project/iactive/mtcnn/mtcnn/positive/404.jpg 122 | /home/duino/project/iactive/mtcnn/mtcnn/positive/405.jpg 123 | /home/duino/project/iactive/mtcnn/mtcnn/positive/406.jpg 124 | /home/duino/project/iactive/mtcnn/mtcnn/positive/407.jpg 125 | /home/duino/project/iactive/mtcnn/mtcnn/positive/482.jpg 126 | /home/duino/project/iactive/mtcnn/mtcnn/positive/483.jpg 127 | -------------------------------------------------------------------------------- /test_utility.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "utility.hpp" 4 | #include 5 | 6 | void loadFromFile(string filename, MatrixXd& X) 7 | { 8 | ifstream fin(filename); 9 | if (fin.is_open()){ 10 | for (int row = 0; row < X.rows(); row++) 11 | for (int col = 0; col < X.cols(); col++){ 12 | double item = 0.0; 13 | fin >> item; 14 | X(row, col) = item; 15 | } 16 | fin.close(); 17 | } 18 | } 19 | 20 | TEST(bbreg, test_bbreg) 21 | { 22 | MatrixXd total_boxes; 23 | total_boxes.resize(2, 5); 24 | total_boxes << 205, 73, 400, 268, 0.98384535, 25 | 209, 101, 367, 259, 0.97880608; 26 | MatrixXd mv; 27 | mv.resize(4, 2); 28 | mv << -0.04941138, -0.07724266, 29 | 0.0447434, -0.08641055, 30 | -0.28392452, -0.1872426, 31 | 0.03337108, 0.05036401; 32 | MatrixXd mv_t; 33 | mv_t.resize(2,4); 34 | mv_t = mv.transpose(); 35 | Matrix boxes_p; 36 | boxes_p << 195.31536902, 81.76970568, 344.35079408, 274.54073162, 0.98384535, 37 | 196.71841745, 87.26072219, 337.2284270, 267.00787819, 0.97880608; 38 | 39 | bbreg(total_boxes, mv_t); // how to use reference here? 40 | for (int i = 0; i < total_boxes.size(); i++){ 41 | EXPECT_EQ((int)total_boxes(i), (int)boxes_p(i)); 42 | } 43 | } 44 | 45 | TEST(pad, test_pad) 46 | { 47 | MatrixXd total_boxes; 48 | total_boxes.resize(78, 5); 49 | total_boxes << 50 | 208, 100, 397, 289, 0.99878901, 51 | 198, 76, 374, 252, 0.99813914, 52 | 201, 62, 418, 280, 0.99703938, 53 | 235, 275, 321, 362, 0.99665654, 54 | 232, 189, 311, 268, 0.9940117 , 55 | 194, 129, 300, 235, 0.99173576, 56 | 236, 294, 324, 381, 0.98405713, 57 | 179, 88, 215, 124, 0.97458196, 58 | 209, 101, 367, 259, 0.95965761, 59 | 329, 104, 381, 157, 0.95791584, 60 | 180, 89, 209, 118, 0.9525429 , 61 | 194, 146, 272, 225, 0.94582903, 62 | 205, 73, 400, 268, 0.94088584, 63 | 242, 272, 285, 315, 0.93917483, 64 | 191, 151, 244, 205, 0.93878382, 65 | 245, 342, 276, 373, 0.9339292 , 66 | 274, 133, 295, 154, 0.9336105 , 67 | 188, 90, 217, 119, 0.93259424, 68 | 185, 90, 228, 133, 0.92992473, 69 | 198, 169, 241, 211, 0.92471832, 70 | 244, 337, 286, 379, 0.92156881, 71 | 211, 91, 336, 216, 0.92082781, 72 | 241, 272, 294, 326, 0.91642487, 73 | 288, 128, 350, 189, 0.91266102, 74 | 243, 195, 303, 256, 0.89758235, 75 | 189, 93, 211, 114, 0.89502412, 76 | 241, 118, 359, 236, 0.89381135, 77 | 177, 80, 228, 130, 0.86884165, 78 | 199, 148, 239, 187, 0.8607381 , 79 | 247, 280, 280, 314, 0.85781771, 80 | 249, 345, 275, 372, 0.84510684, 81 | 263, 230, 297, 264, 0.83451498, 82 | 241, 212, 300, 272, 0.82687539, 83 | 356, 163, 376, 184, 0.82662463, 84 | 257, 96, 390, 230, 0.81952786, 85 | 190, 96, 337, 242, 0.81833953, 86 | 247, 225, 295, 273, 0.81787145, 87 | 238, 192, 322, 276, 0.80674833, 88 | 250, 143, 271, 163, 0.80595565, 89 | 242, 331, 306, 395, 0.79729331, 90 | 232, 134, 294, 196, 0.78863966, 91 | 198, 64, 348, 214, 0.77796942, 92 | 254, 128, 285, 159, 0.77550071, 93 | 184, 102, 314, 232, 0.76476622, 94 | 339, 108, 377, 146, 0.76366198, 95 | 351, 136, 376, 161, 0.76115662, 96 | 202, 160, 236, 194, 0.74090749, 97 | 245, 346, 266, 368, 0.73505855, 98 | 246, 344, 279, 377, 0.73426574, 99 | 244, 119, 269, 144, 0.73202336, 100 | 235, 210, 266, 242, 0.72657281, 101 | 239, 119, 320, 200, 0.71822059, 102 | 245, 114, 286, 155, 0.71781677, 103 | 274, 127, 296, 149, 0.70513207, 104 | 357, 168, 381, 191, 0.7014606 , 105 | 214, 89, 383, 258, 0.70063466, 106 | 228, 140, 251, 163, 0.69477326, 107 | 266, 236, 291, 261, 0.68138945, 108 | 243, 300, 305, 362, 0.67958665, 109 | 185, 94, 205, 114, 0.67336899, 110 | 258, 49, 319, 110, 0.66758376, 111 | 120, 253, 141, 274, 0.66458988, 112 | 198, 92, 221, 115, 0.66407984, 113 | 353, 114, 376, 136, 0.65923673, 114 | 352, 132, 374, 154, 0.65844285, 115 | 201, 158, 239, 196, 0.64497852, 116 | 197, 147, 227, 177, 0.64341497, 117 | 227, 263, 287, 323, 0.63035291, 118 | 244, 220, 264, 240, 0.62759042, 119 | 261, 129, 293, 161, 0.6267885 , 120 | 271, 201, 303, 233, 0.62397933, 121 | 232, 255, 257, 280, 0.62166524, 122 | 197, 172, 245, 220, 0.62008858, 123 | 349, 114, 378, 143, 0.61586976, 124 | 353, 144, 375, 166, 0.6087805 , 125 | 190, 124, 274, 208, 0.60719299, 126 | 212, 146, 234, 168, 0.60466552, 127 | 343, 109, 380, 146, 0.60001802; 128 | double w = 450; 129 | double h = 431; 130 | 131 | Matrix dy, edy, dx, edx, y, ey, x, ex, tmpw, tmph; 132 | dy << 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 133 | dx << 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 134 | y << 99, 75, 61, 274, 188, 128, 293, 87, 100, 103, 88, 145, 72, 271, 150, 341, 132, 89, 89, 168, 336, 90, 271, 127, 194, 92, 117, 79, 147, 279, 344, 229, 211, 162, 95, 95, 224, 191, 142, 330, 133, 63, 127, 101, 107, 135, 159, 345, 343, 118, 209, 118, 113, 126, 167, 88, 139, 235, 299, 93, 48, 252, 91, 113, 131, 157, 146, 262, 219, 128, 200, 254, 171, 113, 143, 123, 145, 108; 135 | x << 207, 197, 200, 234, 231, 193, 235, 178, 208, 328, 179, 193, 204, 241, 190, 244, 273, 187, 184, 197, 243, 210, 240, 287, 242, 188, 240, 176, 198, 246, 248, 262, 240, 355, 256, 189, 246, 237, 249, 241, 231, 197, 253, 183, 338, 350, 201, 244, 245, 243, 234, 238, 244, 273, 356, 213, 227, 265, 242, 184, 257, 119, 197, 352, 351, 200, 196, 226, 243, 260, 270, 231, 196, 348, 352, 189, 211, 342; 136 | edy << 189, 176, 218, 87, 79, 106, 87, 36, 158, 53, 29, 79, 195, 43, 54, 31, 21, 29, 43, 42, 42, 125, 54, 61, 61, 21, 118, 50, 39, 34, 27, 34, 60, 21, 134, 146, 48, 84, 20, 64, 62, 150, 31, 130, 38, 25, 34, 22, 33, 25, 32, 81, 41, 22, 23, 169, 23, 25, 62, 20, 61, 21, 23, 22, 22, 38, 30, 60, 20, 32, 32, 25, 48, 29, 22, 84, 22, 37; 137 | edx << 189, 176, 217, 86, 79, 106, 88, 36, 158, 52, 29, 78, 195, 43, 53, 31, 21, 29, 43, 43, 42, 125, 53, 62, 60, 22, 118, 51, 40, 33, 26, 34, 59, 20, 133, 147, 48, 84, 21, 64, 62, 150, 31, 130, 38, 25, 34, 21, 33, 25, 31, 81, 41, 22, 24, 169, 23, 25, 62, 20, 61, 21, 23, 23, 22, 38, 30, 60, 20, 32, 32, 25, 48, 29, 22, 84, 22, 37; 138 | ey << 288, 251, 279, 361, 267, 234, 380, 123, 258, 156, 117, 224, 267, 314, 204, 372, 153, 118, 132, 210, 378, 215, 325, 188, 255, 113, 235, 129, 186, 313, 371, 263, 271, 183, 229, 241, 272, 275, 162, 394, 195, 213, 158, 231, 145, 160, 193, 367, 376, 143, 241, 199, 154, 148, 190, 257, 162, 260, 361, 113, 109, 273, 114, 135, 153, 195, 176, 322, 239, 160, 232, 279, 219, 142, 165, 207, 167, 145; 139 | ex << 396, 373, 417, 320, 310, 299, 323, 214, 366, 380, 208, 271, 399, 284, 243, 275, 294, 216, 227, 240, 285, 335, 293, 349, 302, 210, 358, 227, 238, 279, 274, 296, 299, 375, 389, 336, 294, 321, 270, 305, 293, 347, 284, 313, 376, 375, 235, 265, 278, 268, 265, 319, 285, 295, 380, 382, 250, 290, 304, 204, 318, 140, 220, 375, 373, 238, 226, 286, 263, 292, 302, 256, 244, 377, 374, 273, 233, 379; 140 | tmpw << 190, 177, 218, 87, 80, 107, 89, 37, 159, 53, 30, 79, 196, 44, 54, 32, 22, 30, 44, 44, 43, 126, 54, 63, 61, 23, 119, 52, 41, 34, 27, 35, 60, 21, 134, 148, 49, 85, 22, 65, 63, 151, 32, 131, 39, 26, 35, 22, 34, 26, 32, 82, 42, 23, 25, 170, 24, 26, 63, 21, 62, 22, 24, 24, 23, 39, 31, 61, 21, 33, 33, 26, 49, 30, 23, 85, 23, 38; 141 | tmph << 190, 177, 219, 88, 80, 107, 88, 37, 159, 54, 30, 80, 196, 44, 55, 32, 22, 30, 44, 43, 43, 126, 55, 62, 62, 22, 119, 51, 40, 35, 28, 35, 61, 22, 135, 147, 49, 85, 21, 65, 63, 151, 32, 131, 39, 26, 35, 23, 34, 26, 33, 82, 42, 23, 24, 170, 24, 26, 63, 21, 62, 22, 24, 23, 23, 39, 31, 61, 21, 33, 33, 26, 49, 30, 23, 85, 23, 38; 142 | 143 | MatrixXd result; 144 | pad(total_boxes, w, h, result); 145 | for (int i = 0; i < result.rows(); i++){ 146 | EXPECT_EQ((int)result(i, 0) , (int)dy(i,0)); 147 | EXPECT_EQ((int)result(i, 1) , (int)edy(i,0)); 148 | EXPECT_EQ((int)result(i, 2) , (int)dx(i,0)); 149 | EXPECT_EQ((int)result(i, 3) , (int)edx(i,0)); 150 | EXPECT_EQ((int)result(i, 4) , (int)y(i,0)); 151 | EXPECT_EQ((int)result(i, 5) , (int)ey(i,0)); 152 | EXPECT_EQ((int)result(i, 6) , (int)x(i,0)); 153 | EXPECT_EQ((int)result(i, 7) , (int)ex(i,0)); 154 | EXPECT_EQ((int)result(i, 8) , (int)tmpw(i,0)); 155 | EXPECT_EQ((int)result(i, 9) , (int)tmph(i,0)); 156 | } 157 | } 158 | 159 | TEST(rerec, test_rerec) 160 | { 161 | MatrixXd total_boxes; 162 | total_boxes.resize(5, 5); 163 | total_boxes << 164 | 230.07784033, 100.35094793, 375.76201081, 289.35045105, 0.99878901, 165 | 217.63145834, 76.52293204, 355.90327752, 252.88063219, 0.99813914, 166 | 219.13960473, 62.8926762, 400.67869663, 280.61021234, 0.99703938, 167 | 246.17034657, 275.92842653, 311.22883457, 362.11322095, 0.99665654, 168 | 238.78208129, 189.81249212, 304.58434872, 268.79625906, 0.9940117; 169 | Matrix out; 170 | out << 171 | 208.42017401, 100.35094793, 397.41967713, 289.35045105, 0.99878901, 172 | 198.58851785, 76.52293204, 374.94621801, 252.88063219, 0.99813914, 173 | 201.05038261, 62.8926762, 418.76791875, 280.61021234, 0.99703938, 174 | 235.60719337, 275.92842653, 321.79198778, 362.11322095, 0.99665654, 175 | 232.19133154, 189.81249212, 311.17509848, 268.79625906, 0.9940117; 176 | rerec(total_boxes); 177 | for (int i = 0; i < total_boxes.size(); i++){ 178 | EXPECT_EQ((int)total_boxes(i) , (int)out(i)); 179 | } 180 | } 181 | 182 | TEST(generateBoxes, test_generateBoxes) 183 | { 184 | MatrixXd map = MatrixXd::Zero(130, 125); 185 | string filePath("/home/duino/project/iactive/mtcnn/"); 186 | loadFromFile(filePath+"test_data/map.out", map); 187 | MatrixXd reg0 = MatrixXd::Zero(130, 125); 188 | MatrixXd reg1 = MatrixXd::Zero(130, 125); 189 | MatrixXd reg2 = MatrixXd::Zero(130, 125); 190 | MatrixXd reg3 = MatrixXd::Zero(130, 125); 191 | loadFromFile(filePath+"test_data/reg0.out", reg0); 192 | loadFromFile(filePath+"test_data/reg1.out", reg1); 193 | loadFromFile(filePath+"test_data/reg2.out", reg2); 194 | loadFromFile(filePath+"test_data/reg3.out", reg3); 195 | vector reg; 196 | reg.push_back(reg0); 197 | reg.push_back(reg1); 198 | reg.push_back(reg2); 199 | reg.push_back(reg3); 200 | MatrixXd boxes = MatrixXd::Zero(32, 9); 201 | loadFromFile(filePath+"test_data/boxes.out", boxes); 202 | 203 | double scale = 0.6; 204 | double threshold = 0.6; 205 | MatrixXd out; 206 | generateBoundingBox(map, reg, scale, threshold, out); 207 | EXPECT_EQ(boxes.rows() , out.rows()); 208 | EXPECT_EQ(boxes.cols() , out.cols()); 209 | 210 | for (int i = 0; i < boxes.size(); i++){ 211 | EXPECT_EQ(boxes(i) , out(i)); 212 | } 213 | } 214 | 215 | TEST(drawBoxes, test_drawBoxes) 216 | { 217 | string filePath("/home/duino/project/iactive/mtcnn/"); 218 | Mat im = imread(filePath+"test_data/test.jpg"); 219 | MatrixXd boxes; 220 | boxes.resize(3, 4); 221 | boxes << 10, 10, 20, 20, 222 | 20, 20, 40, 40, 223 | 60, 60, 100, 100; 224 | drawBoxes(im, boxes); 225 | //imshow("drawBoxes test", im); 226 | //waitKey(0); 227 | } 228 | 229 | int main(int args, char *argv[]) 230 | { 231 | testing::InitGoogleTest(&args, argv); 232 | return RUN_ALL_TESTS(); 233 | } 234 | -------------------------------------------------------------------------------- /mtcnn.pro.user: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | EnvironmentId 7 | {85f7e32f-10f6-497a-82b1-80b39b2e6512} 8 | 9 | 10 | ProjectExplorer.Project.ActiveTarget 11 | 0 12 | 13 | 14 | ProjectExplorer.Project.EditorSettings 15 | 16 | true 17 | false 18 | true 19 | 20 | Cpp 21 | 22 | CppGlobal 23 | 24 | 25 | 26 | QmlJS 27 | 28 | QmlJSGlobal 29 | 30 | 31 | 2 32 | UTF-8 33 | false 34 | 4 35 | false 36 | 80 37 | true 38 | true 39 | 1 40 | true 41 | false 42 | 0 43 | true 44 | 0 45 | 8 46 | true 47 | 1 48 | true 49 | true 50 | true 51 | false 52 | 53 | 54 | 55 | ProjectExplorer.Project.PluginSettings 56 | 57 | 58 | 59 | ProjectExplorer.Project.Target.0 60 | 61 | Desktop Qt 5.6.0 MSVC2013 64bit 62 | Desktop Qt 5.6.0 MSVC2013 64bit 63 | qt.56.win64_msvc2013_64_kit 64 | 0 65 | 0 66 | 0 67 | 68 | H:/project/qt/build-mtcnn-Desktop_Qt_5_6_0_MSVC2013_64bit-Debug 69 | 70 | 71 | true 72 | qmake 73 | 74 | QtProjectManager.QMakeBuildStep 75 | true 76 | 77 | false 78 | false 79 | false 80 | 81 | 82 | true 83 | Make 84 | 85 | Qt4ProjectManager.MakeStep 86 | 87 | false 88 | 89 | 90 | 91 | 2 92 | 构建 93 | 94 | ProjectExplorer.BuildSteps.Build 95 | 96 | 97 | 98 | true 99 | Make 100 | 101 | Qt4ProjectManager.MakeStep 102 | 103 | true 104 | clean 105 | 106 | 107 | 1 108 | 清理 109 | 110 | ProjectExplorer.BuildSteps.Clean 111 | 112 | 2 113 | false 114 | 115 | Debug 116 | 117 | Qt4ProjectManager.Qt4BuildConfiguration 118 | 2 119 | true 120 | 121 | 122 | H:/project/qt/build-mtcnn-Desktop_Qt_5_6_0_MSVC2013_64bit-Release 123 | 124 | 125 | true 126 | qmake 127 | 128 | QtProjectManager.QMakeBuildStep 129 | false 130 | 131 | false 132 | false 133 | false 134 | 135 | 136 | true 137 | Make 138 | 139 | Qt4ProjectManager.MakeStep 140 | 141 | false 142 | 143 | 144 | 145 | 2 146 | 构建 147 | 148 | ProjectExplorer.BuildSteps.Build 149 | 150 | 151 | 152 | true 153 | Make 154 | 155 | Qt4ProjectManager.MakeStep 156 | 157 | true 158 | clean 159 | 160 | 161 | 1 162 | 清理 163 | 164 | ProjectExplorer.BuildSteps.Clean 165 | 166 | 2 167 | false 168 | 169 | Release 170 | 171 | Qt4ProjectManager.Qt4BuildConfiguration 172 | 0 173 | true 174 | 175 | 2 176 | 177 | 178 | 0 179 | 部署 180 | 181 | ProjectExplorer.BuildSteps.Deploy 182 | 183 | 1 184 | 在本地部署 185 | 186 | ProjectExplorer.DefaultDeployConfiguration 187 | 188 | 1 189 | 190 | 191 | false 192 | 1000 193 | 194 | true 195 | 196 | false 197 | false 198 | false 199 | false 200 | true 201 | 0.01 202 | 10 203 | true 204 | 1 205 | 25 206 | 207 | 1 208 | true 209 | false 210 | true 211 | valgrind 212 | 213 | 0 214 | 1 215 | 2 216 | 3 217 | 4 218 | 5 219 | 6 220 | 7 221 | 8 222 | 9 223 | 10 224 | 11 225 | 12 226 | 13 227 | 14 228 | 229 | 2 230 | 231 | mtcnn 232 | 233 | Qt4ProjectManager.Qt4RunConfiguration:H:/project/qt/mtcnn_cpp/mtcnn.pro 234 | true 235 | H:/project/qt/mtcnn_cpp/mtcnn/model 236 | mtcnn.pro 237 | false 238 | false 239 | 240 | 3768 241 | false 242 | true 243 | false 244 | false 245 | true 246 | 247 | 1 248 | 249 | 250 | 251 | ProjectExplorer.Project.TargetCount 252 | 1 253 | 254 | 255 | ProjectExplorer.Project.Updater.FileVersion 256 | 18 257 | 258 | 259 | Version 260 | 18 261 | 262 | 263 | -------------------------------------------------------------------------------- /utility.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _UTILITY_HPP 2 | #define _UTILITY_HPP 3 | 4 | #define CPU_ONLY 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | #include "eigenplus.h" 21 | #include "caffeplus.h" 22 | #include "nms.h" 23 | 24 | using namespace std; 25 | using namespace Eigen; 26 | using namespace cv; 27 | 28 | void bbreg(MatrixXd &boundingbox, MatrixXd ®) 29 | { 30 | assert(boundingbox.cols() == 5); 31 | assert(reg.cols() == 4); 32 | assert(boundingbox.rows() == reg.rows()); 33 | 34 | cout << "bb.rows:" << boundingbox.rows() << endl; 35 | cout << "reg.rows:" << reg.rows() << endl; 36 | 37 | if (reg.rows() == 1){ 38 | cout << "reg.rows == 1" << endl; 39 | } 40 | int numOfBB = boundingbox.rows(); 41 | Matrix w = boundingbox.col(2).cast() - boundingbox.col(0).cast() + MatrixXd::Ones(numOfBB, 1); 42 | Matrix h = boundingbox.col(3).cast() - boundingbox.col(1).cast() + MatrixXd::Ones(numOfBB, 1); 43 | boundingbox.col(0) += w.cwiseProduct(reg.col(0)); 44 | boundingbox.col(1) += h.cwiseProduct(reg.col(1)); 45 | boundingbox.col(2) += w.cwiseProduct(reg.col(2)); 46 | boundingbox.col(3) += h.cwiseProduct(reg.col(3)); 47 | } 48 | 49 | void pad(MatrixXd &boundingbox, double w, double h, MatrixXd &result) 50 | { 51 | assert(boundingbox.cols() == 5); 52 | 53 | int numOfBB = boundingbox.rows(); 54 | result.resize(numOfBB, 10); 55 | 56 | Matrix tmpw = boundingbox.col(2).cast() - boundingbox.col(0).cast() + MatrixXd::Ones(numOfBB, 1); 57 | Matrix tmph = boundingbox.col(3).cast() - boundingbox.col(1).cast() + MatrixXd::Ones(numOfBB, 1); 58 | MatrixXd dx = MatrixXd::Ones(numOfBB, 1); 59 | MatrixXd dy = MatrixXd::Ones(numOfBB, 1); 60 | Matrix edx = tmpw.replicate(1, 1); 61 | Matrix edy = tmph.replicate(1, 1); 62 | 63 | auto x = MatrixXd(boundingbox.col(0)); 64 | auto y = MatrixXd(boundingbox.col(1)); 65 | auto ex = MatrixXd(boundingbox.col(2)); 66 | auto ey = MatrixXd(boundingbox.col(3)); 67 | 68 | MatrixXd w_matrix; 69 | w_matrix.resize(ex.rows(), ex.cols()); 70 | w_matrix.fill(w); 71 | VectorXi tmp = _find(ex, w_matrix); 72 | 73 | for (int i = 0; i < tmp.size(); i++){ 74 | int j = tmp(i); 75 | edx(j) = -ex(j) + w - 1 + tmpw(j); 76 | ex(j) = w - 1; 77 | } 78 | 79 | MatrixXd h_matrix; 80 | h_matrix.resize(ey.rows(), ey.cols()); 81 | h_matrix.fill(h); 82 | tmp = _find(ey, h_matrix); 83 | for (int i = 0; i < tmp.size(); i++){ 84 | int j = tmp(i); 85 | edy(j) = -ey(j) + h - 1 + tmph(j); 86 | ey(j) = h - 1; 87 | } 88 | 89 | MatrixXd one_matrix = MatrixXd::Ones(x.rows(), x.cols()); 90 | tmp = _find(one_matrix, x); 91 | for (int i = 0; i < tmp.size(); i++){ 92 | int j = tmp(i); 93 | dx(j) = 2 - x(j); 94 | x(j) = 1; 95 | } 96 | 97 | tmp = _find(one_matrix, y); 98 | for (int i = 0; i < tmp.size(); i++){ 99 | int j = tmp(i); 100 | dy(j) = 2 - y(j); 101 | y(j) = 1; 102 | } 103 | dy -= MatrixXd::Ones(dy.rows(), dy.cols()); 104 | edy -= MatrixXd::Ones(dy.rows(), dy.cols()); 105 | dx -= MatrixXd::Ones(dy.rows(), dy.cols()); 106 | edx -= MatrixXd::Ones(dy.rows(), dy.cols()); 107 | y -= MatrixXd::Ones(dy.rows(), dy.cols()); 108 | ey -= MatrixXd::Ones(dy.rows(), dy.cols()); 109 | x -= MatrixXd::Ones(dy.rows(), dy.cols()); 110 | ex -= MatrixXd::Ones(dy.rows(), dy.cols()); 111 | 112 | result << dy, edy, dx, edx, y, ey, x, ex, tmpw, tmph; 113 | } 114 | 115 | void rerec(MatrixXd &boundingbox) 116 | { 117 | assert(boundingbox.cols() == 5); 118 | 119 | auto w = MatrixXd(boundingbox.col(2) - boundingbox.col(0)); 120 | auto h = MatrixXd(boundingbox.col(3) - boundingbox.col(1)); 121 | auto l = w.cwiseMax(h); 122 | boundingbox.col(0) += w*0.5 - l*0.5; 123 | boundingbox.col(1) += h*0.5 - l*0.5; 124 | MatrixXd ll; 125 | ll.resize(l.rows(), l.cols() * 2); 126 | ll << l, l; 127 | boundingbox.middleCols(2, 2) = boundingbox.middleCols(0, 2) + ll; 128 | } 129 | 130 | void generateBoundingBox(MatrixXd &map, vector ®, double scale, double threshold, MatrixXd &boxes) 131 | { 132 | assert(reg.size() == 4); 133 | 134 | int stride = 2; 135 | int cellsize = 12; 136 | 137 | MatrixXd threshold_matrix = MatrixXd(map.rows(), map.cols()); 138 | threshold_matrix.fill(threshold); 139 | map -= threshold_matrix; 140 | map = map.cwiseMax(MatrixXd::Zero(map.rows(), map.cols())); 141 | MatrixXd I, J, V; 142 | igl::find(map, I, J, V); // I,J is index, V is value. They are all vectors 143 | 144 | // score 145 | threshold_matrix.resize(V.size(), 1); 146 | threshold_matrix.fill(threshold); 147 | MatrixXd score = V + threshold_matrix; 148 | 149 | // reg 150 | MatrixXd new_reg; 151 | new_reg.resize(I.size(), 4); 152 | for (int i = 0; i < 4; i++){ 153 | MatrixXd content = MatrixXd::Zero(I.size(), 1); 154 | for (int num = 0; num < I.size(); num++){ 155 | content(num) = reg[i](I(num), J(num)); 156 | } 157 | new_reg.middleCols(i,1) = content; 158 | } 159 | 160 | // boundingbox 161 | MatrixXd boundingbox; 162 | boundingbox.resize(I.size(), 2); 163 | boundingbox << I, J; 164 | 165 | MatrixXd cellsize_m = MatrixXd::Zero(boundingbox.rows(), boundingbox.cols()); 166 | cellsize_m.fill(cellsize); 167 | 168 | MatrixXd bb1 = (stride * boundingbox + MatrixXd::Ones(boundingbox.rows(), boundingbox.cols())) / scale; 169 | MatrixXd bb2 = (stride * boundingbox + cellsize_m) / scale; 170 | 171 | _fix(bb1); 172 | _fix(bb2); 173 | 174 | assert(bb1.rows() == bb2.rows()); 175 | assert(bb1.rows() == score.rows()); 176 | assert(bb1.rows() == new_reg.rows()); 177 | assert(bb1.cols() == 2); 178 | assert(bb2.cols() == 2); 179 | assert(score.cols() == 1); 180 | assert(new_reg.cols() == 4); 181 | 182 | boxes.resize(bb1.rows(), 9); 183 | boxes << bb1, bb2, score, new_reg; 184 | 185 | //cout << "score:\n"<< score << endl; 186 | //cout << "reg:\n" << new_reg << endl; 187 | //cout << "bb1:\n" << bb1 << endl; 188 | //cout << "bb2:\n" << bb2 << endl; 189 | } 190 | 191 | void drawBoxes(Mat &im, MatrixXd &boxes) 192 | { 193 | for (int i = 0; i < boxes.rows(); i++){ 194 | rectangle(im, Point((int)boxes(i,0), (int)boxes(i,1)), Point((int)boxes(i,2), 195 | (int)boxes(i,3)), Scalar(0,255,0)); 196 | } 197 | } 198 | 199 | void drawBoxes(Mat &im, vector> &boxes) 200 | { 201 | for (int i = 0; i < boxes.size(); i++){ 202 | rectangle(im, Point(boxes[i][0], boxes[i][1]), Point(boxes[i][2], 203 | boxes[i][3]), Scalar(0,255,0)); 204 | } 205 | } 206 | 207 | void _prepareData(shared_ptr>& net, const Mat& img) 208 | { 209 | // 1. reshape data layer 210 | int height = img.rows; 211 | int width = img.cols; 212 | caffe::Blob* input_layer = net->input_blobs()[0]; 213 | input_layer->Reshape(1, 3, height, width); 214 | 215 | // 2. link input data 216 | std::vector input_channels; 217 | float* input_data = input_layer->mutable_cpu_data(); 218 | for (int i = 0; i < input_layer->channels(); ++i) { 219 | cv::Mat channel(height, width, CV_32FC1, input_data); 220 | input_channels.push_back(channel); 221 | input_data += width * height; 222 | } 223 | 224 | // 3. put img to data layer 225 | Mat sample_float; 226 | img.convertTo(sample_float, CV_32FC3); 227 | split(sample_float, input_channels); 228 | CHECK(reinterpret_cast(input_channels.at(0).data) 229 | == net->input_blobs()[0]->cpu_data()) 230 | << "Input channels are not wrapping the input layer of the network."; 231 | } 232 | 233 | void _prepareData2(shared_ptr>& net, const vector& imgs) 234 | { 235 | assert(imgs.size() > 0); 236 | // 1. reshape data layer 237 | int height = imgs[0].rows; 238 | int width = imgs[0].cols; 239 | int numbox = imgs.size(); 240 | caffe::Blob* input_layer = net->input_blobs()[0]; 241 | input_layer->Reshape(numbox, 3, height, width); 242 | 243 | // 1.5 transpose imgs 244 | for (int i = 0; i < numbox; i++){ 245 | 246 | } 247 | 248 | // 2. link input data and put into img data 249 | vector> input_all_imgs; 250 | float* input_data = input_layer->mutable_cpu_data(); 251 | for (int i = 0; i < numbox; i++){ 252 | vector input_channels; 253 | for (int j = 0; j < input_layer->channels(); j++){ 254 | Mat channel(height, width, CV_32FC1, input_data); 255 | input_channels.push_back(channel); 256 | input_data += width * height; 257 | } 258 | split(imgs[i], input_channels); 259 | input_all_imgs.push_back(input_channels); 260 | } 261 | CHECK(reinterpret_cast(input_all_imgs.at(0).at(0).data) 262 | == net->input_blobs()[0]->cpu_data()) 263 | << "Input channels are not wrapping the input layer of the network."; 264 | } 265 | 266 | void _stage1(Mat &img_mat, int minsize, shared_ptr> PNet, 267 | vector &threshold, bool fastresize, float factor, MatrixXd &total_boxes) 268 | { 269 | int factor_count = 0; 270 | int h = img_mat.rows; 271 | int w = img_mat.cols; 272 | int minl = std::min(h, w); 273 | 274 | float m = 12.0 / minsize; 275 | minl *= m; 276 | 277 | // create scale pyramid 278 | vector scales; 279 | while (minl >= 12){ 280 | scales.push_back(m * std::pow(factor, factor_count)); 281 | minl *= factor; 282 | factor_count++; 283 | } 284 | 285 | for (auto scale : scales){ 286 | int hs = (int)std::ceil(h*scale); 287 | int ws = (int)std::ceil(w*scale); 288 | Mat im_data; 289 | img_mat.convertTo(im_data, CV_32FC3); 290 | if (fastresize){ 291 | im_data = (im_data - 127.5) * 0.0078125; 292 | resize(im_data, im_data, Size(ws, hs)); 293 | } 294 | else{ 295 | resize(im_data, im_data, Size(ws, hs)); 296 | im_data = (im_data - 127.5) * 0.0078125; 297 | } 298 | 299 | CHECK_EQ(PNet->num_inputs(), 1) << "Network should have exactly one input."; 300 | CHECK_EQ(PNet->num_outputs(), 2) << "Network should have exactly two output."; 301 | 302 | Mat im_t = Mat(im_data.cols, im_data.rows, CV_32F); 303 | transpose(im_data, im_t); 304 | _prepareData(PNet, im_t); 305 | 306 | //PNet->Forward(); 307 | PNet->ForwardPrefilled(); 308 | 309 | caffe::Blob* conv4_2 = PNet->output_blobs()[0]; // 1*4*height*width 310 | caffe::Blob* prob1 = PNet->output_blobs()[1]; // 1*2*height*width 311 | 312 | //cout << "PNet prob1 height:" << prob1->height() << endl; 313 | //cout << "PNet conv4-2 height:" << conv4_2->height() << endl; 314 | 315 | // debug prob1 316 | //debug_blob(prob1); 317 | //debug_blob(conv4_2); 318 | 319 | MatrixXd map; 320 | vector reg; 321 | convertToMatrix(prob1, conv4_2, map, reg); 322 | MatrixXd boxes; 323 | generateBoundingBox(map, reg, scale, threshold[0], boxes); 324 | 325 | if (boxes.rows() > 0){ 326 | vector pick; 327 | nms(boxes, 0.5, "Union", pick); 328 | if (pick.size() > 0){ 329 | _select(boxes, boxes, pick); 330 | } 331 | } 332 | 333 | MatrixXd t(total_boxes.rows() + boxes.rows(), boxes.cols()); 334 | t << total_boxes, 335 | boxes; 336 | total_boxes.resize(t.rows(), t.cols()); 337 | total_boxes << t; 338 | } 339 | } 340 | 341 | void _stage2(Mat &img_mat, shared_ptr> RNet, 342 | vector &threshold, MatrixXd &total_boxes) 343 | { 344 | Mat im_data; 345 | img_mat.convertTo(im_data, CV_32FC3); 346 | 347 | vector pick; 348 | nms(total_boxes, 0.7, "Union", pick); 349 | _select(total_boxes, total_boxes, pick); 350 | cout << "[2]: " << total_boxes.rows() << endl; 351 | 352 | // using regression, convert n*9 to n*5 353 | MatrixXd regh = total_boxes.middleCols(3, 1) - total_boxes.middleCols(1, 1); 354 | MatrixXd regw = total_boxes.middleCols(2, 1) - total_boxes.middleCols(0, 1); 355 | MatrixXd t1 = total_boxes.middleCols(0, 1) + regw.cwiseProduct(total_boxes.middleCols(5, 1)); 356 | MatrixXd t2 = total_boxes.middleCols(1, 1) + regh.cwiseProduct(total_boxes.middleCols(6, 1)); 357 | MatrixXd t3 = total_boxes.middleCols(2, 1) + regw.cwiseProduct(total_boxes.middleCols(7, 1)); 358 | MatrixXd t4 = total_boxes.middleCols(3, 1) + regh.cwiseProduct(total_boxes.middleCols(8, 1)); 359 | MatrixXd t5 = total_boxes.middleCols(4, 1); 360 | total_boxes.resize(total_boxes.rows(), 5); 361 | total_boxes << t1, t2, t3, t4, t5; 362 | rerec(total_boxes); 363 | cout << "[4]: " << total_boxes.rows() << endl; 364 | MatrixXd pad_params; 365 | pad(total_boxes, img_mat.cols, img_mat.rows, pad_params); 366 | // pad_params: 0 dy, 1 edy, 2 dx, 3 edx, 4 y, 5 ey, 6 x, 7 ex, 8 tmpw, 9 tmph; 367 | 368 | vector imgs; 369 | for (int i = 0; i < total_boxes.rows(); i++){ 370 | Mat tmp = Mat::zeros(pad_params.col(9)[i], pad_params.col(8)[i], CV_32FC3); 371 | tmp = im_data(Range(pad_params.col(4)[i], pad_params.col(5)[i] + 1), 372 | Range(pad_params.col(6)[i], pad_params.col(7)[i] + 1)); 373 | Mat tmp_resize; 374 | resize(tmp, tmp_resize, Size(24, 24)); 375 | Mat tmp_float; 376 | tmp_resize.convertTo(tmp_float, CV_32FC3); 377 | tmp_float = (tmp_float - 127.5) * 0.0078125; 378 | transpose(tmp_float, tmp_float); 379 | imgs.push_back(tmp_float); 380 | } 381 | 382 | _prepareData2(RNet, imgs); 383 | 384 | //debug_blob(RNet->input_blobs()[0]); 385 | 386 | //RNet->Forward(); 387 | RNet->ForwardPrefilled(); 388 | caffe::Blob* conv5_2 = RNet->output_blobs()[0]; 389 | caffe::Blob* prob1 = RNet->output_blobs()[1]; 390 | 391 | //debug_blob(conv5_2); 392 | //debug_blob(prob1); 393 | 394 | //use prob1 to filter total_boxes 395 | //score = out['prob1'][:,1] 396 | vector score; 397 | convertToVector(prob1, score); 398 | printVector(score, "score"); 399 | 400 | vector pass_t; 401 | _find(score, threshold[1], pass_t); 402 | 403 | filter(total_boxes, pass_t, score); 404 | printVector(pass_t, "pass_t"); 405 | 406 | cout << "[5]:" << total_boxes.rows() << endl; 407 | 408 | // use conv5-2 to bbreg 409 | MatrixXd mv; 410 | getMV(conv5_2, mv, pass_t); // 4*N 411 | if (total_boxes.rows() > 0){ 412 | bbreg(total_boxes, mv); 413 | vector pick; 414 | nms(total_boxes, 0.5, "Union", pick); 415 | if (pick.size() > 0){ 416 | _select(total_boxes, total_boxes, pick); 417 | } 418 | cout << "[7]:" << total_boxes.rows() << endl; 419 | rerec(total_boxes); 420 | cout << "[8]:" << total_boxes.rows() << endl; 421 | } 422 | } 423 | 424 | void _stage3(Mat &img_mat, shared_ptr> ONet, 425 | vector &threshold, MatrixXd &total_boxes) 426 | { 427 | MatrixXd pad_params; 428 | pad(total_boxes, img_mat.cols, img_mat.rows, pad_params); 429 | // pad_params: 0 dy, 1 edy, 2 dx, 3 edx, 4 y, 5 ey, 6 x, 7 ex, 8 tmpw, 9 tmph; 430 | //cout << pad_params; 431 | 432 | vector imgs; 433 | for (int i = 0; i < total_boxes.rows(); i++){ 434 | Mat tmp = Mat::zeros(pad_params.col(9)[i], pad_params.col(8)[i], CV_32FC3); 435 | tmp = img_mat(Range(pad_params.col(4)[i], pad_params.col(5)[i] + 1), 436 | Range(pad_params.col(6)[i], pad_params.col(7)[i] + 1)); 437 | Mat tmp_resize; 438 | resize(tmp, tmp_resize, Size(48, 48)); 439 | Mat tmp_float; 440 | tmp_resize.convertTo(tmp_float, CV_32FC3); 441 | tmp_float = (tmp_float - 127.5) * 0.0078125; 442 | imgs.push_back(tmp_float); 443 | } 444 | 445 | _prepareData2(ONet, imgs); 446 | //ONet->Forward(); 447 | ONet->ForwardPrefilled(); 448 | caffe::Blob* conv6_2 = ONet->output_blobs()[0]; // 4 449 | caffe::Blob* conv6_3 = ONet->output_blobs()[1]; // 10 450 | caffe::Blob* prob1 = ONet->output_blobs()[2]; // 2 451 | 452 | //use prob1 to filter total_boxes 453 | vector score; 454 | 455 | convertToVector(prob1, score); 456 | vector pass_t; 457 | _find(score, threshold[1], pass_t); 458 | filter(total_boxes, pass_t, score); 459 | cout << "[9]:" << total_boxes.rows() << endl; 460 | 461 | // use conv6-2 to bbreg 462 | MatrixXd mv; 463 | getMV(conv6_2, mv, pass_t); 464 | if (total_boxes.rows() > 0){ 465 | bbreg(total_boxes, mv); 466 | cout << "[10]:" << total_boxes.rows() << endl; 467 | vector pick; 468 | nms(total_boxes, 0.5, "Min", pick); 469 | if (pick.size() > 0){ 470 | _select(total_boxes, total_boxes, pick); 471 | } 472 | cout << "[11]:" << total_boxes.rows() << endl; 473 | } 474 | } 475 | 476 | void detect_face(Mat &img_mat, int minsize, 477 | shared_ptr> PNet, shared_ptr> RNet, shared_ptr> ONet, 478 | vector threshold, bool fastresize, float factor, MatrixXd &boxes) 479 | { 480 | MatrixXd total_boxes; 481 | total_boxes.resize(0, 9); 482 | _stage1(img_mat, minsize, PNet, threshold, fastresize, factor, total_boxes); 483 | 484 | if(total_boxes.rows() > 0) 485 | _stage2(img_mat, RNet, threshold, total_boxes); 486 | 487 | //if (total_boxes.rows() > 0) 488 | // _stage3(img_mat, ONet, threshold, total_boxes); 489 | 490 | //cout << "total_boxes num:" << total_boxes.rows() << endl; 491 | //cout << total_boxes << endl; 492 | drawBoxes(img_mat, total_boxes); 493 | boxes = total_boxes; 494 | } 495 | 496 | class FaceDetector 497 | { 498 | public: 499 | FaceDetector(){} 500 | void initialize(const string& _model_path){ model_path = _model_path; init(); } 501 | void detect(Mat& _img, vector>& boxes){ 502 | Mat img; 503 | _img.copyTo(img); 504 | cvtColor(img, img, CV_BGR2RGB); 505 | 506 | MatrixXd boundingboxes; 507 | detect_face(img, minsize, PNet, RNet, ONet, threshold, false, factor, boundingboxes); 508 | //cout << "boundingboxes:\n" << boundingboxes << endl; 509 | for (int i = 0; i < boundingboxes.rows(); i++){ 510 | vector box; 511 | box.resize(4); 512 | assert(boundingboxes.cols() >= 4); 513 | for (int j = 0; j < 4; j++){ 514 | box[j] = (int)boundingboxes(i, j); 515 | } 516 | boxes.push_back(box); 517 | } 518 | } 519 | 520 | private: 521 | void init(){ 522 | threshold.push_back(0.6); 523 | threshold.push_back(0.7); 524 | threshold.push_back(0.7); 525 | factor = 0.709; 526 | minsize = 20; 527 | fastresize = false; 528 | #ifdef CPU_ONLY 529 | caffe::Caffe::set_mode(caffe::Caffe::CPU); 530 | #else 531 | caffe::Caffe::set_mode(caffe::Caffe::GPU); 532 | #endif 533 | PNet.reset(new caffe::Net(model_path + "/det1.prototxt", caffe::TEST)); 534 | PNet->CopyTrainedLayersFrom(model_path + "/det1.caffemodel"); 535 | RNet.reset(new caffe::Net(model_path + "/det2.prototxt", caffe::TEST)); 536 | RNet->CopyTrainedLayersFrom(model_path + "/det2.caffemodel"); 537 | ONet.reset(new caffe::Net(model_path + "/det3.prototxt", caffe::TEST)); 538 | ONet->CopyTrainedLayersFrom(model_path + "/det3.caffemodel"); 539 | } 540 | 541 | string model_path; 542 | vector threshold; 543 | float factor; 544 | int minsize; 545 | bool fastresize; 546 | shared_ptr> PNet, RNet, ONet; 547 | }; 548 | 549 | #endif 550 | -------------------------------------------------------------------------------- /test_nms.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "nms.h" 3 | 4 | TEST(nms1, test_nms) 5 | { 6 | MatrixXd total_boxes; 7 | total_boxes.resize(6, 5); 8 | total_boxes << 9 | 183.41366396, 71.08030653, 346.26206368, 272.96784276, 0.99967718, 10 | 188.47475302, 72.30254986, 340.0438953, 271.67589057, 0.99965048, 11 | 191.2930266, 76.61472487, 339.47823516, 270.15330981, 0.99926764, 12 | 193.21896309, 75.26130742, 339.58434188, 266.14937097, 0.98572284, 13 | 187.90412591, 79.68451911, 332.99922186, 267.89193738, 0.99808455, 14 | 189.21408205, 75.46541651, 344.2887798, 273.11075579, 0.99969637; 15 | Matrix out_p; 16 | out_p << 5; 17 | vector out; 18 | nms(total_boxes, 0.7, "Min", out); 19 | for (int i = 0; i < out.size(); i++){ 20 | EXPECT_EQ(out[i] , out_p(i)); 21 | } 22 | } 23 | 24 | TEST(nms2, test_nms) 25 | { 26 | MatrixXd total_boxes; 27 | total_boxes.resize(11, 5); 28 | total_boxes << 29 | 208., 100., 397., 289., 0.74231839, 30 | 198., 76., 374., 252., 0.96700346, 31 | 201., 62., 418., 280., 0.79915774, 32 | 194., 129., 300., 235., 0.86142009, 33 | 209., 101., 367., 259., 0.97880608, 34 | 205., 73., 400., 268., 0.98384535, 35 | 211., 91., 336., 216., 0.84980434, 36 | 190., 96., 337., 242., 0.97570157, 37 | 198., 64., 348., 214., 0.95710379, 38 | 184., 102., 314., 232., 0.97205275, 39 | 214., 89., 383., 258., 0.96966559; 40 | Matrix out_p; 41 | out_p << 5, 4, 7, 8, 3, 6; 42 | vector out; 43 | nms(total_boxes, 0.7, "Min", out); 44 | for (int i = 0; i < out.size(); i++){ 45 | EXPECT_EQ(out[i] , out_p(i)); 46 | } 47 | } 48 | 49 | TEST(nms3, test_nms) 50 | { 51 | MatrixXd total_boxes; 52 | total_boxes.resize(78, 9); 53 | total_boxes << 54 | 2.78000000e+02, 1.35000000e+02, 2.96000000e+02, 1.53000000e+02, 9.33610499e-01, -8.20154548e-02, -7.18935579e-02, -1.65382951e-01, 7.94545859e-02, 55 | 1.91000000e+02, 9.50000000e+01, 2.10000000e+02, 1.13000000e+02, 8.95024121e-01, -4.34634648e-02, -1.00855976e-01, 1.89852491e-02, 1.04824454e-01, 56 | 2.55000000e+02, 3.51000000e+02, 2.73000000e+02, 3.70000000e+02, 8.45106840e-01, -1.70209587e-01, -2.77867734e-01, 1.69330090e-03, 1.05846629e-01, 57 | 3.58000000e+02, 1.65000000e+02, 3.76000000e+02, 1.83000000e+02, 8.26624632e-01, -4.99067083e-03, -9.66295451e-02, -5.33807203e-02, 5.83959408e-02, 58 | 2.51000000e+02, 1.45000000e+02, 2.70000000e+02, 1.63000000e+02, 8.05955648e-01, 2.93287188e-02, -9.10318196e-02, 2.51093954e-02, 4.70300205e-02, 59 | 3.55000000e+02, 1.41000000e+02, 3.73000000e+02, 1.60000000e+02, 7.61156619e-01, -2.68058106e-02, -2.53878474e-01, 1.79893449e-02, 6.75155967e-02, 60 | 2.45000000e+02, 3.48000000e+02, 2.63000000e+02, 3.66000000e+02, 7.35058546e-01, 1.44458458e-01, -7.45378435e-02, 8.76102671e-02, 1.24141961e-01, 61 | 2.48000000e+02, 1.21000000e+02, 2.66000000e+02, 1.40000000e+02, 7.32023358e-01, -3.90662961e-02, -1.01619840e-01, 7.33766630e-02, 2.26068705e-01, 62 | 2.78000000e+02, 1.28000000e+02, 2.96000000e+02, 1.46000000e+02, 7.05132067e-01, -6.41673654e-02, -1.74753983e-02, -5.79212978e-02, 2.05339223e-01, 63 | 3.61000000e+02, 1.71000000e+02, 3.80000000e+02, 1.90000000e+02, 7.01460600e-01, -6.14192970e-02, -1.54274970e-01, -5.68182208e-02, 8.09654742e-02, 64 | 2.31000000e+02, 1.41000000e+02, 2.50000000e+02, 1.60000000e+02, 6.94773257e-01, 1.77539885e-04, -1.94122978e-02, -6.75368309e-02, 1.98527187e-01, 65 | 2.71000000e+02, 2.41000000e+02, 2.90000000e+02, 2.60000000e+02, 6.81389451e-01, -1.08519286e-01, -2.50961393e-01, -1.13021620e-02, 6.95331991e-02, 66 | 1.85000000e+02, 9.50000000e+01, 2.03000000e+02, 1.13000000e+02, 6.73368990e-01, 8.41817409e-02, -4.88474630e-02, 7.50392452e-02, 9.43255126e-02, 67 | 1.21000000e+02, 2.55000000e+02, 1.40000000e+02, 2.73000000e+02, 6.64589882e-01, 4.22678664e-02, -5.97293675e-02, -8.68501887e-03, 9.56013501e-02, 68 | 2.01000000e+02, 9.50000000e+01, 2.20000000e+02, 1.13000000e+02, 6.64079845e-01, -8.17664862e-02, -1.40165046e-01, 2.29184106e-02, 1.43394351e-01, 69 | 3.58000000e+02, 1.15000000e+02, 3.76000000e+02, 1.33000000e+02, 6.59236729e-01, -9.69149470e-02, -5.10172546e-02, -1.37301594e-01, 1.89575389e-01, 70 | 3.55000000e+02, 1.35000000e+02, 3.73000000e+02, 1.53000000e+02, 6.58442855e-01, -2.76965909e-02, -1.41338900e-01, -5.52261770e-02, 7.09443688e-02, 71 | 2.45000000e+02, 2.21000000e+02, 2.63000000e+02, 2.40000000e+02, 6.27590418e-01, 4.56827283e-02, -3.08516026e-02, -7.18832389e-03, 5.20548560e-02, 72 | 2.35000000e+02, 2.61000000e+02, 2.53000000e+02, 2.80000000e+02, 6.21665239e-01, -1.35340951e-02, -2.80141413e-01, 8.19843933e-02, 4.62583527e-02, 73 | 3.55000000e+02, 1.48000000e+02, 3.73000000e+02, 1.66000000e+02, 6.08780503e-01, 4.01630700e-02, -1.81000233e-01, -4.39032912e-04, 3.88609432e-02, 74 | 2.15000000e+02, 1.48000000e+02, 2.33000000e+02, 1.66000000e+02, 6.04665518e-01, -5.78003339e-02, -7.93638229e-02, -3.00562195e-02, 1.45663098e-01, 75 | 1.81000000e+02, 9.10000000e+01, 2.06000000e+02, 1.17000000e+02, 9.52542901e-01, 9.74441022e-02, -5.45117110e-02, 1.98100284e-02, 4.81336862e-02, 76 | 2.46000000e+02, 3.45000000e+02, 2.72000000e+02, 3.71000000e+02, 9.33929205e-01, 1.06157333e-01, -8.55512321e-02, 4.38237116e-02, 1.14697382e-01, 77 | 1.90000000e+02, 9.10000000e+01, 2.16000000e+02, 1.17000000e+02, 9.32594240e-01, 2.86794454e-03, -2.00528428e-02, -3.24708670e-02, 1.03921875e-01, 78 | 2.51000000e+02, 2.84000000e+02, 2.77000000e+02, 3.10000000e+02, 8.57817709e-01, -8.71825218e-03, -1.27555713e-01, 3.65214795e-03, 1.64893642e-01, 79 | 2.70000000e+02, 2.37000000e+02, 2.96000000e+02, 2.63000000e+02, 8.34514976e-01, -1.44744337e-01, -2.50891954e-01, -4.42436226e-02, 7.35061914e-02, 80 | 2.56000000e+02, 1.29000000e+02, 2.82000000e+02, 1.55000000e+02, 7.75500715e-01, 4.47253697e-02, -1.65223591e-02, 4.26719412e-02, 1.83312178e-01, 81 | 2.09000000e+02, 1.66000000e+02, 2.35000000e+02, 1.92000000e+02, 7.40907490e-01, -1.47132501e-01, -2.25915119e-01, -2.60201506e-02, 8.36350173e-02, 82 | 2.51000000e+02, 3.50000000e+02, 2.77000000e+02, 3.76000000e+02, 7.34265745e-01, -6.06262423e-02, -2.17379048e-01, 4.64009494e-03, 4.83529605e-02, 83 | 2.37000000e+02, 2.13000000e+02, 2.63000000e+02, 2.39000000e+02, 7.26572812e-01, 2.46584415e-02, -8.26789290e-02, 4.91453633e-02, 1.34076715e-01, 84 | 1.99000000e+02, 1.48000000e+02, 2.25000000e+02, 1.73000000e+02, 6.43414974e-01, 3.68531682e-02, -6.73728436e-03, 1.04441419e-02, 1.96677729e-01, 85 | 2.65000000e+02, 1.33000000e+02, 2.91000000e+02, 1.59000000e+02, 6.26788497e-01, -3.78842913e-02, -1.34447947e-01, 2.60662213e-02, 1.03012025e-01, 86 | 2.75000000e+02, 2.04000000e+02, 3.00000000e+02, 2.30000000e+02, 6.23979330e-01, -1.04509294e-04, -8.11065137e-02, 7.23331422e-03, 1.36356235e-01, 87 | 3.50000000e+02, 1.15000000e+02, 3.76000000e+02, 1.41000000e+02, 6.15869761e-01, 1.08815610e-01, -2.54970286e-02, -3.95275280e-02, 8.02992731e-02, 88 | 1.75000000e+02, 8.90000000e+01, 2.12000000e+02, 1.25000000e+02, 9.74581957e-01, 1.89248875e-01, -2.72051916e-02, 2.34529600e-02, -1.56523660e-02, 89 | 2.48000000e+02, 2.75000000e+02, 2.85000000e+02, 3.11000000e+02, 9.39174831e-01, -2.37493031e-02, -5.91576472e-02, -9.73371863e-02, 1.38470754e-01, 90 | 1.88000000e+02, 9.60000000e+01, 2.25000000e+02, 1.32000000e+02, 9.29924726e-01, 1.84886530e-02, -1.62535965e-01, 2.02556252e-02, 2.92208903e-02, 91 | 2.02000000e+02, 1.75000000e+02, 2.38000000e+02, 2.12000000e+02, 9.24718320e-01, 3.96779366e-02, -1.60735354e-01, -4.13426794e-02, -1.95367038e-02, 92 | 2.48000000e+02, 3.41000000e+02, 2.85000000e+02, 3.77000000e+02, 9.21568811e-01, 2.43514776e-03, -1.01761237e-01, -6.84146658e-02, 7.60710537e-02, 93 | 2.02000000e+02, 1.49000000e+02, 2.38000000e+02, 1.85000000e+02, 8.60738099e-01, 3.89678665e-02, -4.38078493e-03, -6.84391111e-02, 8.06697309e-02, 94 | 2.55000000e+02, 2.35000000e+02, 2.91000000e+02, 2.71000000e+02, 8.17871451e-01, -1.06936187e-01, -2.60329783e-01, 2.69831046e-02, 6.73739463e-02, 95 | 3.41000000e+02, 1.09000000e+02, 3.77000000e+02, 1.45000000e+02, 7.63661981e-01, 7.04247952e-02, -1.76096726e-02, -1.12217262e-01, 4.46442552e-02, 96 | 2.48000000e+02, 1.16000000e+02, 2.85000000e+02, 1.52000000e+02, 7.17816770e-01, 6.95258938e-03, -4.99074087e-02, -3.11612934e-02, 1.07024208e-01, 97 | 2.02000000e+02, 1.62000000e+02, 2.38000000e+02, 1.98000000e+02, 6.44978523e-01, 6.01485334e-02, -1.05217904e-01, -4.13702726e-02, -4.18038480e-02, 98 | 2.02000000e+02, 1.88000000e+02, 2.38000000e+02, 2.25000000e+02, 6.20088577e-01, 6.89951889e-03, -4.17398006e-01, 6.53185323e-02, -1.19325414e-01, 99 | 3.48000000e+02, 1.16000000e+02, 3.84000000e+02, 1.52000000e+02, 6.00018024e-01, 2.80705690e-02, -1.89156726e-01, -2.43346393e-01, -1.41168237e-01, 100 | 3.32000000e+02, 1.07000000e+02, 3.83000000e+02, 1.58000000e+02, 9.57915843e-01, 4.45968546e-02, -4.01132926e-02, -1.25267655e-01, -3.88895907e-03, 101 | 1.91000000e+02, 1.54000000e+02, 2.43000000e+02, 2.05000000e+02, 9.38783824e-01, 1.13164753e-01, -4.12500054e-02, -6.34074435e-02, 5.43425418e-03, 102 | 2.47000000e+02, 2.75000000e+02, 2.99000000e+02, 3.27000000e+02, 9.16424870e-01, -5.54427877e-03, -4.23343778e-02, -1.80819571e-01, -1.26157999e-02, 103 | 2.94000000e+02, 1.35000000e+02, 3.46000000e+02, 1.87000000e+02, 9.12661016e-01, 4.83000651e-03, -1.31538481e-01, -1.09739751e-02, 5.57082035e-02, 104 | 2.47000000e+02, 2.01000000e+02, 2.99000000e+02, 2.52000000e+02, 8.97582352e-01, 8.03423394e-03, -9.85199735e-02, 6.43486530e-03, 9.14307982e-02, 105 | 1.73000000e+02, 7.90000000e+01, 2.24000000e+02, 1.30000000e+02, 8.68841648e-01, 1.98184088e-01, 1.98275708e-02, -1.97148249e-02, 1.37677565e-02, 106 | 2.47000000e+02, 2.19000000e+02, 2.99000000e+02, 2.71000000e+02, 8.26875389e-01, -4.85096164e-02, -1.19001731e-01, -3.98771018e-02, 2.24097930e-02, 107 | 2.47000000e+02, 3.41000000e+02, 2.99000000e+02, 3.92000000e+02, 7.97293305e-01, 2.77274344e-02, -1.92399308e-01, 3.43092158e-02, 7.52068609e-02, 108 | 2.38000000e+02, 1.44000000e+02, 2.89000000e+02, 1.96000000e+02, 7.88639665e-01, -5.38329780e-03, -1.80634752e-01, 1.98005065e-02, 1.09340288e-02, 109 | 2.47000000e+02, 3.13000000e+02, 2.99000000e+02, 3.64000000e+02, 6.79586649e-01, 3.26336212e-02, -2.38431230e-01, 3.64469066e-02, -2.44539790e-02, 110 | 2.66000000e+02, 5.10000000e+01, 3.17000000e+02, 1.02000000e+02, 6.67583764e-01, -4.91853841e-02, -3.58208120e-02, -5.58938421e-02, 1.58750221e-01, 111 | 2.29000000e+02, 2.66000000e+02, 2.80000000e+02, 3.17000000e+02, 6.30352914e-01, 9.33899283e-02, -4.96173650e-02, 2.31320336e-02, 1.27742931e-01, 112 | 2.44000000e+02, 2.83000000e+02, 3.16000000e+02, 3.56000000e+02, 9.96656537e-01, 3.01437024e-02, -9.68708694e-02, -6.62661865e-02, 8.37427527e-02, 113 | 2.30000000e+02, 2.04000000e+02, 3.03000000e+02, 2.77000000e+02, 9.94011700e-01, 1.20302483e-01, -1.94349423e-01, 2.17034072e-02, -1.12380013e-01, 114 | 2.44000000e+02, 3.09000000e+02, 3.16000000e+02, 3.82000000e+02, 9.84057128e-01, 5.40508442e-02, -2.02546179e-01, -3.23340595e-02, -9.69446264e-04, 115 | 1.91000000e+02, 1.51000000e+02, 2.63000000e+02, 2.24000000e+02, 9.45829034e-01, 1.61108270e-01, -5.66872954e-02, 2.70408615e-02, 1.52264461e-02, 116 | 2.57000000e+02, 2.04000000e+02, 3.29000000e+02, 2.77000000e+02, 8.06748331e-01, -1.41240582e-01, -1.51828408e-01, -1.98290050e-01, -2.47118529e-03, 117 | 2.44000000e+02, 1.25000000e+02, 3.16000000e+02, 1.97000000e+02, 7.18220592e-01, 2.81636491e-02, -7.16374218e-02, -2.90201455e-02, 4.24995422e-02, 118 | 1.91000000e+02, 1.25000000e+02, 2.63000000e+02, 1.97000000e+02, 6.07192993e-01, 1.05893567e-01, -3.09394300e-03, 4.56905141e-02, 1.54981196e-01, 119 | 1.95000000e+02, 1.39000000e+02, 2.97000000e+02, 2.41000000e+02, 9.91735756e-01, 7.90825039e-02, -9.78166014e-02, -5.39516620e-02, -5.77941462e-02, 120 | 2.32000000e+02, 1.02000000e+02, 3.34000000e+02, 2.04000000e+02, 9.20827806e-01, -7.85513073e-02, -9.92713571e-02, -9.81625617e-02, 1.19282380e-01, 121 | 2.51000000e+02, 1.39000000e+02, 3.53000000e+02, 2.41000000e+02, 8.93811345e-01, 2.01638956e-02, -2.04821959e-01, -5.30151501e-02, -4.71881591e-02, 122 | 1.95000000e+02, 1.02000000e+02, 2.97000000e+02, 2.04000000e+02, 7.64766216e-01, 3.62210497e-02, 4.57721576e-03, 3.15693840e-02, 2.79234976e-01, 123 | 2.23000000e+02, 9.10000000e+01, 3.67000000e+02, 2.36000000e+02, 9.98139143e-01, -3.72815393e-02, -9.98418480e-02, -7.70605728e-02, 1.16418153e-01, 124 | 2.23000000e+02, 1.44000000e+02, 3.67000000e+02, 2.88000000e+02, 9.59657609e-01, 1.78628769e-02, -2.95878172e-01, -1.07396677e-01, -2.00705156e-01, 125 | 2.75000000e+02, 9.10000000e+01, 4.19000000e+02, 2.36000000e+02, 8.19527864e-01, 2.35665515e-02, 4.00160886e-02, -3.41928512e-01, -3.96483503e-02, 126 | 1.70000000e+02, 9.10000000e+01, 3.14000000e+02, 2.36000000e+02, 8.18339527e-01, 2.43739292e-01, 3.61245982e-02, 6.27742335e-02, 4.64914329e-02, 127 | 1.96000000e+02, 3.90000000e+01, 3.41000000e+02, 1.83000000e+02, 7.77969420e-01, 1.15551725e-01, 1.75964609e-01, -4.13505509e-02, 2.17152327e-01, 128 | 1.66000000e+02, 9.20000000e+01, 3.70000000e+02, 2.96000000e+02, 9.98789012e-01, 3.14107060e-01, 4.09360193e-02, 2.82451510e-02, -3.25958282e-02, 129 | 2.03000000e+02, 1.80000000e+01, 4.07000000e+02, 2.22000000e+02, 9.40885842e-01, 1.21894300e-01, 2.70426244e-01, -1.42774135e-01, 2.27811188e-01, 130 | 2.40000000e+02, 9.20000000e+01, 4.44000000e+02, 2.96000000e+02, 7.00634658e-01, -1.49217770e-02, -1.14631541e-02, -4.10333633e-01, -1.82203099e-01, 131 | 1.82000000e+02, 2.60000000e+01, 4.69000000e+02, 3.13000000e+02, 9.97039378e-01, 1.29406288e-01, 1.28545910e-01, -2.38053322e-01, -1.12856403e-01; 132 | Matrix out_p; 133 | out_p << 74, 69, 77, 58, 59, 65, 60, 34, 70, 46, 21, 61, 75, 35, 47, 22, 0, 23, 36, 37, 38, 66, 48, 49, 50, 1, 67, 51, 39, 24, 2, 25, 52, 3, 71, 72, 40, 62, 4, 53, 54, 73, 26, 68, 41, 5, 27, 6, 28, 7, 29, 63, 42, 8, 9, 76, 10, 11, 55, 12, 56, 13, 14, 15, 16, 43, 30, 57, 17, 31, 32, 18, 44, 33, 19, 64, 20, 45; 134 | 135 | vector out; 136 | nms(total_boxes, 0.7, "Union", out); 137 | for (int i = 0; i < out.size(); i++){ 138 | EXPECT_EQ(out[i] , out_p(i)); 139 | } 140 | } 141 | 142 | TEST(nms4, test_nms) 143 | { 144 | MatrixXd total_boxes; 145 | total_boxes.resize(32, 9); 146 | total_boxes << 147 | 1.85000000e+02, 9.50000000e+01, 2.03000000e+02, 1.13000000e+02, 6.73368990e-01, 8.41817409e-02, -4.88474630e-02, 7.50392452e-02, 9.43255126e-02, 148 | 1.88000000e+02, 9.50000000e+01, 2.06000000e+02, 1.13000000e+02, 6.46447659e-01, -3.22338976e-02, -1.03326187e-01, 7.51694813e-02, 1.50386810e-01, 149 | 1.91000000e+02, 9.50000000e+01, 2.10000000e+02, 1.13000000e+02, 8.95024121e-01, -4.34634648e-02, -1.00855976e-01, 1.89852491e-02, 1.04824454e-01, 150 | 2.01000000e+02, 9.50000000e+01, 2.20000000e+02, 1.13000000e+02, 6.64079845e-01, -8.17664862e-02, -1.40165046e-01, 2.29184106e-02, 1.43394351e-01, 151 | 3.58000000e+02, 1.15000000e+02, 3.76000000e+02, 1.33000000e+02, 6.59236729e-01, -9.69149470e-02, -5.10172546e-02, -1.37301594e-01, 1.89575389e-01, 152 | 2.45000000e+02, 1.21000000e+02, 2.63000000e+02, 1.40000000e+02, 7.25341737e-01, -4.39546742e-02, -1.23070359e-01, 4.48870584e-02, 2.03440323e-01, 153 | 2.48000000e+02, 1.21000000e+02, 2.66000000e+02, 1.40000000e+02, 7.32023358e-01, -3.90662961e-02, -1.01619840e-01, 7.33766630e-02, 2.26068705e-01, 154 | 2.78000000e+02, 1.28000000e+02, 2.96000000e+02, 1.46000000e+02, 7.05132067e-01, -6.41673654e-02, -1.74753983e-02, -5.79212978e-02, 2.05339223e-01, 155 | 2.75000000e+02, 1.31000000e+02, 2.93000000e+02, 1.50000000e+02, 7.20660865e-01, -5.29861413e-02, -3.42522562e-02, -6.92065433e-02, 1.97051674e-01, 156 | 2.78000000e+02, 1.31000000e+02, 2.96000000e+02, 1.50000000e+02, 6.76997364e-01, -5.76520227e-02, -4.16126326e-02, -1.52568221e-01, 1.15462855e-01, 157 | 2.75000000e+02, 1.35000000e+02, 2.93000000e+02, 1.53000000e+02, 7.06298232e-01, -6.76914454e-02, -1.17664099e-01, -2.32201740e-02, 1.29369929e-01, 158 | 2.78000000e+02, 1.35000000e+02, 2.96000000e+02, 1.53000000e+02, 9.33610499e-01, -8.20154548e-02, -7.18935579e-02, -1.65382951e-01, 7.94545859e-02, 159 | 3.55000000e+02, 1.35000000e+02, 3.73000000e+02, 1.53000000e+02, 6.58442855e-01, -2.76965909e-02, -1.41338900e-01, -5.52261770e-02, 7.09443688e-02, 160 | 3.55000000e+02, 1.38000000e+02, 3.73000000e+02, 1.56000000e+02, 6.40712917e-01, -5.31828739e-02, -2.20835999e-01, -4.25284654e-02, 5.39630167e-02, 161 | 2.31000000e+02, 1.41000000e+02, 2.50000000e+02, 1.60000000e+02, 6.94773257e-01, 1.77539885e-04, -1.94122978e-02, -6.75368309e-02, 1.98527187e-01, 162 | 3.55000000e+02, 1.41000000e+02, 3.73000000e+02, 1.60000000e+02, 7.61156619e-01, -2.68058106e-02, -2.53878474e-01, 1.79893449e-02, 6.75155967e-02, 163 | 2.51000000e+02, 1.45000000e+02, 2.70000000e+02, 1.63000000e+02, 8.05955648e-01, 2.93287188e-02, -9.10318196e-02, 2.51093954e-02, 4.70300205e-02, 164 | 2.55000000e+02, 1.45000000e+02, 2.73000000e+02, 1.63000000e+02, 6.20101035e-01, -7.17875808e-02, -9.55546200e-02, -1.07438788e-02, 1.12353891e-01, 165 | 2.15000000e+02, 1.48000000e+02, 2.33000000e+02, 1.66000000e+02, 6.04665518e-01, -5.78003339e-02, -7.93638229e-02, -3.00562195e-02, 1.45663098e-01, 166 | 3.55000000e+02, 1.48000000e+02, 3.73000000e+02, 1.66000000e+02, 6.08780503e-01, 4.01630700e-02, -1.81000233e-01, -4.39032912e-04, 3.88609432e-02, 167 | 3.55000000e+02, 1.61000000e+02, 3.73000000e+02, 1.80000000e+02, 7.12293386e-01, 6.16945215e-02, -1.34687692e-01, -2.14347057e-02, 6.06373288e-02, 168 | 3.58000000e+02, 1.61000000e+02, 3.76000000e+02, 1.80000000e+02, 7.72113860e-01, 3.61951441e-03, -5.96733280e-02, -7.96180889e-02, 8.74350667e-02, 169 | 3.58000000e+02, 1.65000000e+02, 3.76000000e+02, 1.83000000e+02, 8.26624632e-01, -4.99067083e-03, -9.66295451e-02, -5.33807203e-02, 5.83959408e-02, 170 | 3.61000000e+02, 1.71000000e+02, 3.80000000e+02, 1.90000000e+02, 7.01460600e-01, -6.14192970e-02, -1.54274970e-01, -5.68182208e-02, 8.09654742e-02, 171 | 2.45000000e+02, 2.21000000e+02, 2.63000000e+02, 2.40000000e+02, 6.27590418e-01, 4.56827283e-02, -3.08516026e-02, -7.18832389e-03, 5.20548560e-02, 172 | 2.71000000e+02, 2.41000000e+02, 2.90000000e+02, 2.60000000e+02, 6.81389451e-01, -1.08519286e-01, -2.50961393e-01, -1.13021620e-02, 6.95331991e-02, 173 | 1.21000000e+02, 2.55000000e+02, 1.40000000e+02, 2.73000000e+02, 6.64589882e-01, 4.22678664e-02, -5.97293675e-02, -8.68501887e-03, 9.56013501e-02, 174 | 2.35000000e+02, 2.61000000e+02, 2.53000000e+02, 2.80000000e+02, 6.21665239e-01, -1.35340951e-02, -2.80141413e-01, 8.19843933e-02, 4.62583527e-02, 175 | 2.45000000e+02, 3.48000000e+02, 2.63000000e+02, 3.66000000e+02, 7.35058546e-01, 1.44458458e-01, -7.45378435e-02, 8.76102671e-02, 1.24141961e-01, 176 | 2.55000000e+02, 3.48000000e+02, 2.73000000e+02, 3.66000000e+02, 7.30409145e-01, -1.42104581e-01, -1.60892934e-01, -5.36750630e-03, 1.92731500e-01, 177 | 2.51000000e+02, 3.51000000e+02, 2.70000000e+02, 3.70000000e+02, 8.13210666e-01, -1.37664884e-01, -2.60863423e-01, 3.36306691e-02, 1.14658982e-01, 178 | 2.55000000e+02, 3.51000000e+02, 2.73000000e+02, 3.70000000e+02, 8.45106840e-01, -1.70209587e-01, -2.77867734e-01, 1.69330090e-03, 1.05846629e-01; 179 | Matrix out_p; 180 | out_p << 11, 2, 31, 22, 16, 15, 28, 6, 7, 23, 14, 25, 0, 26, 3, 4, 12, 24, 27, 19, 18; 181 | 182 | vector out; 183 | nms(total_boxes, 0.5, "Union", out); 184 | 185 | for (int i = 0; i < out.size(); i++){ 186 | cout << out[i] << " " << endl; 187 | EXPECT_EQ(out[i] , out_p(i)); 188 | } 189 | } 190 | -------------------------------------------------------------------------------- /mtcnn.cpp: -------------------------------------------------------------------------------- 1 | #include "mtcnn.h" 2 | 3 | void bbreg(MatrixXd &boundingbox, MatrixXd ®) 4 | { 5 | assert(boundingbox.cols() == 5); 6 | assert(reg.cols() == 4); 7 | assert(boundingbox.rows() == reg.rows()); 8 | 9 | #ifdef DEBUG_MTCNN 10 | cout << "bb.rows:" << boundingbox.rows() << endl; 11 | cout << "reg.rows:" << reg.rows() << endl; 12 | #endif 13 | 14 | if (reg.rows() == 1){ 15 | cout << "reg.rows == 1" << endl; 16 | } 17 | int numOfBB = boundingbox.rows(); 18 | Matrix w = boundingbox.col(2).cast() - boundingbox.col(0).cast() + MatrixXd::Ones(numOfBB, 1); 19 | Matrix h = boundingbox.col(3).cast() - boundingbox.col(1).cast() + MatrixXd::Ones(numOfBB, 1); 20 | boundingbox.col(0) += w.cwiseProduct(reg.col(0)); 21 | boundingbox.col(1) += h.cwiseProduct(reg.col(1)); 22 | boundingbox.col(2) += w.cwiseProduct(reg.col(2)); 23 | boundingbox.col(3) += h.cwiseProduct(reg.col(3)); 24 | } 25 | 26 | void denormalize(MatrixXd &boundingbox, MatrixXd &points) 27 | { 28 | assert(boundingbox.cols() == 5); 29 | assert(points.cols() == 10); 30 | assert(boundingbox.rows() == points.rows()); 31 | 32 | #ifdef DEBUG_MTCNN 33 | cout << "bb.rows:" << boundingbox.rows() << endl; 34 | cout << "pts.rows:" << points.rows() << endl; 35 | #endif 36 | 37 | MatrixXd w; 38 | w.resize(points.rows(), 1); 39 | 40 | MatrixXd h; 41 | h.resize(points.rows(), 1); 42 | 43 | for (int i = 0; i < points.rows(); i++){ 44 | w(i, 0) = boundingbox(i, 3) - boundingbox(i, 1) + 1; 45 | h(i, 0) = boundingbox(i, 2) - boundingbox(i, 0) + 1; 46 | } 47 | 48 | for (int i = 0; i < points.rows(); i++){ 49 | for (int j = 0; j < 5; j++){ 50 | points(i,j) = w(i, 0) * points(i, j) + boundingbox(i, 0) - 1; 51 | } 52 | for (int k = 5; k < 10; k++){ 53 | points(i,k) = h(i, 0) * points(i, k) + boundingbox(i, 1) - 1; 54 | } 55 | } 56 | } 57 | 58 | void pad(MatrixXd &boundingbox, double w, double h, MatrixXd &result) 59 | { 60 | assert(boundingbox.cols() == 5); 61 | 62 | int numOfBB = boundingbox.rows(); 63 | result.resize(numOfBB, 10); 64 | 65 | Matrix tmpw = boundingbox.col(2).cast() - boundingbox.col(0).cast() + MatrixXd::Ones(numOfBB, 1); 66 | Matrix tmph = boundingbox.col(3).cast() - boundingbox.col(1).cast() + MatrixXd::Ones(numOfBB, 1); 67 | MatrixXd dx = MatrixXd::Ones(numOfBB, 1); 68 | MatrixXd dy = MatrixXd::Ones(numOfBB, 1); 69 | Matrix edx = tmpw.replicate(1, 1); 70 | Matrix edy = tmph.replicate(1, 1); 71 | 72 | auto x = MatrixXd(boundingbox.col(0)); 73 | auto y = MatrixXd(boundingbox.col(1)); 74 | auto ex = MatrixXd(boundingbox.col(2)); 75 | auto ey = MatrixXd(boundingbox.col(3)); 76 | 77 | MatrixXd w_matrix; 78 | w_matrix.resize(ex.rows(), ex.cols()); 79 | w_matrix.fill(w); 80 | VectorXi tmp = _find(ex, w_matrix); 81 | 82 | for (int i = 0; i < tmp.size(); i++){ 83 | int j = tmp(i); 84 | edx(j) = -ex(j) + w - 1 + tmpw(j); 85 | ex(j) = w - 1; 86 | } 87 | 88 | MatrixXd h_matrix; 89 | h_matrix.resize(ey.rows(), ey.cols()); 90 | h_matrix.fill(h); 91 | tmp = _find(ey, h_matrix); 92 | for (int i = 0; i < tmp.size(); i++){ 93 | int j = tmp(i); 94 | edy(j) = -ey(j) + h - 1 + tmph(j); 95 | ey(j) = h - 1; 96 | } 97 | 98 | MatrixXd one_matrix = MatrixXd::Ones(x.rows(), x.cols()); 99 | tmp = _find(one_matrix, x); 100 | for (int i = 0; i < tmp.size(); i++){ 101 | int j = tmp(i); 102 | dx(j) = 2 - x(j); 103 | x(j) = 1; 104 | } 105 | 106 | tmp = _find(one_matrix, y); 107 | for (int i = 0; i < tmp.size(); i++){ 108 | int j = tmp(i); 109 | dy(j) = 2 - y(j); 110 | y(j) = 1; 111 | } 112 | dy -= MatrixXd::Ones(dy.rows(), dy.cols()); 113 | edy -= MatrixXd::Ones(dy.rows(), dy.cols()); 114 | dx -= MatrixXd::Ones(dy.rows(), dy.cols()); 115 | edx -= MatrixXd::Ones(dy.rows(), dy.cols()); 116 | y -= MatrixXd::Ones(dy.rows(), dy.cols()); 117 | ey -= MatrixXd::Ones(dy.rows(), dy.cols()); 118 | x -= MatrixXd::Ones(dy.rows(), dy.cols()); 119 | ex -= MatrixXd::Ones(dy.rows(), dy.cols()); 120 | 121 | result << dy, edy, dx, edx, y, ey, x, ex, tmpw, tmph; 122 | } 123 | 124 | void rerec(MatrixXd &boundingbox) 125 | { 126 | assert(boundingbox.cols() == 5); 127 | 128 | auto w = MatrixXd(boundingbox.col(2) - boundingbox.col(0)); 129 | auto h = MatrixXd(boundingbox.col(3) - boundingbox.col(1)); 130 | auto l = w.cwiseMax(h); 131 | boundingbox.col(0) += w*0.5 - l*0.5; 132 | boundingbox.col(1) += h*0.5 - l*0.5; 133 | MatrixXd ll; 134 | ll.resize(l.rows(), l.cols() * 2); 135 | ll << l, l; 136 | boundingbox.middleCols(2, 2) = boundingbox.middleCols(0, 2) + ll; 137 | } 138 | 139 | void generateBoundingBox(MatrixXd &map, vector ®, double scale, double threshold, MatrixXd &boxes) 140 | { 141 | assert(reg.size() == 4); 142 | 143 | int stride = 2; 144 | int cellsize = 12; 145 | 146 | MatrixXd threshold_matrix = MatrixXd(map.rows(), map.cols()); 147 | threshold_matrix.fill(threshold); 148 | map -= threshold_matrix; 149 | map = map.cwiseMax(MatrixXd::Zero(map.rows(), map.cols())); 150 | MatrixXd I, J, V; 151 | igl::find(map, I, J, V); // I,J is index, V is value. They are all vectors 152 | 153 | // score 154 | threshold_matrix.resize(V.size(), 1); 155 | threshold_matrix.fill(threshold); 156 | MatrixXd score = V + threshold_matrix; 157 | 158 | // reg 159 | MatrixXd new_reg; 160 | new_reg.resize(I.size(), 4); 161 | for (int i = 0; i < 4; i++){ 162 | MatrixXd content = MatrixXd::Zero(I.size(), 1); 163 | for (int num = 0; num < I.size(); num++){ 164 | content(num) = reg[i](I(num), J(num)); 165 | } 166 | new_reg.middleCols(i,1) = content; 167 | } 168 | 169 | // boundingbox 170 | MatrixXd boundingbox; 171 | boundingbox.resize(I.size(), 2); 172 | boundingbox << I, J; 173 | 174 | MatrixXd cellsize_m = MatrixXd::Zero(boundingbox.rows(), boundingbox.cols()); 175 | cellsize_m.fill(cellsize); 176 | 177 | MatrixXd bb1 = (stride * boundingbox + MatrixXd::Ones(boundingbox.rows(), boundingbox.cols())) / scale; 178 | MatrixXd bb2 = (stride * boundingbox + cellsize_m) / scale; 179 | 180 | _fix(bb1); 181 | _fix(bb2); 182 | 183 | assert(bb1.rows() == bb2.rows()); 184 | assert(bb1.rows() == score.rows()); 185 | assert(bb1.rows() == new_reg.rows()); 186 | assert(bb1.cols() == 2); 187 | assert(bb2.cols() == 2); 188 | assert(score.cols() == 1); 189 | assert(new_reg.cols() == 4); 190 | 191 | boxes.resize(bb1.rows(), 9); 192 | boxes << bb1, bb2, score, new_reg; 193 | 194 | //cout << "score:\n"<< score << endl; 195 | //cout << "reg:\n" << new_reg << endl; 196 | //cout << "bb1:\n" << bb1 << endl; 197 | //cout << "bb2:\n" << bb2 << endl; 198 | } 199 | 200 | void drawBoxes(Mat &im, MatrixXd &boxes) 201 | { 202 | for (int i = 0; i < boxes.rows(); i++){ 203 | rectangle(im, Point((int)boxes(i,0), (int)boxes(i,1)), Point((int)boxes(i,2), 204 | (int)boxes(i,3)), Scalar(0,255,0)); 205 | } 206 | } 207 | 208 | void drawBoxes(Mat &im, vector> &boxes) 209 | { 210 | for (int i = 0; i < boxes.size(); i++){ 211 | rectangle(im, Point(boxes[i][0], boxes[i][1]), Point(boxes[i][2], 212 | boxes[i][3]), Scalar(0,0,255), 1); 213 | } 214 | } 215 | 216 | void drawPoints(Mat &im, MatrixXd &points) 217 | { 218 | for (int i = 0; i < points.rows(); i++){ 219 | for (int j = 0; j < 5; j++){ 220 | circle(im, Point((int)points(i,j), (int)points(i,j+5)), 2, Scalar(0,255,0)); 221 | } 222 | } 223 | } 224 | 225 | void drawPoints(Mat &im, vector> &points) 226 | { 227 | for (int i = 0; i < points.size(); i++){ 228 | for (int j = 0; j < 5; j++){ 229 | circle(im, Point((int)points[i][j], (int)points[i][j+5]), 2, Scalar(0,255,0)); 230 | } 231 | } 232 | } 233 | 234 | void _prepareData(shared_ptr>& net, const Mat& img) 235 | { 236 | // 1. reshape data layer 237 | int height = img.rows; 238 | int width = img.cols; 239 | caffe::Blob* input_layer = net->input_blobs()[0]; 240 | input_layer->Reshape(1, 3, height, width); 241 | 242 | // 2. link input data 243 | std::vector input_channels; 244 | float* input_data = input_layer->mutable_cpu_data(); 245 | for (int i = 0; i < input_layer->channels(); ++i) { 246 | cv::Mat channel(height, width, CV_32FC1, input_data); 247 | input_channels.push_back(channel); 248 | input_data += width * height; 249 | } 250 | 251 | // 3. put img to data layer 252 | Mat sample_float; 253 | img.convertTo(sample_float, CV_32FC3); 254 | split(sample_float, input_channels); 255 | CHECK(reinterpret_cast(input_channels.at(0).data) 256 | == net->input_blobs()[0]->cpu_data()) 257 | << "Input channels are not wrapping the input layer of the network."; 258 | } 259 | 260 | void _prepareData2(shared_ptr>& net, const vector& imgs) 261 | { 262 | assert(imgs.size() > 0); 263 | // 1. reshape data layer 264 | int height = imgs[0].rows; 265 | int width = imgs[0].cols; 266 | int numbox = imgs.size(); 267 | caffe::Blob* input_layer = net->input_blobs()[0]; 268 | input_layer->Reshape(numbox, 3, height, width); 269 | 270 | // 1.5 transpose imgs 271 | for (int i = 0; i < numbox; i++){ 272 | 273 | } 274 | 275 | // 2. link input data and put into img data 276 | vector> input_all_imgs; 277 | float* input_data = input_layer->mutable_cpu_data(); 278 | for (int i = 0; i < numbox; i++){ 279 | vector input_channels; 280 | for (int j = 0; j < input_layer->channels(); j++){ 281 | Mat channel(height, width, CV_32FC1, input_data); 282 | input_channels.push_back(channel); 283 | input_data += width * height; 284 | } 285 | split(imgs[i], input_channels); 286 | input_all_imgs.push_back(input_channels); 287 | } 288 | CHECK(reinterpret_cast(input_all_imgs.at(0).at(0).data) 289 | == net->input_blobs()[0]->cpu_data()) 290 | << "Input channels are not wrapping the input layer of the network."; 291 | } 292 | 293 | void _stage1(Mat &img_mat, int minsize, shared_ptr> PNet, 294 | vector &threshold, bool fastresize, float factor, MatrixXd &total_boxes) 295 | { 296 | int factor_count = 0; 297 | int h = img_mat.rows; 298 | int w = img_mat.cols; 299 | int minl = std::min(h, w); 300 | 301 | float m = 12.0 / minsize; 302 | minl *= m; 303 | 304 | // create scale pyramid 305 | vector scales; 306 | while (minl >= 12){ 307 | scales.push_back(m * std::pow(factor, factor_count)); 308 | minl *= factor; 309 | factor_count++; 310 | } 311 | 312 | for (auto scale : scales){ 313 | int hs = (int)std::ceil(h*scale); 314 | int ws = (int)std::ceil(w*scale); 315 | Mat im_data; 316 | img_mat.convertTo(im_data, CV_32FC3); 317 | if (fastresize){ 318 | im_data = (im_data - 127.5) * 0.0078125; 319 | resize(im_data, im_data, Size(ws, hs)); 320 | } 321 | else{ 322 | resize(im_data, im_data, Size(ws, hs)); 323 | im_data = (im_data - 127.5) * 0.0078125; 324 | } 325 | 326 | CHECK_EQ(PNet->num_inputs(), 1) << "Network should have exactly one input."; 327 | CHECK_EQ(PNet->num_outputs(), 2) << "Network should have exactly two output."; 328 | 329 | Mat im_t = Mat(im_data.cols, im_data.rows, CV_32F); 330 | transpose(im_data, im_t); 331 | _prepareData(PNet, im_t); 332 | 333 | //PNet->Forward(); 334 | PNet->ForwardPrefilled(); 335 | 336 | caffe::Blob* conv4_2 = PNet->output_blobs()[0]; // 1*4*height*width 337 | caffe::Blob* prob1 = PNet->output_blobs()[1]; // 1*2*height*width 338 | 339 | //cout << "PNet prob1 height:" << prob1->height() << endl; 340 | //cout << "PNet conv4-2 height:" << conv4_2->height() << endl; 341 | 342 | // debug prob1 343 | //debug_blob(prob1); 344 | //debug_blob(conv4_2); 345 | 346 | MatrixXd map; 347 | vector reg; 348 | convertToMatrix(prob1, conv4_2, map, reg); 349 | MatrixXd boxes; 350 | generateBoundingBox(map, reg, scale, threshold[0], boxes); 351 | 352 | if (boxes.rows() > 0){ 353 | vector pick; 354 | nms(boxes, 0.5, "Union", pick); 355 | if (pick.size() > 0){ 356 | _select(boxes, boxes, pick); 357 | } 358 | } 359 | 360 | MatrixXd t(total_boxes.rows() + boxes.rows(), boxes.cols()); 361 | t << total_boxes, 362 | boxes; 363 | total_boxes.resize(t.rows(), t.cols()); 364 | total_boxes << t; 365 | } 366 | } 367 | 368 | void _stage2(Mat &img_mat, shared_ptr> RNet, 369 | vector &threshold, MatrixXd &total_boxes) 370 | { 371 | Mat im_data; 372 | img_mat.convertTo(im_data, CV_32FC3); 373 | 374 | vector pick; 375 | nms(total_boxes, 0.7, "Union", pick); 376 | _select(total_boxes, total_boxes, pick); 377 | 378 | #ifdef DEBUG_MTCNN 379 | cout << "[2]: " << total_boxes.rows() << endl; 380 | #endif 381 | 382 | // using regression, convert n*9 to n*5 383 | MatrixXd regh = total_boxes.middleCols(3, 1) - total_boxes.middleCols(1, 1); 384 | MatrixXd regw = total_boxes.middleCols(2, 1) - total_boxes.middleCols(0, 1); 385 | MatrixXd t1 = total_boxes.middleCols(0, 1) + regw.cwiseProduct(total_boxes.middleCols(5, 1)); 386 | MatrixXd t2 = total_boxes.middleCols(1, 1) + regh.cwiseProduct(total_boxes.middleCols(6, 1)); 387 | MatrixXd t3 = total_boxes.middleCols(2, 1) + regw.cwiseProduct(total_boxes.middleCols(7, 1)); 388 | MatrixXd t4 = total_boxes.middleCols(3, 1) + regh.cwiseProduct(total_boxes.middleCols(8, 1)); 389 | MatrixXd t5 = total_boxes.middleCols(4, 1); 390 | total_boxes.resize(total_boxes.rows(), 5); 391 | total_boxes << t1, t2, t3, t4, t5; 392 | rerec(total_boxes); 393 | 394 | #ifdef DEBUG_MTCNN 395 | cout << "[4]: " << total_boxes.rows() << endl; 396 | #endif 397 | 398 | MatrixXd pad_params; 399 | pad(total_boxes, img_mat.cols, img_mat.rows, pad_params); 400 | // pad_params: 0 dy, 1 edy, 2 dx, 3 edx, 4 y, 5 ey, 6 x, 7 ex, 8 tmpw, 9 tmph; 401 | 402 | vector imgs; 403 | for (int i = 0; i < total_boxes.rows(); i++){ 404 | Mat tmp = Mat::zeros(pad_params.col(9)[i], pad_params.col(8)[i], CV_32FC3); 405 | tmp = im_data(Range(pad_params.col(4)[i], pad_params.col(5)[i] + 1), 406 | Range(pad_params.col(6)[i], pad_params.col(7)[i] + 1)); 407 | Mat tmp_resize; 408 | resize(tmp, tmp_resize, Size(24, 24)); 409 | Mat tmp_float; 410 | tmp_resize.convertTo(tmp_float, CV_32FC3); 411 | tmp_float = (tmp_float - 127.5) * 0.0078125; 412 | transpose(tmp_float, tmp_float); 413 | imgs.push_back(tmp_float); 414 | } 415 | 416 | _prepareData2(RNet, imgs); 417 | 418 | //debug_blob(RNet->input_blobs()[0]); 419 | 420 | //RNet->Forward(); 421 | RNet->ForwardPrefilled(); 422 | caffe::Blob* conv5_2 = RNet->output_blobs()[0]; 423 | caffe::Blob* prob1 = RNet->output_blobs()[1]; 424 | 425 | //debug_blob(conv5_2); 426 | //debug_blob(prob1); 427 | 428 | //use prob1 to filter total_boxes 429 | //score = out['prob1'][:,1] 430 | vector score; 431 | convertToVector(prob1, score); 432 | 433 | #ifdef DEBUG_MTCNN 434 | printVector(score, "score"); 435 | #endif 436 | 437 | vector pass_t; 438 | _find(score, threshold[1], pass_t); 439 | 440 | filter(total_boxes, pass_t, score); 441 | 442 | #ifdef DEBUG_MTCNN 443 | printVector(pass_t, "pass_t"); 444 | #endif 445 | 446 | #ifdef DEBUG_MTCNN 447 | cout << "[5]:" << total_boxes.rows() << endl; 448 | #endif 449 | 450 | // use conv5-2 to bbreg 451 | MatrixXd mv; 452 | getMV(conv5_2, mv, pass_t); // 4*N 453 | if (total_boxes.rows() > 0){ 454 | vector pick; 455 | nms(total_boxes, 0.7, "Union", pick); 456 | if (pick.size() > 0){ 457 | _select(total_boxes, total_boxes, pick); 458 | _select(mv, mv, pick); 459 | #ifdef DEBUG_MTCNN 460 | cout << "[6]:" << total_boxes.rows() << endl; 461 | #endif 462 | bbreg(total_boxes, mv); 463 | #ifdef DEBUG_MTCNN 464 | cout << "[7]:" << total_boxes.rows() << endl; 465 | #endif 466 | rerec(total_boxes); 467 | #ifdef DEBUG_MTCNN 468 | cout << "[8]:" << total_boxes.rows() << endl; 469 | #endif 470 | } 471 | } 472 | } 473 | 474 | 475 | 476 | void _stage3(Mat &img_mat, shared_ptr> ONet, 477 | vector &threshold, MatrixXd &total_boxes, MatrixXd &total_points) 478 | { 479 | MatrixXd pad_params; 480 | pad(total_boxes, img_mat.cols, img_mat.rows, pad_params); 481 | // pad_params: 0 dy, 1 edy, 2 dx, 3 edx, 4 y, 5 ey, 6 x, 7 ex, 8 tmpw, 9 tmph; 482 | //cout << pad_params; 483 | 484 | vector imgs; 485 | for (int i = 0; i < total_boxes.rows(); i++){ 486 | Mat tmp = Mat::zeros(pad_params.col(9)[i], pad_params.col(8)[i], CV_32FC3); 487 | tmp = img_mat(Range(pad_params.col(4)[i], pad_params.col(5)[i] + 1), 488 | Range(pad_params.col(6)[i], pad_params.col(7)[i] + 1)); 489 | Mat tmp_resize; 490 | resize(tmp, tmp_resize, Size(48, 48)); 491 | Mat tmp_float; 492 | tmp_resize.convertTo(tmp_float, CV_32FC3); 493 | tmp_float = (tmp_float - 127.5) * 0.0078125; 494 | transpose(tmp_float, tmp_float); 495 | imgs.push_back(tmp_float); 496 | } 497 | 498 | _prepareData2(ONet, imgs); 499 | //ONet->Forward(); 500 | ONet->ForwardPrefilled(); 501 | // face bounding box [y1, x1, y2, x2] 502 | caffe::Blob* conv6_2 = ONet->output_blobs()[0]; // 4 503 | // facial landmark point [x1, x2, x3, x4, x5, y1, y2, y3, y4, y5] 0 ~ 1 (normalized) 504 | caffe::Blob* conv6_3 = ONet->output_blobs()[1]; // 10 505 | // face classification [not face, face] 506 | caffe::Blob* prob1 = ONet->output_blobs()[2]; // 2 507 | 508 | //use prob1 to filter total_boxes 509 | vector score; 510 | 511 | convertToVector(prob1, score); 512 | 513 | #ifdef DEBUG_MTCNN 514 | printVector(score, "score"); 515 | #endif 516 | 517 | vector pass_t; 518 | _find(score, threshold[2], pass_t); 519 | filter(total_boxes, pass_t, score); 520 | 521 | #ifdef DEBUG_MTCNN 522 | printVector(pass_t, "pass_t"); 523 | #endif 524 | 525 | #ifdef DEBUG_MTCNN 526 | cout << "[9]:" << total_boxes.rows() << endl; 527 | #endif 528 | 529 | // use conv6-2 to bbreg 530 | // use conv6-3 to points 531 | 532 | MatrixXd mv; 533 | MatrixXd mv_points; 534 | getMV(conv6_2, mv, pass_t); 535 | getMV(conv6_3, mv_points, pass_t); 536 | 537 | total_points = mv_points; 538 | 539 | denormalize(total_boxes, total_points); 540 | 541 | if (total_boxes.rows() > 0){ 542 | bbreg(total_boxes, mv); 543 | 544 | #ifdef DEBUG_MTCNN 545 | cout << "[10]:" << total_boxes.rows() << endl; 546 | #endif 547 | vector pick; 548 | nms(total_boxes, 0.7, "Min", pick); 549 | if (pick.size() > 0){ 550 | _select(total_boxes, total_boxes, pick); 551 | _select(total_points, total_points, pick); 552 | } 553 | 554 | #ifdef DEBUG_MTCNN 555 | cout << "[11]:" << total_boxes.rows() << endl; 556 | cout << "[12]:" << total_points.rows() << endl; 557 | #endif 558 | } 559 | 560 | } 561 | 562 | void detect_face(Mat &img_mat, int minsize, 563 | shared_ptr> PNet, shared_ptr> RNet, shared_ptr> ONet, 564 | vector threshold, bool fastresize, float factor, MatrixXd &boxes, MatrixXd &points) 565 | { 566 | MatrixXd total_boxes; 567 | MatrixXd total_points; 568 | total_boxes.resize(0, 9); 569 | total_points.resize(0, 10); 570 | _stage1(img_mat, minsize, PNet, threshold, fastresize, factor, total_boxes); 571 | 572 | if(total_boxes.rows() > 0) 573 | _stage2(img_mat, RNet, threshold, total_boxes); 574 | 575 | if (total_boxes.rows() > 0) 576 | _stage3(img_mat, ONet, threshold, total_boxes, total_points); 577 | 578 | //cout << "total_boxes num:" << total_boxes.rows() << endl; 579 | //cout << total_boxes << endl; 580 | drawBoxes(img_mat, total_boxes); 581 | boxes = total_boxes; 582 | 583 | drawPoints(img_mat, total_points); 584 | points = total_points; 585 | } 586 | 587 | /* 588 | * FaceDetector 589 | */ 590 | 591 | void FaceDetector::detect(Mat& _img, vector>& boxes, vector>& points) 592 | { 593 | Mat img; 594 | _img.copyTo(img); 595 | cvtColor(img, img, CV_BGR2RGB); 596 | 597 | MatrixXd boundingboxes; 598 | MatrixXd facialkeypoints; 599 | detect_face(img, minsize, PNet, RNet, ONet, threshold, false, factor, boundingboxes, facialkeypoints); 600 | //cout << "boundingboxes:\n" << boundingboxes << endl; 601 | for (int i = 0; i < boundingboxes.rows(); i++){ 602 | vector box; 603 | box.resize(5); 604 | assert(boundingboxes.cols() >= 5); 605 | for (int j = 0; j < 5; j++){ 606 | box[j] = (int)boundingboxes(i, j); 607 | } 608 | boxes.push_back(box); 609 | } 610 | 611 | for (int i = 0; i < facialkeypoints.rows(); i++){ 612 | vector point; 613 | point.resize(10); 614 | assert(facialkeypoints.cols() >= 10); 615 | for (int j = 0; j < 10; j++){ 616 | point[j] = (int)facialkeypoints(i, j); 617 | } 618 | points.push_back(point); 619 | } 620 | } 621 | 622 | void FaceDetector::init() 623 | { 624 | //Eigen::initParallel(); 625 | 626 | threshold.push_back(0.6); 627 | threshold.push_back(0.7); 628 | threshold.push_back(0.7); 629 | factor = 0.709; 630 | minsize = 20; 631 | fastresize = false; 632 | #ifdef CPU_ONLY 633 | caffe::Caffe::set_mode(caffe::Caffe::CPU); 634 | #else 635 | caffe::Caffe::set_mode(caffe::Caffe::GPU); 636 | #endif 637 | 638 | PNet.reset(new caffe::Net(model_path + "/det1.prototxt", caffe::TEST)); 639 | PNet->CopyTrainedLayersFrom(model_path + "/det1.caffemodel"); 640 | RNet.reset(new caffe::Net(model_path + "/det2.prototxt", caffe::TEST)); 641 | RNet->CopyTrainedLayersFrom(model_path + "/det2.caffemodel"); 642 | ONet.reset(new caffe::Net(model_path + "/det3.prototxt", caffe::TEST)); 643 | ONet->CopyTrainedLayersFrom(model_path + "/det3.caffemodel"); 644 | } 645 | --------------------------------------------------------------------------------