├── .gitattributes ├── .gitignore ├── CMakeLists.txt ├── LICENSE ├── README.md ├── dist └── main ├── include └── FaceDetectFMTCNN.hpp ├── make.sh ├── src ├── FaceDetectFMTCNN.cpp └── main.cpp └── static ├── model ├── det1.prototxt ├── det1_.caffemodel ├── det1_.prototxt ├── det1_half.caffemodel ├── det2.prototxt ├── det2_half.caffemodel ├── det3-half.caffemodel ├── det3-half.prototxt ├── det3.caffemodel ├── det3.prototxt ├── sphereface_deploy.prototxt └── sphereface_model.caffemodel └── test.jpeg /.gitattributes: -------------------------------------------------------------------------------- 1 | *.caffemodel filter=lfs diff=lfs merge=lfs -text 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | CMakeLists.txt.user 2 | CMakeCache.txt 3 | CMakeFiles 4 | CMakeScripts 5 | Testing 6 | Makefile 7 | cmake_install.cmake 8 | install_manifest.txt 9 | compile_commands.json 10 | CTestTestfile.cmake -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # CMake 版本号 2 | cmake_minimum_required(VERSION 3.5) 3 | 4 | # 项目名称 5 | PROJECT(face-recognition) 6 | 7 | # 二进制文件 8 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ./dist) 9 | 10 | # 引入 OpenCV 包 11 | find_package(OpenCV REQUIRED) 12 | 13 | # 头文件 14 | include_directories( 15 | ${OpenCV_INCLUDE_DIRS}, 16 | ${CMAKE_CURRENT_LIST_DIR}/include 17 | ) 18 | 19 | # 源文件 20 | aux_source_directory(./src src) 21 | add_executable(main ${src}) 22 | 23 | # 库文件 24 | link_directories(${OpenCV_LIBRARY_DIRS}) 25 | target_link_libraries(main ${OpenCV_LIBS}) -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2018-present, Zhi Zhang 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 13 | all 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 21 | THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # **Face Recognition via Opencv4** 2 | 3 | This project provides a face recoganization system via opencv4. 4 | 5 | The solution involves 4 parts: 6 | 7 | 1. face detection —— FMTCNN 8 | 2. face calibration —— Affine Transform 9 | 3. face feature extraction —— SphereFace 10 | 4. face classification —— Cosine Similarity 11 | 12 | ## How to run 13 | 14 | Just run the command in project 15 | 16 | ``` 17 | sh make.sh 18 | ``` 19 | 20 | ## License 21 | 22 | [MIT](http://opensource.org/licenses/MIT) 23 | 24 | Copyright (c) 2018-present, Zhi Zhang 25 | -------------------------------------------------------------------------------- /dist/main: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tczhangzhi/face-recognition/ac0ddb395432dd42a3d41f5c1209d481a5464942/dist/main -------------------------------------------------------------------------------- /include/FaceDetectFMTCNN.hpp: -------------------------------------------------------------------------------- 1 | #ifndef FaceDetectFMTCNN_hpp 2 | #define FaceDetectFMTCNN_hpp 3 | 4 | #include 5 | #include 6 | 7 | using namespace std; 8 | using namespace cv; 9 | 10 | typedef struct FaceBox { 11 | float xmin; 12 | float ymin; 13 | float xmax; 14 | float ymax; 15 | float score; 16 | } FaceBox; 17 | 18 | typedef struct FaceInfo { 19 | float bbox_reg[4]; 20 | float landmark_reg[10]; 21 | float landmark[10]; 22 | FaceBox bbox; 23 | Mat FeatureVector; 24 | } FaceInfo; 25 | 26 | class CFaceDetectFMTCNN { 27 | public: 28 | dnn::Net PNet_; 29 | dnn::Net RNet_; 30 | dnn::Net ONet_; 31 | 32 | vector candidate_boxes_; 33 | vector total_boxes_; 34 | 35 | float factor = 0.709f; 36 | float threshold[3] = { 0.7f, 0.6f, 0.6f }; 37 | int minSize = 12; 38 | 39 | CFaceDetectFMTCNN(void); 40 | ~CFaceDetectFMTCNN(void); 41 | Mat getTformMatrix(float* std_points, float* feat_points); 42 | vector DetectMTCNN(const Mat& image, const int minSize, const float* threshold, const float factor, const int stage); 43 | void RotateFace(Mat image, FaceInfo faceInfoVar, Mat &dstImage); 44 | void NormalizeFace(Mat dstImage, Mat &normalizeImg); 45 | vector ProposalNet(const Mat& img, int min_size, float threshold, float factor); 46 | vector NextStage(const Mat& image, vector &pre_stage_res, int input_w, int input_h, int stage_num, const float threshold); 47 | void BBoxRegression(vector& bboxes); 48 | void BBoxPadSquare(vector& bboxes, int width, int height); 49 | void BBoxPad(vector& bboxes, int width, int height); 50 | void GenerateBBox(Mat* confidence, Mat* reg_box, float scale, float thresh); 51 | vector NMS(vector& bboxes, float thresh, char methodType); 52 | float IoU(float xmin, float ymin, float xmax, float ymax, float xmin_, float ymin_, float xmax_, float ymax_, bool is_iom = false); 53 | void Detect(Mat image, vector &faceInfo); 54 | void DisplayBoxMarks(Mat image, vector FaceInfo); 55 | 56 | 57 | private: 58 | const float pnet_stride = 2; 59 | const float pnet_cell_size = 12; 60 | const int pnet_max_detect_num = 5000; 61 | const float mean_val = 127.5f; 62 | const float std_val = 0.0078125f; 63 | const int step_size = 128; 64 | const string proto_model_dir = "static/model"; 65 | }; 66 | 67 | #endif /* FaceDetectFMTCNN_hpp */ -------------------------------------------------------------------------------- /make.sh: -------------------------------------------------------------------------------- 1 | cmake . -DCMAKE_BUILD_TYPE=Release -DBLAS="Open" -Dpython_version=3 -DCUDA_HOST_COMPILER=/usr/bin/g++-5 -DCUDA_PROPAGATE_HOST_FLAGS=off -DCMAKE_CXX_FLAGS="-std=c++11" 2 | make 3 | ./dist/main -------------------------------------------------------------------------------- /src/FaceDetectFMTCNN.cpp: -------------------------------------------------------------------------------- 1 | #include "FaceDetectFMTCNN.hpp" 2 | 3 | #define IMGNORHEIGHT 112 4 | #define IMGNORWIDTH 96 5 | 6 | CFaceDetectFMTCNN::CFaceDetectFMTCNN() { 7 | PNet_ = dnn::readNetFromCaffe(proto_model_dir + "/det1_.prototxt", proto_model_dir + "/det1_.caffemodel"); 8 | RNet_ = dnn::readNetFromCaffe(proto_model_dir + "/det2.prototxt", proto_model_dir + "/det2_half.caffemodel"); 9 | ONet_ = dnn::readNetFromCaffe(proto_model_dir + "/det3-half.prototxt", proto_model_dir + "/det3-half.caffemodel"); 10 | } 11 | 12 | 13 | float CFaceDetectFMTCNN::IoU(float xmin, float ymin, float xmax, float ymax, 14 | float xmin_, float ymin_, float xmax_, float ymax_, bool is_iom) { 15 | float iw = min(xmax, xmax_) - max(xmin, xmin_) + 1; 16 | float ih = min(ymax, ymax_) - max(ymin, ymin_) + 1; 17 | if (iw <= 0 || ih <= 0) 18 | return 0; 19 | float s = iw*ih; 20 | if (is_iom) { 21 | float ov = s / min((xmax - xmin + 1)*(ymax - ymin + 1), (xmax_ - xmin_ + 1)*(ymax_ - ymin_ + 1)); 22 | return ov; 23 | } 24 | else { 25 | float ov = s / ((xmax - xmin + 1)*(ymax - ymin + 1) + (xmax_ - xmin_ + 1)*(ymax_ - ymin_ + 1) - s); 26 | return ov; 27 | } 28 | } 29 | void CFaceDetectFMTCNN::BBoxRegression(vector& bboxes) { 30 | for (int i = 0; i < bboxes.size(); ++i) { 31 | FaceBox &bbox = bboxes[i].bbox; 32 | float *bbox_reg = bboxes[i].bbox_reg; 33 | float w = bbox.xmax - bbox.xmin + 1; 34 | float h = bbox.ymax - bbox.ymin + 1; 35 | bbox.xmin += bbox_reg[0] * w; 36 | bbox.ymin += bbox_reg[1] * h; 37 | bbox.xmax += bbox_reg[2] * w; 38 | bbox.ymax += bbox_reg[3] * h; 39 | } 40 | } 41 | void CFaceDetectFMTCNN::BBoxPad(vector& bboxes, int width, int height) { 42 | for (int i = 0; i < bboxes.size(); ++i) { 43 | FaceBox &bbox = bboxes[i].bbox; 44 | bbox.xmin = round(max(bbox.xmin, 0.f)); 45 | bbox.ymin = round(max(bbox.ymin, 0.f)); 46 | bbox.xmax = round(min(bbox.xmax, width - 1.f)); 47 | bbox.ymax = round(min(bbox.ymax, height - 1.f)); 48 | } 49 | } 50 | void CFaceDetectFMTCNN::BBoxPadSquare(vector& bboxes, int width, int height) { 51 | for (int i = 0; i < bboxes.size(); ++i) { 52 | FaceBox &bbox = bboxes[i].bbox; 53 | float w = bbox.xmax - bbox.xmin + 1; 54 | float h = bbox.ymax - bbox.ymin + 1; 55 | float side = h>w ? h : w; 56 | bbox.xmin = round(max(bbox.xmin + (w - side)*0.5f, 0.f)); 57 | 58 | bbox.ymin = round(max(bbox.ymin + (h - side)*0.5f, 0.f)); 59 | bbox.xmax = round(min(bbox.xmin + side - 1, width - 1.f)); 60 | bbox.ymax = round(min(bbox.ymin + side - 1, height - 1.f)); 61 | } 62 | } 63 | void CFaceDetectFMTCNN::GenerateBBox(Mat* confidence, Mat* reg_box, 64 | float scale, float thresh) { 65 | int feature_map_w_ = confidence->size[3]; 66 | int feature_map_h_ = confidence->size[2]; 67 | int spatical_size = feature_map_w_*feature_map_h_; 68 | 69 | cout<size; 70 | cout<<" "<data); 73 | confidence_data += spatical_size; 74 | 75 | Mat image(feature_map_h_,feature_map_w_,confidence->type()); 76 | 77 | image.data =(unsigned char*)(confidence_data); 78 | 79 | const float* reg_data = (float*)(reg_box->data); 80 | candidate_boxes_.clear(); 81 | for (int i = 0; i b.bbox.score; 105 | } 106 | 107 | vector CFaceDetectFMTCNN::NMS(vector& bboxes, 108 | float thresh, char methodType) { 109 | vector bboxes_nms; 110 | if (bboxes.size() == 0) { 111 | return bboxes_nms; 112 | } 113 | sort(bboxes.begin(), bboxes.end(), CompareBBox); 114 | 115 | int32_t select_idx = 0; 116 | int32_t num_bbox = static_cast(bboxes.size()); 117 | vector mask_merged(num_bbox, 0); 118 | bool all_merged = false; 119 | 120 | while (!all_merged) { 121 | while (select_idx < num_bbox && mask_merged[select_idx] == 1) 122 | select_idx++; 123 | if (select_idx == num_bbox) { 124 | all_merged = true; 125 | continue; 126 | } 127 | 128 | bboxes_nms.push_back(bboxes[select_idx]); 129 | mask_merged[select_idx] = 1; 130 | 131 | FaceBox select_bbox = bboxes[select_idx].bbox; 132 | float area1 = static_cast((select_bbox.xmax - select_bbox.xmin + 1) * (select_bbox.ymax - select_bbox.ymin + 1)); 133 | float x1 = static_cast(select_bbox.xmin); 134 | float y1 = static_cast(select_bbox.ymin); 135 | float x2 = static_cast(select_bbox.xmax); 136 | float y2 = static_cast(select_bbox.ymax); 137 | 138 | select_idx++; 139 | for (int32_t i = select_idx; i < num_bbox; i++) { 140 | if (mask_merged[i] == 1) 141 | continue; 142 | 143 | FaceBox & bbox_i = bboxes[i].bbox; 144 | float x = max(x1, static_cast(bbox_i.xmin)); 145 | float y = max(y1, static_cast(bbox_i.ymin)); 146 | float w = min(x2, static_cast(bbox_i.xmax)) - x + 1; 147 | float h = min(y2, static_cast(bbox_i.ymax)) - y + 1; 148 | if (w <= 0 || h <= 0) 149 | continue; 150 | 151 | float area2 = static_cast((bbox_i.xmax - bbox_i.xmin + 1) * (bbox_i.ymax - bbox_i.ymin + 1)); 152 | float area_intersect = w * h; 153 | 154 | switch (methodType) { 155 | case 'u': 156 | if (static_cast(area_intersect) / (area1 + area2 - area_intersect) > thresh) 157 | mask_merged[i] = 1; 158 | break; 159 | case 'm': 160 | if (static_cast(area_intersect) / min(area1, area2) > thresh) 161 | mask_merged[i] = 1; 162 | break; 163 | default: 164 | break; 165 | } 166 | } 167 | } 168 | return bboxes_nms; 169 | } 170 | 171 | vector CFaceDetectFMTCNN::NextStage(const Mat& image, vector &pre_stage_res, int input_w, int input_h, int stage_num, const float threshold) { 172 | vector res; 173 | int batch_size = (int)pre_stage_res.size(); 174 | if (batch_size == 0) 175 | return res; 176 | Mat* input_layer = nullptr; 177 | Mat* confidence = nullptr; 178 | Mat* reg_box = nullptr; 179 | Mat* reg_landmark = nullptr; 180 | 181 | vector< Mat > targets_blobs; 182 | 183 | 184 | 185 | switch (stage_num) { 186 | case 2: { 187 | }break; 188 | case 3: { 189 | }break; 190 | default: 191 | return res; 192 | break; 193 | } 194 | int spatial_size = input_h*input_w; 195 | 196 | vector inputs; 197 | 198 | for (int n = 0; n < batch_size; ++n) { 199 | FaceBox &box = pre_stage_res[n].bbox; 200 | Mat roi = image(Rect(Point((int)box.xmin, (int)box.ymin), Point((int)box.xmax, (int)box.ymax))).clone(); 201 | resize(roi, roi, Size(input_w, input_h)); 202 | inputs.push_back(roi); 203 | } 204 | 205 | Mat blob_input = dnn::blobFromImages(inputs, std_val,Size(),Scalar(mean_val,mean_val,mean_val),false); 206 | 207 | switch (stage_num) { 208 | case 2: { 209 | RNet_.setInput(blob_input, "data"); 210 | const vector< String > targets_node{"conv5-2","prob1"}; 211 | RNet_.forward(targets_blobs,targets_node); 212 | confidence = &targets_blobs[1]; 213 | reg_box = &targets_blobs[0]; 214 | 215 | float* confidence_data = (float*)confidence->data; 216 | }break; 217 | case 3: { 218 | 219 | ONet_.setInput(blob_input, "data"); 220 | const vector< String > targets_node{"conv6-2","conv6-3","prob1"}; 221 | ONet_.forward(targets_blobs,targets_node); 222 | reg_box = &targets_blobs[0]; 223 | reg_landmark = &targets_blobs[1]; 224 | confidence = &targets_blobs[2]; 225 | 226 | }break; 227 | } 228 | 229 | 230 | const float* confidence_data = (float*)confidence->data; 231 | 232 | const float* reg_data = (float*)reg_box->data; 233 | const float* landmark_data = nullptr; 234 | if (reg_landmark) { 235 | landmark_data = (float*)reg_landmark->data; 236 | } 237 | for (int k = 0; k < batch_size; ++k) { 238 | if (confidence_data[2 * k + 1] >= threshold) { 239 | FaceInfo info; 240 | info.bbox.score = confidence_data[2 * k + 1]; 241 | info.bbox.xmin = pre_stage_res[k].bbox.xmin; 242 | info.bbox.ymin = pre_stage_res[k].bbox.ymin; 243 | info.bbox.xmax = pre_stage_res[k].bbox.xmax; 244 | info.bbox.ymax = pre_stage_res[k].bbox.ymax; 245 | for (int i = 0; i < 4; ++i) { 246 | info.bbox_reg[i] = reg_data[4 * k + i]; 247 | } 248 | if (reg_landmark) { 249 | float w = info.bbox.xmax - info.bbox.xmin + 1.f; 250 | float h = info.bbox.ymax - info.bbox.ymin + 1.f; 251 | for (int i = 0; i < 5; ++i){ 252 | info.landmark[2 * i] = landmark_data[10 * k + 2 * i] * w + info.bbox.xmin; 253 | info.landmark[2 * i + 1] = landmark_data[10 * k + 2 * i + 1] * h + info.bbox.ymin; 254 | } 255 | } 256 | res.push_back(info); 257 | } 258 | } 259 | return res; 260 | } 261 | 262 | vector CFaceDetectFMTCNN::ProposalNet(const Mat& img, int minSize, float threshold, float factor) { 263 | Mat resized; 264 | int width = img.cols; 265 | int height = img.rows; 266 | float scale = 12.f / minSize; 267 | float minWH = min(height, width) *scale; 268 | vector scales; 269 | while (minWH >= 12) { 270 | scales.push_back(scale); 271 | minWH *= factor; 272 | scale *= factor; 273 | } 274 | 275 | total_boxes_.clear(); 276 | for (int i = 0; i < scales.size(); i++) { 277 | int ws = (int)ceil(width*scales[i]); 278 | int hs = (int)ceil(height*scales[i]); 279 | resize(img, resized, Size(ws, hs), 0, 0, INTER_LINEAR); 280 | 281 | 282 | Mat inputBlob = dnn::blobFromImage(resized, 1/255.0,Size(),Scalar(0,0,0),false); 283 | 284 | float* c = (float*)inputBlob.data; 285 | PNet_.setInput(inputBlob, "data"); 286 | const vector< String > targets_node{"conv4-2","prob1"}; 287 | vector< Mat > targets_blobs; 288 | PNet_.forward(targets_blobs,targets_node); 289 | 290 | Mat prob = targets_blobs[1] 291 | ; 292 | Mat reg = targets_blobs[0]; 293 | GenerateBBox(&prob, ®, scales[i], threshold); 294 | vector bboxes_nms = NMS(candidate_boxes_, 0.5, 'u'); 295 | if (bboxes_nms.size()>0) { 296 | total_boxes_.insert(total_boxes_.end(), bboxes_nms.begin(), bboxes_nms.end()); 297 | } 298 | } 299 | int num_box = (int)total_boxes_.size(); 300 | 301 | vector res_boxes; 302 | if (num_box != 0) { 303 | res_boxes = NMS(total_boxes_, 0.7f, 'u'); 304 | BBoxRegression(res_boxes); 305 | BBoxPadSquare(res_boxes, width, height); 306 | } 307 | return res_boxes; 308 | } 309 | 310 | vector CFaceDetectFMTCNN::DetectMTCNN(const Mat& image, const int minSize, const float* threshold, const float factor, const int stage) { 311 | vector pnet_res; 312 | vector rnet_res; 313 | vector onet_res; 314 | if (stage >= 1){ 315 | pnet_res = ProposalNet(image, minSize, threshold[0], factor); 316 | } 317 | if (stage >= 2 && pnet_res.size()>0){ 318 | if (pnet_max_detect_num < (int)pnet_res.size()){ 319 | pnet_res.resize(pnet_max_detect_num); 320 | } 321 | int num = (int)pnet_res.size(); 322 | int size = (int)ceil(1.f*num / step_size); 323 | for (int iter = 0; iter < size; ++iter){ 324 | int start = iter*step_size; 325 | int end = min(start + step_size, num); 326 | vector input(pnet_res.begin() + start, pnet_res.begin() + end); 327 | vector res = NextStage(image, input, 24, 24, 2, threshold[1]); 328 | rnet_res.insert(rnet_res.end(), res.begin(), res.end()); 329 | } 330 | rnet_res = NMS(rnet_res, 0.4f, 'm'); 331 | BBoxRegression(rnet_res); 332 | BBoxPadSquare(rnet_res, image.cols, image.rows); 333 | 334 | } 335 | if (stage >= 3 && rnet_res.size()>0){ 336 | int num = (int)rnet_res.size(); 337 | int size = (int)ceil(1.f*num / step_size); 338 | for (int iter = 0; iter < size; ++iter){ 339 | int start = iter*step_size; 340 | int end = min(start + step_size, num); 341 | vector input(rnet_res.begin() + start, rnet_res.begin() + end); 342 | vector res = NextStage(image, input, 48, 48, 3, threshold[2]); 343 | onet_res.insert(onet_res.end(), res.begin(), res.end()); 344 | } 345 | BBoxRegression(onet_res); 346 | onet_res = NMS(onet_res, 0.4f, 'm'); 347 | BBoxPad(onet_res, image.cols, image.rows); 348 | 349 | } 350 | if (stage == 1){ 351 | return pnet_res; 352 | } 353 | else if (stage == 2){ 354 | return rnet_res; 355 | } 356 | else if (stage == 3){ 357 | return onet_res; 358 | } 359 | else{ 360 | return onet_res; 361 | } 362 | } 363 | 364 | void CFaceDetectFMTCNN::RotateFace(Mat image, FaceInfo faceInfoVar, Mat &dstImage) 365 | { 366 | float std_points[10] = {30.2946, 65.5318, 48.0252, 33.5493, 62.7299, 51.6963, 51.5014, 71.7366, 92.3655, 92.2041}; 367 | 368 | float facial_points[10]; 369 | for (int i = 0; i < 5; i++) { 370 | facial_points[2 * i] = faceInfoVar.landmark[2 * i]; 371 | facial_points[2 * i + 1] = faceInfoVar.landmark[2 * i + 1]; 372 | } 373 | Mat tform = getTformMatrix(std_points, facial_points); 374 | 375 | warpAffine(image, dstImage, tform, dstImage.size(), 1, 0, Scalar(0)); 376 | } 377 | 378 | void CFaceDetectFMTCNN::NormalizeFace(Mat dstImage, Mat &normalizeImg) 379 | { 380 | Mat subfactor = 127.5 * Mat(IMGNORHEIGHT, IMGNORWIDTH, CV_32FC3, Scalar(1, 1, 1)); 381 | dstImage.convertTo(normalizeImg, CV_32FC3); 382 | normalizeImg = normalizeImg - subfactor; 383 | normalizeImg = normalizeImg / 128; 384 | } 385 | 386 | Mat CFaceDetectFMTCNN::getTformMatrix(float* std_points, float* feat_points) 387 | { 388 | int points_num_ = 5; 389 | double sum_x = 0, sum_y = 0; 390 | double sum_u = 0, sum_v = 0; 391 | double sum_xx_yy = 0; 392 | double sum_ux_vy = 0; 393 | double sum_vx__uy = 0; 394 | for (int c = 0; c < points_num_; ++c) { 395 | int x_off = c * 2; 396 | int y_off = x_off + 1; 397 | sum_x += std_points[c * 2]; 398 | sum_y += std_points[c * 2 + 1]; 399 | sum_u += feat_points[x_off]; 400 | sum_v += feat_points[y_off]; 401 | sum_xx_yy += std_points[c * 2] * std_points[c * 2] + 402 | std_points[c * 2 + 1] * std_points[c * 2 + 1]; 403 | sum_ux_vy += std_points[c * 2] * feat_points[x_off] + 404 | std_points[c * 2 + 1] * feat_points[y_off]; 405 | sum_vx__uy += feat_points[y_off] * std_points[c * 2] - 406 | feat_points[x_off] * std_points[c * 2 + 1]; 407 | } 408 | double q = sum_u - sum_x * sum_ux_vy / sum_xx_yy 409 | + sum_y * sum_vx__uy / sum_xx_yy; 410 | double p = sum_v - sum_y * sum_ux_vy / sum_xx_yy 411 | - sum_x * sum_vx__uy / sum_xx_yy; 412 | double r = points_num_ - (sum_x * sum_x + sum_y * sum_y) / sum_xx_yy; 413 | double a = (sum_ux_vy - sum_x * q / r - sum_y * p / r) / sum_xx_yy; 414 | double b = (sum_vx__uy + sum_y * q / r - sum_x * p / r) / sum_xx_yy; 415 | double c = q / r; 416 | double d = p / r; 417 | 418 | 419 | Mat Tinv = (cv::Mat_(3, 3) << a, b, 0, -b, a, 0, c, d, 1); 420 | Mat T = Tinv.inv(); 421 | Mat res = T.colRange(0, 2).clone(); 422 | return res.t(); 423 | } 424 | 425 | void CFaceDetectFMTCNN::Detect(Mat image, vector &faceInfo) 426 | { 427 | Mat copyImage; 428 | image.copyTo(copyImage); 429 | 430 | faceInfo = DetectMTCNN(image, minSize, threshold, factor, 3); 431 | 432 | for (int i = 0; i < faceInfo.size(); i++) { 433 | int x = (int) faceInfo[i].bbox.xmin; 434 | int y = (int) faceInfo[i].bbox.ymin; 435 | int w = (int) (faceInfo[i].bbox.xmax - faceInfo[i].bbox.xmin + 1); 436 | int h = (int) (faceInfo[i].bbox.ymax - faceInfo[i].bbox.ymin + 1); 437 | rectangle(copyImage, Rect(x, y, w, h), Scalar(255, 0, 0), 2); 438 | } 439 | 440 | imshow("人脸检测结果", copyImage); 441 | waitKey(0); 442 | } 443 | 444 | CFaceDetectFMTCNN::~CFaceDetectFMTCNN(void) 445 | { 446 | } -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | using namespace std; 8 | using namespace cv; 9 | using namespace dnn; 10 | 11 | #include "FaceDetectFMTCNN.hpp" 12 | 13 | #define IMGNORHEIGHT 112 14 | #define IMGNORWIDTH 96 15 | 16 | double CosineSimilarity(Mat& a, Mat& b) 17 | { 18 | double ab = a.dot(b); 19 | double norma=norm(a); 20 | double normb=norm(b); 21 | if(norma!=0 && normb!=0){ 22 | return ab / (norma * normb); 23 | } 24 | return -1; 25 | } 26 | 27 | Mat CaputreFeature(Net net) 28 | { 29 | CFaceDetectFMTCNN detector; 30 | vector faceInfo; 31 | 32 | cout << "捕获摄像头图像:" << endl; 33 | VideoCapture capture(0); 34 | Mat frame; 35 | capture >> frame; 36 | imshow("摄像头捕捉结果", frame); 37 | detector.Detect(frame, faceInfo); 38 | 39 | for (int i = 0; i < faceInfo.size(); i++) { 40 | FaceInfo faceInfoVar = faceInfo[i]; 41 | Mat dstImage(IMGNORHEIGHT, IMGNORWIDTH, CV_8UC3); 42 | detector.RotateFace(frame, faceInfoVar, dstImage); 43 | 44 | Mat normalizeImage; 45 | normalizeImage.create(dstImage.size(), CV_32FC3); 46 | detector.NormalizeFace(dstImage, normalizeImage); 47 | 48 | Mat inputBlob = blobFromImage(normalizeImage); 49 | Mat featureOutput; 50 | net.setInput(inputBlob, "data"); 51 | featureOutput = net.forward("fc5"); 52 | 53 | Mat result(IMGNORHEIGHT, IMGNORWIDTH, CV_8UC3); 54 | featureOutput.copyTo(result); 55 | return result; 56 | } 57 | 58 | cout << "出错啦" << endl; 59 | } 60 | 61 | int main(int argc, char* argv[]) 62 | { 63 | Net net; 64 | 65 | string proto_model_dir = "static/model"; 66 | string modelTxt = proto_model_dir + "/sphereface_deploy.prototxt"; 67 | string modelBin = proto_model_dir + "/sphereface_model.caffemodel"; 68 | 69 | net = dnn::readNetFromCaffe(modelTxt, modelBin); 70 | if (net.empty()) { 71 | cerr << "无法加载模型" << endl; 72 | exit(-1); 73 | } 74 | 75 | String imageFile = "static/test.jpeg"; 76 | Mat image = imread(imageFile, 1); 77 | if (image.empty()) { 78 | cerr << "无法加载图像" << endl; 79 | exit(-1); 80 | } 81 | 82 | Mat captureFeature = CaputreFeature(net); 83 | cout << captureFeature << endl; 84 | 85 | CFaceDetectFMTCNN detector; 86 | vector faceInfo; 87 | 88 | cout << "检测所有人脸:" << endl; 89 | detector.Detect(image, faceInfo); 90 | 91 | Mat dstImage(IMGNORHEIGHT, IMGNORWIDTH, CV_8UC3); 92 | 93 | for (int i = 0; i < faceInfo.size(); i++) { 94 | cout << "匹配照片中的图像是否有与该人脸相似的:" << endl; 95 | FaceInfo faceInfoVar = faceInfo[i]; 96 | detector.RotateFace(image, faceInfoVar, dstImage); 97 | 98 | Mat normalizeImage; 99 | normalizeImage.create(dstImage.size(), CV_32FC3); 100 | detector.NormalizeFace(dstImage, normalizeImage); 101 | 102 | Mat inputBlob = blobFromImage(normalizeImage); 103 | Mat featureOutput; 104 | net.setInput(inputBlob, "data"); 105 | featureOutput = net.forward("fc5"); 106 | featureOutput.copyTo(faceInfo[i].FeatureVector); 107 | float similarity = CosineSimilarity(featureOutput, captureFeature); 108 | cout << similarity << endl; 109 | if (similarity > 0.2) { 110 | int x = (int) faceInfo[i].bbox.xmin; 111 | int y = (int) faceInfo[i].bbox.ymin; 112 | int w = (int) (faceInfo[i].bbox.xmax - faceInfo[i].bbox.xmin + 1); 113 | int h = (int) (faceInfo[i].bbox.ymax - faceInfo[i].bbox.ymin + 1); 114 | rectangle(image, Rect(x, y, w, h), Scalar(0, 0, 255), 2); 115 | imshow("匹配结果", image); 116 | waitKey(0); 117 | } 118 | } 119 | 120 | return 0; 121 | } 122 | -------------------------------------------------------------------------------- /static/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 | -------------------------------------------------------------------------------- /static/model/det1_.caffemodel: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:13535969fa9cbdd90986365e8bdc7a8f4267d656aa9161ad5583a54daee47311 3 | size 17198 4 | -------------------------------------------------------------------------------- /static/model/det1_.prototxt: -------------------------------------------------------------------------------- 1 | input: "data" 2 | input_dim: 1 3 | input_dim: 3 4 | input_dim: 12 5 | input_dim: 12 6 | layer { 7 | name: "conv1" 8 | type: "Convolution" 9 | bottom: "data" 10 | top: "conv1" 11 | convolution_param { 12 | num_output: 10 13 | bias_term: true 14 | pad_h: 0 15 | pad_w: 0 16 | kernel_h: 3 17 | kernel_w: 3 18 | stride_h: 1 19 | stride_w: 1 20 | } 21 | } 22 | layer { 23 | name: "batch_normalization_5" 24 | type: "BatchNorm" 25 | bottom: "conv1" 26 | top: "batch_normalization_5" 27 | batch_norm_param { 28 | moving_average_fraction: 0.990000009537 29 | eps: 0.0010000000475 30 | } 31 | } 32 | layer { 33 | name: "batch_normalization_5_scale" 34 | type: "Scale" 35 | bottom: "batch_normalization_5" 36 | top: "batch_normalization_5" 37 | scale_param { 38 | bias_term: true 39 | } 40 | } 41 | layer { 42 | name: "prelu1" 43 | type: "PReLU" 44 | bottom: "batch_normalization_5" 45 | top: "prelu1" 46 | } 47 | layer { 48 | name: "max_pooling2d_3" 49 | type: "Pooling" 50 | bottom: "prelu1" 51 | top: "max_pooling2d_3" 52 | pooling_param { 53 | pool: MAX 54 | kernel_h: 2 55 | kernel_w: 2 56 | stride_h: 2 57 | stride_w: 2 58 | pad_h: 0 59 | pad_w: 0 60 | } 61 | } 62 | layer { 63 | name: "conv2_" 64 | type: "Convolution" 65 | bottom: "max_pooling2d_3" 66 | top: "conv2_" 67 | convolution_param { 68 | num_output: 14 69 | bias_term: true 70 | pad_h: 0 71 | pad_w: 0 72 | kernel_h: 3 73 | kernel_w: 3 74 | stride_h: 1 75 | stride_w: 1 76 | } 77 | } 78 | layer { 79 | name: "batch_normalization_6" 80 | type: "BatchNorm" 81 | bottom: "conv2_" 82 | top: "batch_normalization_6" 83 | batch_norm_param { 84 | moving_average_fraction: 0.990000009537 85 | eps: 0.0010000000475 86 | } 87 | } 88 | layer { 89 | name: "batch_normalization_6_scale" 90 | type: "Scale" 91 | bottom: "batch_normalization_6" 92 | top: "batch_normalization_6" 93 | scale_param { 94 | bias_term: true 95 | } 96 | } 97 | layer { 98 | name: "prelu2" 99 | type: "PReLU" 100 | bottom: "batch_normalization_6" 101 | top: "prelu2" 102 | } 103 | layer { 104 | name: "conv3" 105 | type: "Convolution" 106 | bottom: "prelu2" 107 | top: "conv3" 108 | convolution_param { 109 | num_output: 16 110 | bias_term: true 111 | pad_h: 0 112 | pad_w: 0 113 | kernel_h: 3 114 | kernel_w: 3 115 | stride_h: 1 116 | stride_w: 1 117 | } 118 | } 119 | layer { 120 | name: "batch_normalization_7" 121 | type: "BatchNorm" 122 | bottom: "conv3" 123 | top: "batch_normalization_7" 124 | batch_norm_param { 125 | moving_average_fraction: 0.990000009537 126 | eps: 0.0010000000475 127 | } 128 | } 129 | layer { 130 | name: "batch_normalization_7_scale" 131 | type: "Scale" 132 | bottom: "batch_normalization_7" 133 | top: "batch_normalization_7" 134 | scale_param { 135 | bias_term: true 136 | } 137 | } 138 | layer { 139 | name: "prelu3" 140 | type: "PReLU" 141 | bottom: "batch_normalization_7" 142 | top: "prelu3" 143 | } 144 | layer { 145 | name: "classifier1" 146 | type: "Convolution" 147 | bottom: "prelu3" 148 | top: "classifier1" 149 | convolution_param { 150 | num_output: 2 151 | bias_term: true 152 | pad_h: 0 153 | pad_w: 0 154 | kernel_h: 1 155 | kernel_w: 1 156 | stride_h: 1 157 | stride_w: 1 158 | } 159 | } 160 | layer { 161 | name: "prob1" 162 | type: "Softmax" 163 | bottom: "classifier1" 164 | top: "prob1" 165 | } 166 | layer { 167 | name: "conv4-2" 168 | type: "Convolution" 169 | bottom: "prelu3" 170 | top: "conv4-2" 171 | convolution_param { 172 | num_output: 4 173 | bias_term: true 174 | pad_h: 0 175 | pad_w: 0 176 | kernel_h: 1 177 | kernel_w: 1 178 | stride_h: 1 179 | stride_w: 1 180 | } 181 | } 182 | -------------------------------------------------------------------------------- /static/model/det1_half.caffemodel: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:ed6d79581511c51d98bc78689b22750f7f004713a0ea37bd57c51a4805816470 3 | size 15279 4 | -------------------------------------------------------------------------------- /static/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 | layer { 9 | name: "conv1" 10 | type: "Convolution" 11 | bottom: "data" 12 | top: "conv1" 13 | param { 14 | lr_mult: 0 15 | decay_mult: 0 16 | } 17 | param { 18 | lr_mult: 0 19 | decay_mult: 0 20 | } 21 | convolution_param { 22 | num_output: 28 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 | propagate_down: true 40 | } 41 | layer { 42 | name: "pool1" 43 | type: "Pooling" 44 | bottom: "conv1" 45 | top: "pool1" 46 | pooling_param { 47 | pool: MAX 48 | kernel_size: 3 49 | stride: 2 50 | } 51 | } 52 | 53 | layer { 54 | name: "conv2" 55 | type: "Convolution" 56 | bottom: "pool1" 57 | top: "conv2" 58 | param { 59 | lr_mult: 0 60 | decay_mult: 0 61 | } 62 | param { 63 | lr_mult: 0 64 | decay_mult: 0 65 | } 66 | convolution_param { 67 | num_output: 48 68 | kernel_size: 3 69 | stride: 1 70 | weight_filler { 71 | type: "xavier" 72 | } 73 | bias_filler { 74 | type: "constant" 75 | value: 0 76 | } 77 | } 78 | } 79 | layer { 80 | name: "prelu2" 81 | type: "PReLU" 82 | bottom: "conv2" 83 | top: "conv2" 84 | propagate_down: true 85 | } 86 | layer { 87 | name: "pool2" 88 | type: "Pooling" 89 | bottom: "conv2" 90 | top: "pool2" 91 | pooling_param { 92 | pool: MAX 93 | kernel_size: 3 94 | stride: 2 95 | } 96 | } 97 | #################################### 98 | 99 | ################################## 100 | layer { 101 | name: "conv3" 102 | type: "Convolution" 103 | bottom: "pool2" 104 | top: "conv3" 105 | param { 106 | lr_mult: 0 107 | decay_mult: 0 108 | } 109 | param { 110 | lr_mult: 0 111 | decay_mult: 0 112 | } 113 | convolution_param { 114 | num_output: 64 115 | kernel_size: 2 116 | stride: 1 117 | weight_filler { 118 | type: "xavier" 119 | } 120 | bias_filler { 121 | type: "constant" 122 | value: 0 123 | } 124 | } 125 | } 126 | layer { 127 | name: "prelu3" 128 | type: "PReLU" 129 | bottom: "conv3" 130 | top: "conv3" 131 | propagate_down: true 132 | } 133 | ############################### 134 | 135 | ############################### 136 | 137 | layer { 138 | name: "conv4" 139 | type: "InnerProduct" 140 | bottom: "conv3" 141 | top: "conv4" 142 | param { 143 | lr_mult: 0 144 | decay_mult: 0 145 | } 146 | param { 147 | lr_mult: 0 148 | decay_mult: 0 149 | } 150 | inner_product_param { 151 | num_output: 128 152 | weight_filler { 153 | type: "xavier" 154 | } 155 | bias_filler { 156 | type: "constant" 157 | value: 0 158 | } 159 | } 160 | } 161 | layer { 162 | name: "prelu4" 163 | type: "PReLU" 164 | bottom: "conv4" 165 | top: "conv4" 166 | } 167 | 168 | layer { 169 | name: "conv5-1" 170 | type: "InnerProduct" 171 | bottom: "conv4" 172 | top: "conv5-1" 173 | param { 174 | lr_mult: 0 175 | decay_mult: 0 176 | } 177 | param { 178 | lr_mult: 0 179 | decay_mult: 0 180 | } 181 | inner_product_param { 182 | num_output: 2 183 | #kernel_size: 1 184 | #stride: 1 185 | weight_filler { 186 | type: "xavier" 187 | } 188 | bias_filler { 189 | type: "constant" 190 | value: 0 191 | } 192 | } 193 | } 194 | layer { 195 | name: "conv5-2" 196 | type: "InnerProduct" 197 | bottom: "conv4" 198 | top: "conv5-2" 199 | param { 200 | lr_mult: 1 201 | decay_mult: 1 202 | } 203 | param { 204 | lr_mult: 2 205 | decay_mult: 1 206 | } 207 | inner_product_param { 208 | num_output: 4 209 | #kernel_size: 1 210 | #stride: 1 211 | weight_filler { 212 | type: "xavier" 213 | } 214 | bias_filler { 215 | type: "constant" 216 | value: 0 217 | } 218 | } 219 | } 220 | layer { 221 | name: "prob1" 222 | type: "Softmax" 223 | bottom: "conv5-1" 224 | top: "prob1" 225 | } -------------------------------------------------------------------------------- /static/model/det2_half.caffemodel: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:3bae14c3ea782eb926ac10d9965c31274ff3f6db15577796a1f074ee2f57c3e1 3 | size 203056 4 | -------------------------------------------------------------------------------- /static/model/det3-half.caffemodel: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:f26e566ae174f31d4fffde183a140a1f09463e8fd7c1eee0007cfa9170260f65 3 | size 397842 4 | -------------------------------------------------------------------------------- /static/model/det3-half.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 | ################################## 9 | layer { 10 | name: "conv1" 11 | type: "Convolution" 12 | bottom: "data" 13 | top: "conv1" 14 | param { 15 | lr_mult: 1 16 | decay_mult: 1 17 | } 18 | param { 19 | lr_mult: 2 20 | decay_mult: 1 21 | } 22 | convolution_param { 23 | num_output: 16 24 | kernel_size: 3 25 | stride: 1 26 | weight_filler { 27 | type: "xavier" 28 | } 29 | bias_filler { 30 | type: "constant" 31 | value: 0 32 | } 33 | } 34 | } 35 | layer { 36 | name: "prelu1" 37 | type: "PReLU" 38 | bottom: "conv1" 39 | top: "conv1" 40 | } 41 | layer { 42 | name: "pool1" 43 | type: "Pooling" 44 | bottom: "conv1" 45 | top: "pool1" 46 | pooling_param { 47 | pool: MAX 48 | kernel_size: 3 49 | stride: 2 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: 1 64 | } 65 | convolution_param { 66 | num_output: 32 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 | 79 | layer { 80 | name: "prelu2" 81 | type: "PReLU" 82 | bottom: "conv2" 83 | top: "conv2" 84 | } 85 | layer { 86 | name: "pool2" 87 | type: "Pooling" 88 | bottom: "conv2" 89 | top: "pool2" 90 | pooling_param { 91 | pool: MAX 92 | kernel_size: 3 93 | stride: 2 94 | } 95 | } 96 | 97 | layer { 98 | name: "conv3" 99 | type: "Convolution" 100 | bottom: "pool2" 101 | top: "conv3" 102 | param { 103 | lr_mult: 1 104 | decay_mult: 1 105 | } 106 | param { 107 | lr_mult: 2 108 | decay_mult: 1 109 | } 110 | convolution_param { 111 | num_output: 32 112 | kernel_size: 3 113 | weight_filler { 114 | type: "xavier" 115 | } 116 | bias_filler { 117 | type: "constant" 118 | value: 0 119 | } 120 | } 121 | } 122 | layer { 123 | name: "prelu3" 124 | type: "PReLU" 125 | bottom: "conv3" 126 | top: "conv3" 127 | } 128 | layer { 129 | name: "pool3" 130 | type: "Pooling" 131 | bottom: "conv3" 132 | top: "pool3" 133 | pooling_param { 134 | pool: MAX 135 | kernel_size: 2 136 | stride: 2 137 | } 138 | } 139 | layer { 140 | name: "conv4" 141 | type: "Convolution" 142 | bottom: "pool3" 143 | top: "conv4" 144 | param { 145 | lr_mult: 1 146 | decay_mult: 1 147 | } 148 | param { 149 | lr_mult: 2 150 | decay_mult: 1 151 | } 152 | convolution_param { 153 | num_output: 64 154 | kernel_size: 2 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 | 172 | layer { 173 | name: "conv5" 174 | type: "InnerProduct" 175 | bottom: "conv4" 176 | top: "conv5" 177 | param { 178 | lr_mult: 1 179 | decay_mult: 1 180 | } 181 | param { 182 | lr_mult: 2 183 | decay_mult: 1 184 | } 185 | inner_product_param { 186 | #kernel_size: 3 187 | num_output: 128 188 | weight_filler { 189 | type: "xavier" 190 | } 191 | bias_filler { 192 | type: "constant" 193 | value: 0 194 | } 195 | } 196 | } 197 | layer { 198 | name: "prelu5" 199 | type: "PReLU" 200 | # type: "TanH" 201 | bottom: "conv5" 202 | top: "conv5" 203 | } 204 | 205 | 206 | layer { 207 | name: "conv6-1" 208 | type: "InnerProduct" 209 | bottom: "conv5" 210 | top: "conv6-1" 211 | param { 212 | lr_mult: 1 213 | decay_mult: 1 214 | } 215 | param { 216 | lr_mult: 2 217 | decay_mult: 1 218 | } 219 | inner_product_param { 220 | #kernel_size: 1 221 | num_output: 2 222 | weight_filler { 223 | type: "xavier" 224 | } 225 | bias_filler { 226 | type: "constant" 227 | value: 0 228 | } 229 | } 230 | } 231 | layer { 232 | name: "conv6-2" 233 | type: "InnerProduct" 234 | bottom: "conv5" 235 | top: "conv6-2" 236 | param { 237 | lr_mult: 1 238 | decay_mult: 1 239 | } 240 | param { 241 | lr_mult: 2 242 | decay_mult: 1 243 | } 244 | inner_product_param { 245 | #kernel_size: 1 246 | num_output: 4 247 | weight_filler { 248 | type: "xavier" 249 | } 250 | bias_filler { 251 | type: "constant" 252 | value: 0 253 | } 254 | } 255 | } 256 | layer { 257 | name: "conv6-3" 258 | type: "InnerProduct" 259 | bottom: "conv5" 260 | top: "conv6-3" 261 | param { 262 | lr_mult: 1 263 | decay_mult: 1 264 | } 265 | param { 266 | lr_mult: 2 267 | decay_mult: 1 268 | } 269 | inner_product_param { 270 | #kernel_size: 1 271 | num_output: 10 272 | weight_filler { 273 | type: "xavier" 274 | } 275 | bias_filler { 276 | type: "constant" 277 | value: 0 278 | } 279 | } 280 | } 281 | 282 | layer { 283 | name: "prob1" 284 | type: "Softmax" 285 | bottom: "conv6-1" 286 | top: "prob1" 287 | } 288 | -------------------------------------------------------------------------------- /static/model/det3.caffemodel: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:3cc0250a3008428219cdf46914e68822a61acef454d40b0d41643ab07fcdf9d4 3 | size 1558918 4 | -------------------------------------------------------------------------------- /static/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 | ################################## 9 | layer { 10 | name: "conv1" 11 | type: "Convolution" 12 | bottom: "data" 13 | top: "conv1" 14 | param { 15 | lr_mult: 1 16 | decay_mult: 1 17 | } 18 | param { 19 | lr_mult: 2 20 | decay_mult: 1 21 | } 22 | convolution_param { 23 | num_output: 32 24 | kernel_size: 3 25 | stride: 1 26 | weight_filler { 27 | type: "xavier" 28 | } 29 | bias_filler { 30 | type: "constant" 31 | value: 0 32 | } 33 | } 34 | } 35 | layer { 36 | name: "prelu1" 37 | type: "PReLU" 38 | bottom: "conv1" 39 | top: "conv1" 40 | } 41 | layer { 42 | name: "pool1" 43 | type: "Pooling" 44 | bottom: "conv1" 45 | top: "pool1" 46 | pooling_param { 47 | pool: MAX 48 | kernel_size: 3 49 | stride: 2 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: 1 64 | } 65 | convolution_param { 66 | num_output: 64 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 | 79 | layer { 80 | name: "prelu2" 81 | type: "PReLU" 82 | bottom: "conv2" 83 | top: "conv2" 84 | } 85 | layer { 86 | name: "pool2" 87 | type: "Pooling" 88 | bottom: "conv2" 89 | top: "pool2" 90 | pooling_param { 91 | pool: MAX 92 | kernel_size: 3 93 | stride: 2 94 | } 95 | } 96 | 97 | layer { 98 | name: "conv3" 99 | type: "Convolution" 100 | bottom: "pool2" 101 | top: "conv3" 102 | param { 103 | lr_mult: 1 104 | decay_mult: 1 105 | } 106 | param { 107 | lr_mult: 2 108 | decay_mult: 1 109 | } 110 | convolution_param { 111 | num_output: 64 112 | kernel_size: 3 113 | weight_filler { 114 | type: "xavier" 115 | } 116 | bias_filler { 117 | type: "constant" 118 | value: 0 119 | } 120 | } 121 | } 122 | layer { 123 | name: "prelu3" 124 | type: "PReLU" 125 | bottom: "conv3" 126 | top: "conv3" 127 | } 128 | layer { 129 | name: "pool3" 130 | type: "Pooling" 131 | bottom: "conv3" 132 | top: "pool3" 133 | pooling_param { 134 | pool: MAX 135 | kernel_size: 2 136 | stride: 2 137 | } 138 | } 139 | layer { 140 | name: "conv4" 141 | type: "Convolution" 142 | bottom: "pool3" 143 | top: "conv4" 144 | param { 145 | lr_mult: 1 146 | decay_mult: 1 147 | } 148 | param { 149 | lr_mult: 2 150 | decay_mult: 1 151 | } 152 | convolution_param { 153 | num_output: 128 154 | kernel_size: 2 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 | 172 | layer { 173 | name: "conv5" 174 | type: "InnerProduct" 175 | bottom: "conv4" 176 | top: "conv5" 177 | param { 178 | lr_mult: 1 179 | decay_mult: 1 180 | } 181 | param { 182 | lr_mult: 2 183 | decay_mult: 1 184 | } 185 | inner_product_param { 186 | #kernel_size: 3 187 | num_output: 256 188 | weight_filler { 189 | type: "xavier" 190 | } 191 | bias_filler { 192 | type: "constant" 193 | value: 0 194 | } 195 | } 196 | } 197 | 198 | layer { 199 | name: "drop5" 200 | type: "Dropout" 201 | bottom: "conv5" 202 | top: "conv5" 203 | dropout_param { 204 | dropout_ratio: 0.25 205 | } 206 | } 207 | layer { 208 | name: "prelu5" 209 | type: "PReLU" 210 | # type: "TanH" 211 | bottom: "conv5" 212 | top: "conv5" 213 | } 214 | 215 | 216 | layer { 217 | name: "conv6-1" 218 | type: "InnerProduct" 219 | bottom: "conv5" 220 | top: "conv6-1" 221 | param { 222 | lr_mult: 1 223 | decay_mult: 1 224 | } 225 | param { 226 | lr_mult: 2 227 | decay_mult: 1 228 | } 229 | inner_product_param { 230 | #kernel_size: 1 231 | num_output: 2 232 | weight_filler { 233 | type: "xavier" 234 | } 235 | bias_filler { 236 | type: "constant" 237 | value: 0 238 | } 239 | } 240 | } 241 | layer { 242 | name: "conv6-2" 243 | type: "InnerProduct" 244 | bottom: "conv5" 245 | top: "conv6-2" 246 | param { 247 | lr_mult: 1 248 | decay_mult: 1 249 | } 250 | param { 251 | lr_mult: 2 252 | decay_mult: 1 253 | } 254 | inner_product_param { 255 | #kernel_size: 1 256 | num_output: 4 257 | weight_filler { 258 | type: "xavier" 259 | } 260 | bias_filler { 261 | type: "constant" 262 | value: 0 263 | } 264 | } 265 | } 266 | layer { 267 | name: "conv6-3" 268 | type: "InnerProduct" 269 | bottom: "conv5" 270 | top: "conv6-3" 271 | param { 272 | lr_mult: 1 273 | decay_mult: 1 274 | } 275 | param { 276 | lr_mult: 2 277 | decay_mult: 1 278 | } 279 | inner_product_param { 280 | #kernel_size: 1 281 | num_output: 10 282 | weight_filler { 283 | type: "xavier" 284 | } 285 | bias_filler { 286 | type: "constant" 287 | value: 0 288 | } 289 | } 290 | } 291 | 292 | layer { 293 | name: "prob1" 294 | type: "Softmax" 295 | bottom: "conv6-1" 296 | top: "prob1" 297 | } 298 | -------------------------------------------------------------------------------- /static/model/sphereface_deploy.prototxt: -------------------------------------------------------------------------------- 1 | name: "SpherefaceNet-20" 2 | input: "data" 3 | input_dim: 1 4 | input_dim: 3 5 | input_dim: 112 6 | input_dim: 96 7 | ############## CNN Architecture ############### 8 | layer { 9 | name: "conv1_1" 10 | type: "Convolution" 11 | bottom: "data" 12 | top: "conv1_1" 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: 64 23 | kernel_size: 3 24 | stride: 2 25 | pad: 1 26 | weight_filler { 27 | type: "xavier" 28 | } 29 | bias_filler { 30 | type: "constant" 31 | value: 0 32 | } 33 | } 34 | } 35 | layer { 36 | name: "relu1_1" 37 | type: "PReLU" 38 | bottom: "conv1_1" 39 | top: "conv1_1" 40 | } 41 | layer { 42 | name: "conv1_2" 43 | type: "Convolution" 44 | bottom: "conv1_1" 45 | top: "conv1_2" 46 | param { 47 | lr_mult: 1 48 | decay_mult: 1 49 | } 50 | param { 51 | lr_mult: 0 52 | decay_mult: 0 53 | } 54 | convolution_param { 55 | num_output: 64 56 | kernel_size: 3 57 | stride: 1 58 | pad: 1 59 | weight_filler { 60 | type: "gaussian" 61 | std: 0.01 62 | } 63 | bias_filler { 64 | type: "constant" 65 | value: 0 66 | } 67 | } 68 | } 69 | layer { 70 | name: "relu1_2" 71 | type: "PReLU" 72 | bottom: "conv1_2" 73 | top: "conv1_2" 74 | } 75 | layer { 76 | name: "conv1_3" 77 | type: "Convolution" 78 | bottom: "conv1_2" 79 | top: "conv1_3" 80 | param { 81 | lr_mult: 1 82 | decay_mult: 1 83 | } 84 | param { 85 | lr_mult: 0 86 | decay_mult: 0 87 | } 88 | convolution_param { 89 | num_output: 64 90 | kernel_size: 3 91 | stride: 1 92 | pad: 1 93 | weight_filler { 94 | type: "gaussian" 95 | std: 0.01 96 | } 97 | bias_filler { 98 | type: "constant" 99 | value: 0 100 | } 101 | } 102 | } 103 | layer { 104 | name: "relu1_3" 105 | type: "PReLU" 106 | bottom: "conv1_3" 107 | top: "conv1_3" 108 | } 109 | layer { 110 | name: "res1_3" 111 | type: "Eltwise" 112 | bottom: "conv1_1" 113 | bottom: "conv1_3" 114 | top: "res1_3" 115 | eltwise_param { 116 | operation: 1 117 | } 118 | } 119 | layer { 120 | name: "conv2_1" 121 | type: "Convolution" 122 | bottom: "res1_3" 123 | top: "conv2_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: 128 134 | kernel_size: 3 135 | stride: 2 136 | pad: 1 137 | weight_filler { 138 | type: "xavier" 139 | } 140 | bias_filler { 141 | type: "constant" 142 | value: 0 143 | } 144 | } 145 | } 146 | layer { 147 | name: "relu2_1" 148 | type: "PReLU" 149 | bottom: "conv2_1" 150 | top: "conv2_1" 151 | } 152 | layer { 153 | name: "conv2_2" 154 | type: "Convolution" 155 | bottom: "conv2_1" 156 | top: "conv2_2" 157 | param { 158 | lr_mult: 1 159 | decay_mult: 1 160 | } 161 | param { 162 | lr_mult: 0 163 | decay_mult: 0 164 | } 165 | convolution_param { 166 | num_output: 128 167 | kernel_size: 3 168 | stride: 1 169 | pad: 1 170 | weight_filler { 171 | type: "gaussian" 172 | std: 0.01 173 | } 174 | bias_filler { 175 | type: "constant" 176 | value: 0 177 | } 178 | } 179 | } 180 | layer { 181 | name: "relu2_2" 182 | type: "PReLU" 183 | bottom: "conv2_2" 184 | top: "conv2_2" 185 | } 186 | layer { 187 | name: "conv2_3" 188 | type: "Convolution" 189 | bottom: "conv2_2" 190 | top: "conv2_3" 191 | param { 192 | lr_mult: 1 193 | decay_mult: 1 194 | } 195 | param { 196 | lr_mult: 0 197 | decay_mult: 0 198 | } 199 | convolution_param { 200 | num_output: 128 201 | kernel_size: 3 202 | stride: 1 203 | pad: 1 204 | weight_filler { 205 | type: "gaussian" 206 | std: 0.01 207 | } 208 | bias_filler { 209 | type: "constant" 210 | value: 0 211 | } 212 | } 213 | } 214 | layer { 215 | name: "relu2_3" 216 | type: "PReLU" 217 | bottom: "conv2_3" 218 | top: "conv2_3" 219 | } 220 | layer { 221 | name: "res2_3" 222 | type: "Eltwise" 223 | bottom: "conv2_1" 224 | bottom: "conv2_3" 225 | top: "res2_3" 226 | eltwise_param { 227 | operation: 1 228 | } 229 | } 230 | layer { 231 | name: "conv2_4" 232 | type: "Convolution" 233 | bottom: "res2_3" 234 | top: "conv2_4" 235 | param { 236 | lr_mult: 1 237 | decay_mult: 1 238 | } 239 | param { 240 | lr_mult: 0 241 | decay_mult: 0 242 | } 243 | convolution_param { 244 | num_output: 128 245 | kernel_size: 3 246 | stride: 1 247 | pad: 1 248 | weight_filler { 249 | type: "gaussian" 250 | std: 0.01 251 | } 252 | bias_filler { 253 | type: "constant" 254 | value: 0 255 | } 256 | } 257 | } 258 | layer { 259 | name: "relu2_4" 260 | type: "PReLU" 261 | bottom: "conv2_4" 262 | top: "conv2_4" 263 | } 264 | layer { 265 | name: "conv2_5" 266 | type: "Convolution" 267 | bottom: "conv2_4" 268 | top: "conv2_5" 269 | param { 270 | lr_mult: 1 271 | decay_mult: 1 272 | } 273 | param { 274 | lr_mult: 0 275 | decay_mult: 0 276 | } 277 | convolution_param { 278 | num_output: 128 279 | kernel_size: 3 280 | stride: 1 281 | pad: 1 282 | weight_filler { 283 | type: "gaussian" 284 | std: 0.01 285 | } 286 | bias_filler { 287 | type: "constant" 288 | value: 0 289 | } 290 | } 291 | } 292 | layer { 293 | name: "relu2_5" 294 | type: "PReLU" 295 | bottom: "conv2_5" 296 | top: "conv2_5" 297 | } 298 | layer { 299 | name: "res2_5" 300 | type: "Eltwise" 301 | bottom: "res2_3" 302 | bottom: "conv2_5" 303 | top: "res2_5" 304 | eltwise_param { 305 | operation: 1 306 | } 307 | } 308 | layer { 309 | name: "conv3_1" 310 | type: "Convolution" 311 | bottom: "res2_5" 312 | top: "conv3_1" 313 | param { 314 | lr_mult: 1 315 | decay_mult: 1 316 | } 317 | param { 318 | lr_mult: 2 319 | decay_mult: 0 320 | } 321 | convolution_param { 322 | num_output: 256 323 | kernel_size: 3 324 | stride: 2 325 | pad: 1 326 | weight_filler { 327 | type: "xavier" 328 | } 329 | bias_filler { 330 | type: "constant" 331 | value: 0 332 | } 333 | } 334 | } 335 | layer { 336 | name: "relu3_1" 337 | type: "PReLU" 338 | bottom: "conv3_1" 339 | top: "conv3_1" 340 | } 341 | layer { 342 | name: "conv3_2" 343 | type: "Convolution" 344 | bottom: "conv3_1" 345 | top: "conv3_2" 346 | param { 347 | lr_mult: 1 348 | decay_mult: 1 349 | } 350 | param { 351 | lr_mult: 0 352 | decay_mult: 0 353 | } 354 | convolution_param { 355 | num_output: 256 356 | kernel_size: 3 357 | stride: 1 358 | pad: 1 359 | weight_filler { 360 | type: "gaussian" 361 | std: 0.01 362 | } 363 | bias_filler { 364 | type: "constant" 365 | value: 0 366 | } 367 | } 368 | } 369 | layer { 370 | name: "relu3_2" 371 | type: "PReLU" 372 | bottom: "conv3_2" 373 | top: "conv3_2" 374 | } 375 | layer { 376 | name: "conv3_3" 377 | type: "Convolution" 378 | bottom: "conv3_2" 379 | top: "conv3_3" 380 | param { 381 | lr_mult: 1 382 | decay_mult: 1 383 | } 384 | param { 385 | lr_mult: 0 386 | decay_mult: 0 387 | } 388 | convolution_param { 389 | num_output: 256 390 | kernel_size: 3 391 | stride: 1 392 | pad: 1 393 | weight_filler { 394 | type: "gaussian" 395 | std: 0.01 396 | } 397 | bias_filler { 398 | type: "constant" 399 | value: 0 400 | } 401 | } 402 | } 403 | layer { 404 | name: "relu3_3" 405 | type: "PReLU" 406 | bottom: "conv3_3" 407 | top: "conv3_3" 408 | } 409 | layer { 410 | name: "res3_3" 411 | type: "Eltwise" 412 | bottom: "conv3_1" 413 | bottom: "conv3_3" 414 | top: "res3_3" 415 | eltwise_param { 416 | operation: 1 417 | } 418 | } 419 | layer { 420 | name: "conv3_4" 421 | type: "Convolution" 422 | bottom: "res3_3" 423 | top: "conv3_4" 424 | param { 425 | lr_mult: 1 426 | decay_mult: 1 427 | } 428 | param { 429 | lr_mult: 0 430 | decay_mult: 0 431 | } 432 | convolution_param { 433 | num_output: 256 434 | kernel_size: 3 435 | stride: 1 436 | pad: 1 437 | weight_filler { 438 | type: "gaussian" 439 | std: 0.01 440 | } 441 | bias_filler { 442 | type: "constant" 443 | value: 0 444 | } 445 | } 446 | } 447 | layer { 448 | name: "relu3_4" 449 | type: "PReLU" 450 | bottom: "conv3_4" 451 | top: "conv3_4" 452 | } 453 | layer { 454 | name: "conv3_5" 455 | type: "Convolution" 456 | bottom: "conv3_4" 457 | top: "conv3_5" 458 | param { 459 | lr_mult: 1 460 | decay_mult: 1 461 | } 462 | param { 463 | lr_mult: 0 464 | decay_mult: 0 465 | } 466 | convolution_param { 467 | num_output: 256 468 | kernel_size: 3 469 | stride: 1 470 | pad: 1 471 | weight_filler { 472 | type: "gaussian" 473 | std: 0.01 474 | } 475 | bias_filler { 476 | type: "constant" 477 | value: 0 478 | } 479 | } 480 | } 481 | layer { 482 | name: "relu3_5" 483 | type: "PReLU" 484 | bottom: "conv3_5" 485 | top: "conv3_5" 486 | } 487 | layer { 488 | name: "res3_5" 489 | type: "Eltwise" 490 | bottom: "res3_3" 491 | bottom: "conv3_5" 492 | top: "res3_5" 493 | eltwise_param { 494 | operation: 1 495 | } 496 | } 497 | layer { 498 | name: "conv3_6" 499 | type: "Convolution" 500 | bottom: "res3_5" 501 | top: "conv3_6" 502 | param { 503 | lr_mult: 1 504 | decay_mult: 1 505 | } 506 | param { 507 | lr_mult: 0 508 | decay_mult: 0 509 | } 510 | convolution_param { 511 | num_output: 256 512 | kernel_size: 3 513 | stride: 1 514 | pad: 1 515 | weight_filler { 516 | type: "gaussian" 517 | std: 0.01 518 | } 519 | bias_filler { 520 | type: "constant" 521 | value: 0 522 | } 523 | } 524 | } 525 | layer { 526 | name: "relu3_6" 527 | type: "PReLU" 528 | bottom: "conv3_6" 529 | top: "conv3_6" 530 | } 531 | layer { 532 | name: "conv3_7" 533 | type: "Convolution" 534 | bottom: "conv3_6" 535 | top: "conv3_7" 536 | param { 537 | lr_mult: 1 538 | decay_mult: 1 539 | } 540 | param { 541 | lr_mult: 0 542 | decay_mult: 0 543 | } 544 | convolution_param { 545 | num_output: 256 546 | kernel_size: 3 547 | stride: 1 548 | pad: 1 549 | weight_filler { 550 | type: "gaussian" 551 | std: 0.01 552 | } 553 | bias_filler { 554 | type: "constant" 555 | value: 0 556 | } 557 | } 558 | } 559 | layer { 560 | name: "relu3_7" 561 | type: "PReLU" 562 | bottom: "conv3_7" 563 | top: "conv3_7" 564 | } 565 | layer { 566 | name: "res3_7" 567 | type: "Eltwise" 568 | bottom: "res3_5" 569 | bottom: "conv3_7" 570 | top: "res3_7" 571 | eltwise_param { 572 | operation: 1 573 | } 574 | } 575 | layer { 576 | name: "conv3_8" 577 | type: "Convolution" 578 | bottom: "res3_7" 579 | top: "conv3_8" 580 | param { 581 | lr_mult: 1 582 | decay_mult: 1 583 | } 584 | param { 585 | lr_mult: 0 586 | decay_mult: 0 587 | } 588 | convolution_param { 589 | num_output: 256 590 | kernel_size: 3 591 | stride: 1 592 | pad: 1 593 | weight_filler { 594 | type: "gaussian" 595 | std: 0.01 596 | } 597 | bias_filler { 598 | type: "constant" 599 | value: 0 600 | } 601 | } 602 | } 603 | layer { 604 | name: "relu3_8" 605 | type: "PReLU" 606 | bottom: "conv3_8" 607 | top: "conv3_8" 608 | } 609 | layer { 610 | name: "conv3_9" 611 | type: "Convolution" 612 | bottom: "conv3_8" 613 | top: "conv3_9" 614 | param { 615 | lr_mult: 1 616 | decay_mult: 1 617 | } 618 | param { 619 | lr_mult: 0 620 | decay_mult: 0 621 | } 622 | convolution_param { 623 | num_output: 256 624 | kernel_size: 3 625 | stride: 1 626 | pad: 1 627 | weight_filler { 628 | type: "gaussian" 629 | std: 0.01 630 | } 631 | bias_filler { 632 | type: "constant" 633 | value: 0 634 | } 635 | } 636 | } 637 | layer { 638 | name: "relu3_9" 639 | type: "PReLU" 640 | bottom: "conv3_9" 641 | top: "conv3_9" 642 | } 643 | layer { 644 | name: "res3_9" 645 | type: "Eltwise" 646 | bottom: "res3_7" 647 | bottom: "conv3_9" 648 | top: "res3_9" 649 | eltwise_param { 650 | operation: 1 651 | } 652 | } 653 | layer { 654 | name: "conv4_1" 655 | type: "Convolution" 656 | bottom: "res3_9" 657 | top: "conv4_1" 658 | param { 659 | lr_mult: 1 660 | decay_mult: 1 661 | } 662 | param { 663 | lr_mult: 2 664 | decay_mult: 0 665 | } 666 | convolution_param { 667 | num_output: 512 668 | kernel_size: 3 669 | stride: 2 670 | pad: 1 671 | weight_filler { 672 | type: "xavier" 673 | } 674 | bias_filler { 675 | type: "constant" 676 | value: 0 677 | } 678 | } 679 | } 680 | layer { 681 | name: "relu4_1" 682 | type: "PReLU" 683 | bottom: "conv4_1" 684 | top: "conv4_1" 685 | } 686 | layer { 687 | name: "conv4_2" 688 | type: "Convolution" 689 | bottom: "conv4_1" 690 | top: "conv4_2" 691 | param { 692 | lr_mult: 1 693 | decay_mult: 1 694 | } 695 | param { 696 | lr_mult: 0 697 | decay_mult: 0 698 | } 699 | convolution_param { 700 | num_output: 512 701 | kernel_size: 3 702 | stride: 1 703 | pad: 1 704 | weight_filler { 705 | type: "gaussian" 706 | std: 0.01 707 | } 708 | bias_filler { 709 | type: "constant" 710 | value: 0 711 | } 712 | } 713 | } 714 | layer { 715 | name: "relu4_2" 716 | type: "PReLU" 717 | bottom: "conv4_2" 718 | top: "conv4_2" 719 | } 720 | layer { 721 | name: "conv4_3" 722 | type: "Convolution" 723 | bottom: "conv4_2" 724 | top: "conv4_3" 725 | param { 726 | lr_mult: 1 727 | decay_mult: 1 728 | } 729 | param { 730 | lr_mult: 0 731 | decay_mult: 0 732 | } 733 | convolution_param { 734 | num_output: 512 735 | kernel_size: 3 736 | stride: 1 737 | pad: 1 738 | weight_filler { 739 | type: "gaussian" 740 | std: 0.01 741 | } 742 | bias_filler { 743 | type: "constant" 744 | value: 0 745 | } 746 | } 747 | } 748 | layer { 749 | name: "relu4_3" 750 | type: "PReLU" 751 | bottom: "conv4_3" 752 | top: "conv4_3" 753 | } 754 | layer { 755 | name: "res4_3" 756 | type: "Eltwise" 757 | bottom: "conv4_1" 758 | bottom: "conv4_3" 759 | top: "res4_3" 760 | eltwise_param { 761 | operation: 1 762 | } 763 | } 764 | layer { 765 | name: "fc5" 766 | type: "InnerProduct" 767 | bottom: "res4_3" 768 | top: "fc5" 769 | param { 770 | lr_mult: 1 771 | decay_mult: 1 772 | } 773 | param { 774 | lr_mult: 2 775 | decay_mult: 0 776 | } 777 | inner_product_param { 778 | num_output: 512 779 | weight_filler { 780 | type: "xavier" 781 | } 782 | bias_filler { 783 | type: "constant" 784 | value: 0 785 | } 786 | } 787 | } -------------------------------------------------------------------------------- /static/model/sphereface_model.caffemodel: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:092d8fb00291d80ed7e43f7c9323693581cd75e734be3c52764525043288a20d 3 | size 90688218 4 | -------------------------------------------------------------------------------- /static/test.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tczhangzhi/face-recognition/ac0ddb395432dd42a3d41f5c1209d481a5464942/static/test.jpeg --------------------------------------------------------------------------------