├── .gitignore ├── CMakeLists.txt ├── README.md ├── Windows ├── ncnn_face.sln └── ncnn_face.vcxproj ├── clean.bat └── src └── ncnn_face.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | .vs/ 2 | build/ 3 | Windows/x64 4 | *.param 5 | *.bin 6 | *.zip -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | find_package(OpenCV QUIET COMPONENTS core highgui imgproc imgcodecs) 3 | if(NOT OpenCV_FOUND) 4 | find_package(OpenCV REQUIRED COMPONENTS core highgui imgproc) 5 | endif() 6 | option(NCNN_STDIO "load model from external file" ON) 7 | option(NCNN_STRING "plain and verbose string" ON) 8 | 9 | add_executable(ncnn_face src/ncnn_face.cpp) 10 | target_link_libraries(ncnn_face ncnn ${OpenCV_LIBS}) -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ncnn-face 2 | 3 | ## 基于MobileNet-SSD的人脸检测器ncnn版 4 | 5 | ![](https://i.imgur.com/QDGkI9r.jpg) 6 | 7 | 8 | ## 使用方法 9 | 10 | 下载转换好的模型,地址[releases](https://github.com/imistyrain/ncnn_face/releases) 11 | 12 | 编译并安装ncnn库,步骤参见[how to build ncnn library](https://github.com/Tencent/ncnn/wiki/how-to-build) 13 | 14 | ### Windows 15 | 16 | 双击打开Windows文件夹下的ncnn_face.sln编译即可 17 | 18 | ### Linux & arm 19 | 20 | mkdir build 21 | cd build 22 | cmake .. 23 | make -j8 24 | 25 | 训练参见[https://github.com/chuanqi305/MobileNet-SSD](MobileNet-SSD) 26 | 27 | 模型转换参见[convert to ncnn model](https://github.com/Tencent/ncnn/wiki/how-to-use-ncnn-with-alexnet) 28 | 29 | 参考: 30 | 31 | * [ncnn-mtcnn](https://github.com/Longqi-S/ncnn-mtcnn/) 32 | 33 | * [MobileNet-SSD](https://github.com/chuanqi305/MobileNet-SSD) -------------------------------------------------------------------------------- /Windows/ncnn_face.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 14 4 | VisualStudioVersion = 14.0.25420.1 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ncnn_face", "ncnn_face.vcxproj", "{B58A7B68-DEA6-4B53-8EC6-A557DC50E515}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x64 = Debug|x64 11 | Debug|x86 = Debug|x86 12 | Release|x64 = Release|x64 13 | Release|x86 = Release|x86 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {B58A7B68-DEA6-4B53-8EC6-A557DC50E515}.Debug|x64.ActiveCfg = Debug|x64 17 | {B58A7B68-DEA6-4B53-8EC6-A557DC50E515}.Debug|x64.Build.0 = Debug|x64 18 | {B58A7B68-DEA6-4B53-8EC6-A557DC50E515}.Debug|x86.ActiveCfg = Debug|Win32 19 | {B58A7B68-DEA6-4B53-8EC6-A557DC50E515}.Debug|x86.Build.0 = Debug|Win32 20 | {B58A7B68-DEA6-4B53-8EC6-A557DC50E515}.Release|x64.ActiveCfg = Release|x64 21 | {B58A7B68-DEA6-4B53-8EC6-A557DC50E515}.Release|x64.Build.0 = Release|x64 22 | {B58A7B68-DEA6-4B53-8EC6-A557DC50E515}.Release|x86.ActiveCfg = Release|Win32 23 | {B58A7B68-DEA6-4B53-8EC6-A557DC50E515}.Release|x86.Build.0 = Release|Win32 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | EndGlobal 29 | -------------------------------------------------------------------------------- /Windows/ncnn_face.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Debug 10 | x64 11 | 12 | 13 | Release 14 | Win32 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 23 | 24 | 25 | {B58A7B68-DEA6-4B53-8EC6-A557DC50E515} 26 | Win32Proj 27 | squeezenet 28 | 29 | 30 | 31 | Application 32 | true 33 | v140 34 | Unicode 35 | 36 | 37 | Application 38 | true 39 | v140 40 | Unicode 41 | 42 | 43 | Application 44 | false 45 | v140 46 | true 47 | Unicode 48 | 49 | 50 | Application 51 | false 52 | v140 53 | true 54 | Unicode 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | true 74 | 75 | 76 | true 77 | ../src;$(IncludePath) 78 | ../build/install/lib;$(LibraryPath) 79 | 80 | 81 | false 82 | 83 | 84 | false 85 | ../../src;$(IncludePath) 86 | ../build/install/lib;$(LibraryPath) 87 | 88 | 89 | 90 | 91 | 92 | Level3 93 | Disabled 94 | WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) 95 | true 96 | 97 | 98 | Console 99 | true 100 | 101 | 102 | 103 | 104 | 105 | 106 | Level3 107 | Disabled 108 | WIN32;NCNN_STRING;NCNN_STDIO;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) 109 | true 110 | true 111 | 112 | 113 | Console 114 | true 115 | 116 | 117 | 118 | 119 | Level3 120 | 121 | 122 | MaxSpeed 123 | true 124 | true 125 | WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) 126 | true 127 | 128 | 129 | Console 130 | true 131 | true 132 | true 133 | 134 | 135 | 136 | 137 | Level3 138 | 139 | 140 | MaxSpeed 141 | true 142 | true 143 | WIN32;NCNN_STRING;NCNN_STDIO;NCNN_PIXEL;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) 144 | true 145 | true 146 | 147 | 148 | Console 149 | true 150 | true 151 | true 152 | 153 | 154 | 155 | 156 | 157 | -------------------------------------------------------------------------------- /clean.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | set dirs2del="./,Windows,build" 3 | :DEL_LOOP 4 | for /f "Tokens=1,* Delims=," %%a in (%dirs2del%) do ( 5 | echo clearing %%a 6 | if exist "%%a\x64" rd "%%a\x64" /s /q 7 | if exist "%%a\Release" rd "%%a\Release" /s /q 8 | if exist "%%a\Debug" rd "%%a\Debug" /s /q 9 | if exist "%%a\*.exp" del "%%a\*.exp" /f /s /q 10 | if exist "%%a\*.pdb" del "%%a\*.pdb" /f /s /q 11 | set dirs2del="%%b" 12 | goto DEL_LOOP 13 | ) 14 | pause -------------------------------------------------------------------------------- /src/ncnn_face.cpp: -------------------------------------------------------------------------------- 1 | //MobileNet-SSD Face detection demo 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include "net.h" 8 | #include "mrdir.h" 9 | #include "mropencv.h" 10 | #pragma comment(lib,"ncnn.lib") 11 | #define USE_PARAM_BIN 0 12 | #if USE_PARAM_BIN 13 | #include "mobilenet_ssd_voc_ncnn.id.h" 14 | #endif 15 | struct Object{ 16 | cv::Rect rec; 17 | int class_id; 18 | float prob; 19 | }; 20 | int input_size = 300; 21 | const char* class_names[] = {"background","face"}; 22 | std::string modelnameprefix = "../ncnn_face"; 23 | static int detect_mobilenet(cv::Mat& raw_img, float show_threshold) 24 | { 25 | ncnn::Net mobilenet; 26 | /* 27 | * model is converted from https://github.com/chuanqi305/MobileNet-SSD 28 | * and can be downloaded from https://drive.google.com/open?id=0ByaKLD9QaPtucWk0Y0dha1VVY0U 29 | */ 30 | int img_h = raw_img.size().height; 31 | int img_w = raw_img.size().width; 32 | #if USE_PARAM_BIN 33 | mobilenet.load_param_bin((modelnameprefix + ".param.bin").c_str()); 34 | #else 35 | mobilenet.load_param((modelnameprefix+".param").c_str()); 36 | #endif 37 | mobilenet.load_model((modelnameprefix + ".bin").c_str()); 38 | ncnn::Mat in = ncnn::Mat::from_pixels_resize(raw_img.data, ncnn::Mat::PIXEL_BGR, raw_img.cols, raw_img.rows, input_size, input_size); 39 | 40 | const float mean_vals[3] = {127.5f, 127.5f, 127.5f}; 41 | const float norm_vals[3] = {1.0/127.5,1.0/127.5,1.0/127.5}; 42 | in.substract_mean_normalize(mean_vals, norm_vals); 43 | 44 | ncnn::Mat out; 45 | 46 | ncnn::Extractor ex = mobilenet.create_extractor(); 47 | ex.set_light_mode(true); 48 | //ex.set_num_threads(4); 49 | cv::TickMeter tm; 50 | tm.start(); 51 | #if USE_PARAM_BIN 52 | ex.input(mobilenet_ssd_voc_ncnn_param_id::BLOB_data, in); 53 | ex.extract(mobilenet_ssd_voc_ncnn_param_id::BLOB_detection_out, out); 54 | #else 55 | ex.input("data", in); 56 | ex.extract("detection_out", out); 57 | #endif 58 | tm.stop(); 59 | std::cout << tm.getTimeMilli() << "ms" << std::endl; 60 | printf("%d %d %d\n", out.w, out.h, out.c); 61 | std::vector objects; 62 | for (int iw=0;iw show_threshold) 79 | { 80 | cv::rectangle(raw_img, object.rec, cv::Scalar(255, 0, 0)); 81 | std::ostringstream pro_str; 82 | pro_str< objects; 163 | for (int iw = 0; iw show_threshold) 180 | { 181 | cv::rectangle(raw_img, object.rec, cv::Scalar(255, 0, 0)); 182 | std::ostringstream pro_str; 183 | pro_str << object.prob; 184 | std::string label = std::string(class_names[object.class_id]) + ": " + pro_str.str(); 185 | int baseLine = 0; 186 | cv::Size label_size = cv::getTextSize(label, cv::FONT_HERSHEY_SIMPLEX, 0.5, 1, &baseLine); 187 | cv::rectangle(raw_img, cv::Rect(cv::Point(object.rec.x, object.rec.y - label_size.height), 188 | cv::Size(label_size.width, label_size.height + baseLine)), 189 | cv::Scalar(255, 255, 255), CV_FILLED); 190 | cv::putText(raw_img, label, cv::Point(object.rec.x, object.rec.y), 191 | cv::FONT_HERSHEY_SIMPLEX, 0.5, cv::Scalar(0, 0, 0)); 192 | } 193 | } 194 | return raw_img; 195 | } 196 | 197 | int test_camera(float show_threshold=0.5) 198 | { 199 | cv::VideoCapture capture(0); 200 | MobileNetFaceDetector md; 201 | cv::Mat raw_img; 202 | while (true) 203 | { 204 | capture >> raw_img; 205 | if (!raw_img.data) 206 | { 207 | break; 208 | } 209 | auto result = md.detect(raw_img); 210 | auto show = md.drawResult(raw_img, result); 211 | cv::imshow("img", show); 212 | cv::waitKey(1); 213 | } 214 | return 0; 215 | } 216 | 217 | int test_dir(const std::string dir="../images") 218 | { 219 | MobileNetFaceDetector md; 220 | auto files = getAllFilesinDir(dir); 221 | for (auto file:files) 222 | { 223 | std::string filepath = dir + "/" + file; 224 | cv::Mat raw_img = cv::imread(filepath); 225 | auto result = md.detect(raw_img); 226 | auto show = md.drawResult(raw_img, result); 227 | cv::imshow("img", show); 228 | //cv::imwrite("result.jpg", show); 229 | cv::waitKey(); 230 | } 231 | return 0; 232 | } 233 | 234 | int main(int argc, char** argv) 235 | { 236 | //test_img(); 237 | test_camera(); 238 | //test_dir(); 239 | return 0; 240 | } --------------------------------------------------------------------------------