├── .idea ├── codeStyles │ └── Project.xml └── vcs.xml ├── 2.png ├── 4.jpg ├── CMakeLists.txt ├── Makefile ├── README.md ├── det1_relu.caffemodel ├── det1_relu.prototxt ├── det2_relu.caffemodel ├── det2_relu.prototxt ├── det3_relu.caffemodel ├── det3_relu.prototxt ├── main ├── pictures ├── QR.png ├── modification.png ├── qrcode.png ├── result.jpg └── vrcode.jpg ├── result.jpg ├── src ├── baseEngine.cpp ├── baseEngine.h ├── common.cpp ├── common.h ├── demo.cpp ├── mtcnn.cpp ├── mtcnn.h ├── network.cpp ├── network.h ├── onet_rt.cpp ├── onet_rt.h ├── pBox.h ├── pnet_rt.cpp ├── pnet_rt.h ├── rnet_rt.cpp └── rnet_rt.h └── temp.prototxt /.idea/codeStyles/Project.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 15 | 16 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PKUZHOU/MTCNN_FaceDetection_TensorRT/dfad60565216a68413f434b500168c456fdd2587/2.png -------------------------------------------------------------------------------- /4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PKUZHOU/MTCNN_FaceDetection_TensorRT/dfad60565216a68413f434b500168c456fdd2587/4.jpg -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5) 2 | project(main) 3 | 4 | add_definitions(-std=c++11) 5 | #set(QMAKE_CXXFLAGS "-std=c++11") 6 | include_directories(/opt/OpenBLAS/include) 7 | include_directories(/usr/local/cuda/include) 8 | include_directories(/home/zhou/tensorrt/include) 9 | link_directories(/home/zhou/tensorrt/lib) 10 | link_directories(/opt/cuda/lib64) 11 | 12 | find_package( OpenCV REQUIRED) 13 | 14 | AUX_SOURCE_DIRECTORY(./src DIR_SRCS) 15 | add_executable( main ${DIR_SRCS} src/pnet_rt.cpp src/common.h src/common.cpp src/pnet_rt.h src/rnet_rt.cpp src/rnet_rt.h src/baseEngine.cpp src/baseEngine.h src/onet_rt.h src/onet_rt.cpp) 16 | 17 | set(CMAKE_CXX_FLAGS "-lpthread") 18 | set(CMAKE_CXX_FLAGS "-O3") 19 | target_link_libraries( main ${OpenCV_LIBS} ) 20 | target_link_libraries( main openblas) 21 | target_link_libraries( main cudart) 22 | target_link_libraries( main nvinfer) 23 | target_link_libraries( main nvparsers) 24 | 25 | 26 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # CMAKE generated file: DO NOT EDIT! 2 | # Generated by "Unix Makefiles" Generator, CMake Version 3.10 3 | 4 | # Default target executed when no arguments are given to make. 5 | default_target: all 6 | 7 | .PHONY : default_target 8 | 9 | # Allow only one "make -f Makefile2" at a time, but pass parallelism. 10 | .NOTPARALLEL: 11 | 12 | 13 | #============================================================================= 14 | # Special targets provided by cmake. 15 | 16 | # Disable implicit rules so canonical targets will work. 17 | .SUFFIXES: 18 | 19 | 20 | # Remove some rules from gmake that .SUFFIXES does not remove. 21 | SUFFIXES = 22 | 23 | .SUFFIXES: .hpux_make_needs_suffix_list 24 | 25 | 26 | # Suppress display of executed commands. 27 | $(VERBOSE).SILENT: 28 | 29 | 30 | # A target that is always out of date. 31 | cmake_force: 32 | 33 | .PHONY : cmake_force 34 | 35 | #============================================================================= 36 | # Set environment variables for the build. 37 | 38 | # The shell in which to execute make rules. 39 | SHELL = /bin/sh 40 | 41 | # The CMake executable. 42 | CMAKE_COMMAND = /usr/bin/cmake 43 | 44 | # The command to remove a file. 45 | RM = /usr/bin/cmake -E remove -f 46 | 47 | # Escaping for special characters. 48 | EQUALS = = 49 | 50 | # The top-level source directory on which CMake was run. 51 | CMAKE_SOURCE_DIR = /home/zhou/MTCNN_TensorRT 52 | 53 | # The top-level build directory on which CMake was run. 54 | CMAKE_BINARY_DIR = /home/zhou/MTCNN_TensorRT 55 | 56 | #============================================================================= 57 | # Targets provided globally by CMake. 58 | 59 | # Special rule for the target rebuild_cache 60 | rebuild_cache: 61 | @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Running CMake to regenerate build system..." 62 | /usr/bin/cmake -H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) 63 | .PHONY : rebuild_cache 64 | 65 | # Special rule for the target rebuild_cache 66 | rebuild_cache/fast: rebuild_cache 67 | 68 | .PHONY : rebuild_cache/fast 69 | 70 | # Special rule for the target edit_cache 71 | edit_cache: 72 | @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "No interactive CMake dialog available..." 73 | /usr/bin/cmake -E echo No\ interactive\ CMake\ dialog\ available. 74 | .PHONY : edit_cache 75 | 76 | # Special rule for the target edit_cache 77 | edit_cache/fast: edit_cache 78 | 79 | .PHONY : edit_cache/fast 80 | 81 | # The main all target 82 | all: cmake_check_build_system 83 | $(CMAKE_COMMAND) -E cmake_progress_start /home/zhou/MTCNN_TensorRT/CMakeFiles /home/zhou/MTCNN_TensorRT/CMakeFiles/progress.marks 84 | $(MAKE) -f CMakeFiles/Makefile2 all 85 | $(CMAKE_COMMAND) -E cmake_progress_start /home/zhou/MTCNN_TensorRT/CMakeFiles 0 86 | .PHONY : all 87 | 88 | # The main clean target 89 | clean: 90 | $(MAKE) -f CMakeFiles/Makefile2 clean 91 | .PHONY : clean 92 | 93 | # The main clean target 94 | clean/fast: clean 95 | 96 | .PHONY : clean/fast 97 | 98 | # Prepare targets for installation. 99 | preinstall: all 100 | $(MAKE) -f CMakeFiles/Makefile2 preinstall 101 | .PHONY : preinstall 102 | 103 | # Prepare targets for installation. 104 | preinstall/fast: 105 | $(MAKE) -f CMakeFiles/Makefile2 preinstall 106 | .PHONY : preinstall/fast 107 | 108 | # clear depends 109 | depend: 110 | $(CMAKE_COMMAND) -H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 1 111 | .PHONY : depend 112 | 113 | #============================================================================= 114 | # Target rules for targets named main 115 | 116 | # Build rule for target. 117 | main: cmake_check_build_system 118 | $(MAKE) -f CMakeFiles/Makefile2 main 119 | .PHONY : main 120 | 121 | # fast build rule for target. 122 | main/fast: 123 | $(MAKE) -f CMakeFiles/main.dir/build.make CMakeFiles/main.dir/build 124 | .PHONY : main/fast 125 | 126 | src/baseEngine.o: src/baseEngine.cpp.o 127 | 128 | .PHONY : src/baseEngine.o 129 | 130 | # target to build an object file 131 | src/baseEngine.cpp.o: 132 | $(MAKE) -f CMakeFiles/main.dir/build.make CMakeFiles/main.dir/src/baseEngine.cpp.o 133 | .PHONY : src/baseEngine.cpp.o 134 | 135 | src/baseEngine.i: src/baseEngine.cpp.i 136 | 137 | .PHONY : src/baseEngine.i 138 | 139 | # target to preprocess a source file 140 | src/baseEngine.cpp.i: 141 | $(MAKE) -f CMakeFiles/main.dir/build.make CMakeFiles/main.dir/src/baseEngine.cpp.i 142 | .PHONY : src/baseEngine.cpp.i 143 | 144 | src/baseEngine.s: src/baseEngine.cpp.s 145 | 146 | .PHONY : src/baseEngine.s 147 | 148 | # target to generate assembly for a file 149 | src/baseEngine.cpp.s: 150 | $(MAKE) -f CMakeFiles/main.dir/build.make CMakeFiles/main.dir/src/baseEngine.cpp.s 151 | .PHONY : src/baseEngine.cpp.s 152 | 153 | src/common.o: src/common.cpp.o 154 | 155 | .PHONY : src/common.o 156 | 157 | # target to build an object file 158 | src/common.cpp.o: 159 | $(MAKE) -f CMakeFiles/main.dir/build.make CMakeFiles/main.dir/src/common.cpp.o 160 | .PHONY : src/common.cpp.o 161 | 162 | src/common.i: src/common.cpp.i 163 | 164 | .PHONY : src/common.i 165 | 166 | # target to preprocess a source file 167 | src/common.cpp.i: 168 | $(MAKE) -f CMakeFiles/main.dir/build.make CMakeFiles/main.dir/src/common.cpp.i 169 | .PHONY : src/common.cpp.i 170 | 171 | src/common.s: src/common.cpp.s 172 | 173 | .PHONY : src/common.s 174 | 175 | # target to generate assembly for a file 176 | src/common.cpp.s: 177 | $(MAKE) -f CMakeFiles/main.dir/build.make CMakeFiles/main.dir/src/common.cpp.s 178 | .PHONY : src/common.cpp.s 179 | 180 | src/demo.o: src/demo.cpp.o 181 | 182 | .PHONY : src/demo.o 183 | 184 | # target to build an object file 185 | src/demo.cpp.o: 186 | $(MAKE) -f CMakeFiles/main.dir/build.make CMakeFiles/main.dir/src/demo.cpp.o 187 | .PHONY : src/demo.cpp.o 188 | 189 | src/demo.i: src/demo.cpp.i 190 | 191 | .PHONY : src/demo.i 192 | 193 | # target to preprocess a source file 194 | src/demo.cpp.i: 195 | $(MAKE) -f CMakeFiles/main.dir/build.make CMakeFiles/main.dir/src/demo.cpp.i 196 | .PHONY : src/demo.cpp.i 197 | 198 | src/demo.s: src/demo.cpp.s 199 | 200 | .PHONY : src/demo.s 201 | 202 | # target to generate assembly for a file 203 | src/demo.cpp.s: 204 | $(MAKE) -f CMakeFiles/main.dir/build.make CMakeFiles/main.dir/src/demo.cpp.s 205 | .PHONY : src/demo.cpp.s 206 | 207 | src/mtcnn.o: src/mtcnn.cpp.o 208 | 209 | .PHONY : src/mtcnn.o 210 | 211 | # target to build an object file 212 | src/mtcnn.cpp.o: 213 | $(MAKE) -f CMakeFiles/main.dir/build.make CMakeFiles/main.dir/src/mtcnn.cpp.o 214 | .PHONY : src/mtcnn.cpp.o 215 | 216 | src/mtcnn.i: src/mtcnn.cpp.i 217 | 218 | .PHONY : src/mtcnn.i 219 | 220 | # target to preprocess a source file 221 | src/mtcnn.cpp.i: 222 | $(MAKE) -f CMakeFiles/main.dir/build.make CMakeFiles/main.dir/src/mtcnn.cpp.i 223 | .PHONY : src/mtcnn.cpp.i 224 | 225 | src/mtcnn.s: src/mtcnn.cpp.s 226 | 227 | .PHONY : src/mtcnn.s 228 | 229 | # target to generate assembly for a file 230 | src/mtcnn.cpp.s: 231 | $(MAKE) -f CMakeFiles/main.dir/build.make CMakeFiles/main.dir/src/mtcnn.cpp.s 232 | .PHONY : src/mtcnn.cpp.s 233 | 234 | src/network.o: src/network.cpp.o 235 | 236 | .PHONY : src/network.o 237 | 238 | # target to build an object file 239 | src/network.cpp.o: 240 | $(MAKE) -f CMakeFiles/main.dir/build.make CMakeFiles/main.dir/src/network.cpp.o 241 | .PHONY : src/network.cpp.o 242 | 243 | src/network.i: src/network.cpp.i 244 | 245 | .PHONY : src/network.i 246 | 247 | # target to preprocess a source file 248 | src/network.cpp.i: 249 | $(MAKE) -f CMakeFiles/main.dir/build.make CMakeFiles/main.dir/src/network.cpp.i 250 | .PHONY : src/network.cpp.i 251 | 252 | src/network.s: src/network.cpp.s 253 | 254 | .PHONY : src/network.s 255 | 256 | # target to generate assembly for a file 257 | src/network.cpp.s: 258 | $(MAKE) -f CMakeFiles/main.dir/build.make CMakeFiles/main.dir/src/network.cpp.s 259 | .PHONY : src/network.cpp.s 260 | 261 | src/onet_rt.o: src/onet_rt.cpp.o 262 | 263 | .PHONY : src/onet_rt.o 264 | 265 | # target to build an object file 266 | src/onet_rt.cpp.o: 267 | $(MAKE) -f CMakeFiles/main.dir/build.make CMakeFiles/main.dir/src/onet_rt.cpp.o 268 | .PHONY : src/onet_rt.cpp.o 269 | 270 | src/onet_rt.i: src/onet_rt.cpp.i 271 | 272 | .PHONY : src/onet_rt.i 273 | 274 | # target to preprocess a source file 275 | src/onet_rt.cpp.i: 276 | $(MAKE) -f CMakeFiles/main.dir/build.make CMakeFiles/main.dir/src/onet_rt.cpp.i 277 | .PHONY : src/onet_rt.cpp.i 278 | 279 | src/onet_rt.s: src/onet_rt.cpp.s 280 | 281 | .PHONY : src/onet_rt.s 282 | 283 | # target to generate assembly for a file 284 | src/onet_rt.cpp.s: 285 | $(MAKE) -f CMakeFiles/main.dir/build.make CMakeFiles/main.dir/src/onet_rt.cpp.s 286 | .PHONY : src/onet_rt.cpp.s 287 | 288 | src/pnet_rt.o: src/pnet_rt.cpp.o 289 | 290 | .PHONY : src/pnet_rt.o 291 | 292 | # target to build an object file 293 | src/pnet_rt.cpp.o: 294 | $(MAKE) -f CMakeFiles/main.dir/build.make CMakeFiles/main.dir/src/pnet_rt.cpp.o 295 | .PHONY : src/pnet_rt.cpp.o 296 | 297 | src/pnet_rt.i: src/pnet_rt.cpp.i 298 | 299 | .PHONY : src/pnet_rt.i 300 | 301 | # target to preprocess a source file 302 | src/pnet_rt.cpp.i: 303 | $(MAKE) -f CMakeFiles/main.dir/build.make CMakeFiles/main.dir/src/pnet_rt.cpp.i 304 | .PHONY : src/pnet_rt.cpp.i 305 | 306 | src/pnet_rt.s: src/pnet_rt.cpp.s 307 | 308 | .PHONY : src/pnet_rt.s 309 | 310 | # target to generate assembly for a file 311 | src/pnet_rt.cpp.s: 312 | $(MAKE) -f CMakeFiles/main.dir/build.make CMakeFiles/main.dir/src/pnet_rt.cpp.s 313 | .PHONY : src/pnet_rt.cpp.s 314 | 315 | src/rnet_rt.o: src/rnet_rt.cpp.o 316 | 317 | .PHONY : src/rnet_rt.o 318 | 319 | # target to build an object file 320 | src/rnet_rt.cpp.o: 321 | $(MAKE) -f CMakeFiles/main.dir/build.make CMakeFiles/main.dir/src/rnet_rt.cpp.o 322 | .PHONY : src/rnet_rt.cpp.o 323 | 324 | src/rnet_rt.i: src/rnet_rt.cpp.i 325 | 326 | .PHONY : src/rnet_rt.i 327 | 328 | # target to preprocess a source file 329 | src/rnet_rt.cpp.i: 330 | $(MAKE) -f CMakeFiles/main.dir/build.make CMakeFiles/main.dir/src/rnet_rt.cpp.i 331 | .PHONY : src/rnet_rt.cpp.i 332 | 333 | src/rnet_rt.s: src/rnet_rt.cpp.s 334 | 335 | .PHONY : src/rnet_rt.s 336 | 337 | # target to generate assembly for a file 338 | src/rnet_rt.cpp.s: 339 | $(MAKE) -f CMakeFiles/main.dir/build.make CMakeFiles/main.dir/src/rnet_rt.cpp.s 340 | .PHONY : src/rnet_rt.cpp.s 341 | 342 | # Help Target 343 | help: 344 | @echo "The following are some of the valid targets for this Makefile:" 345 | @echo "... all (the default if no target is provided)" 346 | @echo "... clean" 347 | @echo "... depend" 348 | @echo "... rebuild_cache" 349 | @echo "... main" 350 | @echo "... edit_cache" 351 | @echo "... src/baseEngine.o" 352 | @echo "... src/baseEngine.i" 353 | @echo "... src/baseEngine.s" 354 | @echo "... src/common.o" 355 | @echo "... src/common.i" 356 | @echo "... src/common.s" 357 | @echo "... src/demo.o" 358 | @echo "... src/demo.i" 359 | @echo "... src/demo.s" 360 | @echo "... src/mtcnn.o" 361 | @echo "... src/mtcnn.i" 362 | @echo "... src/mtcnn.s" 363 | @echo "... src/network.o" 364 | @echo "... src/network.i" 365 | @echo "... src/network.s" 366 | @echo "... src/onet_rt.o" 367 | @echo "... src/onet_rt.i" 368 | @echo "... src/onet_rt.s" 369 | @echo "... src/pnet_rt.o" 370 | @echo "... src/pnet_rt.i" 371 | @echo "... src/pnet_rt.s" 372 | @echo "... src/rnet_rt.o" 373 | @echo "... src/rnet_rt.i" 374 | @echo "... src/rnet_rt.s" 375 | .PHONY : help 376 | 377 | 378 | 379 | #============================================================================= 380 | # Special targets to cleanup operation of make. 381 | 382 | # Special rule to run CMake to check the build system integrity. 383 | # No rule that depends on this can have commands that come from listfiles 384 | # because they might be regenerated. 385 | cmake_check_build_system: 386 | $(CMAKE_COMMAND) -H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 0 387 | .PHONY : cmake_check_build_system 388 | 389 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | blob# MTCNN_TensorRT 2 | 3 | **MTCNN Face detection algorithm's C++ implementation with NVIDIA TensorRT Inference acceleration SDK.** 4 | 5 | This repository is based on https://github.com/AlphaQi/MTCNN-light.git 6 | 7 | ## Notations 8 | 9 | 2018/11/14: I have ported most of the computing to GPU using OpenCV CUDA warper and CUDA kernels wrote by myself. 10 | See branch all_gpu for more details, note that you need opencv 3.0+ built with CUDA support to run the projects. The speed is about 5-10 times faster on my GTX1080 GPU than master branch. 11 | 12 | 2018/10/2: Good news! Now you can run the whole MTCNN using TenorRT 3.0 or 4.0! 13 | 14 | I adopt the original models from offical project https://github.com/kpzhang93/MTCNN_face_detection_alignment and do the following modifications: 15 | Considering TensorRT don't support PRelu layer, which is widely used in MTCNN, one solution is to add Plugin Layer (costome layer) but experiments show that this method breaks the CBR process in TensorRT and is very slow. I use Relu layer, Scale layer and ElementWise addition Layer to replace Prelu (as illustrated below), which only adds a bit of computation and won't affect CBR process, the weights of scale layers derive from original Prelu layers. 16 | 17 | ![modification](https://github.com/PKUZHOU/MTCNN_TensorRT/blob/master/pictures/modification.png) 18 | 19 | 20 | ## Required environments 21 | 1) OpenCV (on ubuntu just run sudo apt-get install libopencv-dev to install opencv) 22 | 1) CUDA 9.0 23 | 1) TensorRT 3.04 or TensorRT 4.16 (I only test these two versions) 24 | 1) Cmake >=3.5 25 | 1) A digital camera to run camera test. 26 | 27 | ## Build 28 | 1) Replace the tensorrt and cuda path in CMakeLists.txt 29 | 1) Configure the detection parameters in mtcnn.cpp (min face size, the nms thresholds , etc) 30 | 1) Choose the running modes (camera test or single image test) 31 | 1) cmake . 32 | 1) make -j 33 | 1) ./main 34 | 35 | ## Results 36 | The result will be like this in single image test mode: 37 | 38 | ![single](https://github.com/PKUZHOU/MTCNN_TensorRT/blob/master/pictures/result.jpg) 39 | 40 | ## Speed 41 | On my computer with nvidia-gt730 grapic card (its performance is very very poor) and intel i5 6500 cpu, when the min face-size is set to 60 pixels, the above image costs 20 to 30ms. 42 | 43 | ## TODO 44 | Inplement the whole processing using GPU computing. 45 | 46 | 47 | -------------------------------------------------------------------------------- /det1_relu.caffemodel: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PKUZHOU/MTCNN_FaceDetection_TensorRT/dfad60565216a68413f434b500168c456fdd2587/det1_relu.caffemodel -------------------------------------------------------------------------------- /det1_relu.prototxt: -------------------------------------------------------------------------------- 1 | name: "PNet" 2 | layer 3 | { 4 | name: "data" 5 | type: "Input" 6 | top: "data" 7 | input_param{shape:{dim:1 dim:3 dim:12 dim:12}} 8 | } 9 | 10 | layer { 11 | name: "conv1" 12 | type: "Convolution" 13 | bottom: "data" 14 | top: "conv1" 15 | param { 16 | lr_mult: 1 17 | } 18 | param { 19 | lr_mult: 2 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 | } 31 | } 32 | } 33 | layer { 34 | name: "ReLU1" 35 | type: "ReLU" 36 | bottom: "conv1" 37 | top: "conv1_1" 38 | } 39 | 40 | layer { 41 | name: "scale1_1" 42 | bottom: "conv1" 43 | top: "conv1_2" 44 | type: "Scale" 45 | scale_param { 46 | axis: 1 47 | bias_term:false 48 | } 49 | } 50 | layer { 51 | name: "ReLU1_2" 52 | type: "ReLU" 53 | bottom: "conv1_2" 54 | top: "conv1_2" 55 | } 56 | layer { 57 | name: "scale1_2" 58 | bottom: "conv1_2" 59 | top: "conv1_2" 60 | type: "Scale" 61 | scale_param { 62 | axis: 1 63 | bias_term:false 64 | 65 | } 66 | } 67 | layer { 68 | name: "eltwise-sum1" 69 | type: "Eltwise" 70 | bottom: "conv1_1" 71 | bottom: "conv1_2" 72 | top: "conv1_3" 73 | eltwise_param { operation: SUM } 74 | } 75 | layer { 76 | name: "pool1" 77 | type: "Pooling" 78 | bottom: "conv1_3" 79 | top: "pool1" 80 | pooling_param { 81 | pool: MAX 82 | kernel_size: 2 83 | stride: 2 84 | } 85 | } 86 | 87 | layer { 88 | name: "conv2" 89 | type: "Convolution" 90 | bottom: "pool1" 91 | top: "conv2" 92 | param { 93 | lr_mult: 1 94 | } 95 | param { 96 | lr_mult: 2 97 | } 98 | convolution_param { 99 | num_output: 16 100 | kernel_size: 3 101 | stride: 1 102 | weight_filler { 103 | type: "xavier" 104 | } 105 | bias_filler { 106 | type: "constant" 107 | } 108 | } 109 | } 110 | layer { 111 | name: "ReLU2" 112 | type: "ReLU" 113 | bottom: "conv2" 114 | top: "conv2_1" 115 | } 116 | 117 | layer { 118 | name: "scale2_1" 119 | bottom: "conv2" 120 | top: "conv2_2" 121 | type: "Scale" 122 | scale_param { 123 | axis: 1 124 | bias_term:false 125 | 126 | } 127 | } 128 | layer { 129 | name: "ReLU2_2" 130 | type: "ReLU" 131 | bottom: "conv2_2" 132 | top: "conv2_2" 133 | } 134 | layer { 135 | name: "scale2_2" 136 | bottom: "conv2_2" 137 | top: "conv2_2" 138 | type: "Scale" 139 | scale_param { 140 | axis: 1 141 | bias_term:false 142 | } 143 | } 144 | layer { 145 | name: "eltwise-sum2" 146 | type: "Eltwise" 147 | bottom: "conv2_1" 148 | bottom: "conv2_2" 149 | top: "conv2_3" 150 | eltwise_param { operation: SUM } 151 | } 152 | 153 | 154 | layer { 155 | name: "conv3" 156 | type: "Convolution" 157 | bottom: "conv2_3" 158 | top: "conv3" 159 | param { 160 | lr_mult: 1 161 | } 162 | param { 163 | lr_mult: 2 164 | } 165 | convolution_param { 166 | num_output: 32 167 | kernel_size: 3 168 | stride: 1 169 | weight_filler { 170 | type: "xavier" 171 | } 172 | bias_filler { 173 | type: "constant" 174 | } 175 | } 176 | } 177 | layer { 178 | name: "ReLU3" 179 | type: "ReLU" 180 | bottom: "conv3" 181 | top: "conv3_1" 182 | } 183 | layer { 184 | name: "scale3_1" 185 | bottom: "conv3" 186 | top: "conv3_2" 187 | type: "Scale" 188 | scale_param { 189 | axis: 1 190 | bias_term:false 191 | } 192 | } 193 | layer { 194 | name: "ReLU3_2" 195 | type: "ReLU" 196 | bottom: "conv3_2" 197 | top: "conv3_2" 198 | } 199 | layer { 200 | name: "scale3_2" 201 | bottom: "conv3_2" 202 | top: "conv3_2" 203 | type: "Scale" 204 | scale_param { 205 | axis: 1 206 | bias_term:false 207 | } 208 | } 209 | layer { 210 | name: "eltwise-sum3" 211 | type: "Eltwise" 212 | bottom: "conv3_1" 213 | bottom: "conv3_2" 214 | top: "conv3_3" 215 | eltwise_param { operation: SUM } 216 | } 217 | 218 | layer { 219 | name: "conv4-1" 220 | type: "Convolution" 221 | bottom: "conv3_3" 222 | top: "conv4-1" 223 | param { 224 | lr_mult: 1 225 | decay_mult: 1 226 | } 227 | param { 228 | lr_mult: 2 229 | } 230 | convolution_param { 231 | num_output: 2 232 | kernel_size: 1 233 | stride: 1 234 | weight_filler { 235 | type: "xavier" 236 | } 237 | bias_filler { 238 | type: "constant" 239 | } 240 | } 241 | } 242 | 243 | layer { 244 | name: "conv4-2" 245 | type: "Convolution" 246 | bottom: "conv3_3" 247 | top: "conv4-2" 248 | param { 249 | lr_mult: 1 250 | } 251 | param { 252 | lr_mult: 2 253 | } 254 | convolution_param { 255 | num_output: 4 256 | kernel_size: 1 257 | stride: 1 258 | weight_filler { 259 | type: "xavier" 260 | } 261 | bias_filler { 262 | type: "constant" 263 | } 264 | } 265 | } 266 | layer { 267 | name: "prob1" 268 | type: "Softmax" 269 | bottom: "conv4-1" 270 | top: "prob1" 271 | } -------------------------------------------------------------------------------- /det2_relu.caffemodel: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PKUZHOU/MTCNN_FaceDetection_TensorRT/dfad60565216a68413f434b500168c456fdd2587/det2_relu.caffemodel -------------------------------------------------------------------------------- /det2_relu.prototxt: -------------------------------------------------------------------------------- 1 | name: "RNet" 2 | layer 3 | { 4 | name: "data" 5 | type: "Input" 6 | top: "data" 7 | input_param{shape:{dim:1 dim:3 dim:24 dim:24}} 8 | } 9 | 10 | layer { 11 | name: "conv1" 12 | type: "Convolution" 13 | bottom: "data" 14 | top: "conv1" 15 | param { 16 | lr_mult: 0 17 | decay_mult: 0 18 | } 19 | param { 20 | lr_mult: 0 21 | decay_mult: 0 22 | } 23 | convolution_param { 24 | num_output: 28 25 | kernel_size: 3 26 | stride: 1 27 | weight_filler { 28 | type: "xavier" 29 | } 30 | bias_filler { 31 | type: "constant" 32 | value: 0 33 | } 34 | } 35 | } 36 | layer { 37 | name: "relu1_1" 38 | type: "ReLU" 39 | bottom: "conv1" 40 | top: "conv1_1" 41 | propagate_down: true 42 | } 43 | 44 | layer { 45 | name: "scale1_1" 46 | bottom: "conv1" 47 | top: "conv1_2" 48 | type: "Scale" 49 | scale_param { 50 | axis: 1 51 | bias_term:false 52 | } 53 | } 54 | layer { 55 | name: "ReLU1_2" 56 | type: "ReLU" 57 | bottom: "conv1_2" 58 | top: "conv1_2" 59 | } 60 | layer { 61 | name: "scale1_2" 62 | bottom: "conv1_2" 63 | top: "conv1_2" 64 | type: "Scale" 65 | scale_param { 66 | axis: 1 67 | bias_term:false 68 | } 69 | } 70 | layer { 71 | name: "eltwise-sum1" 72 | type: "Eltwise" 73 | bottom: "conv1_1" 74 | bottom: "conv1_2" 75 | top: "conv1_3" 76 | eltwise_param { operation: SUM } 77 | } 78 | layer { 79 | name: "pool1" 80 | type: "Pooling" 81 | bottom: "conv1_3" 82 | top: "pool1" 83 | pooling_param { 84 | pool: MAX 85 | kernel_size: 3 86 | stride: 2 87 | } 88 | } 89 | 90 | layer { 91 | name: "conv2" 92 | type: "Convolution" 93 | bottom: "pool1" 94 | top: "conv2" 95 | param { 96 | lr_mult: 0 97 | decay_mult: 0 98 | } 99 | param { 100 | lr_mult: 0 101 | decay_mult: 0 102 | } 103 | convolution_param { 104 | num_output: 48 105 | kernel_size: 3 106 | stride: 1 107 | weight_filler { 108 | type: "xavier" 109 | } 110 | bias_filler { 111 | type: "constant" 112 | value: 0 113 | } 114 | } 115 | } 116 | layer { 117 | name: "relu2_1" 118 | type: "ReLU" 119 | bottom: "conv2" 120 | top: "conv2_1" 121 | propagate_down: true 122 | } 123 | 124 | layer { 125 | name: "scale2_1" 126 | bottom: "conv2" 127 | top: "conv2_2" 128 | type: "Scale" 129 | scale_param { 130 | axis: 1 131 | bias_term:false 132 | } 133 | } 134 | layer { 135 | name: "ReLU2_2" 136 | type: "ReLU" 137 | bottom: "conv2_2" 138 | top: "conv2_2" 139 | } 140 | layer { 141 | name: "scale2_2" 142 | bottom: "conv2_2" 143 | top: "conv2_2" 144 | type: "Scale" 145 | scale_param { 146 | axis: 1 147 | bias_term:false 148 | } 149 | } 150 | layer { 151 | name: "eltwise-sum2" 152 | type: "Eltwise" 153 | bottom: "conv2_1" 154 | bottom: "conv2_2" 155 | top: "conv2_3" 156 | eltwise_param { operation: SUM } 157 | } 158 | 159 | layer { 160 | name: "pool2" 161 | type: "Pooling" 162 | bottom: "conv2_3" 163 | top: "pool2" 164 | pooling_param { 165 | pool: MAX 166 | kernel_size: 3 167 | stride: 2 168 | } 169 | } 170 | #################################### 171 | 172 | ################################## 173 | layer { 174 | name: "conv3" 175 | type: "Convolution" 176 | bottom: "pool2" 177 | top: "conv3" 178 | param { 179 | lr_mult: 0 180 | decay_mult: 0 181 | } 182 | param { 183 | lr_mult: 0 184 | decay_mult: 0 185 | } 186 | convolution_param { 187 | num_output: 64 188 | kernel_size: 2 189 | stride: 1 190 | weight_filler { 191 | type: "xavier" 192 | } 193 | bias_filler { 194 | type: "constant" 195 | value: 0 196 | } 197 | } 198 | } 199 | 200 | layer { 201 | name: "scale3_1" 202 | bottom: "conv3" 203 | top: "conv3_2" 204 | type: "Scale" 205 | scale_param { 206 | axis: 1 207 | bias_term:false 208 | } 209 | } 210 | layer { 211 | name: "ReLU3_2" 212 | type: "ReLU" 213 | bottom: "conv3_2" 214 | top: "conv3_2" 215 | } 216 | layer { 217 | name: "scale3_2" 218 | bottom: "conv3_2" 219 | top: "conv3_2" 220 | type: "Scale" 221 | scale_param { 222 | axis: 1 223 | bias_term:false 224 | } 225 | } 226 | layer { 227 | name: "relu3" 228 | type: "ReLU" 229 | bottom: "conv3" 230 | top: "conv3_1" 231 | propagate_down: true 232 | } 233 | layer { 234 | name: "eltwise-sum3" 235 | type: "Eltwise" 236 | bottom: "conv3_1" 237 | bottom: "conv3_2" 238 | top: "conv3_3" 239 | eltwise_param { operation: SUM } 240 | } 241 | 242 | ############################### 243 | 244 | ############################### 245 | 246 | layer { 247 | name: "conv4" 248 | type: "InnerProduct" 249 | bottom: "conv3_3" 250 | top: "conv4" 251 | param { 252 | lr_mult: 0 253 | decay_mult: 0 254 | } 255 | param { 256 | lr_mult: 0 257 | decay_mult: 0 258 | } 259 | inner_product_param { 260 | num_output: 128 261 | weight_filler { 262 | type: "xavier" 263 | } 264 | bias_filler { 265 | type: "constant" 266 | value: 0 267 | } 268 | } 269 | } 270 | layer { 271 | name: "relu4_1" 272 | type: "ReLU" 273 | bottom: "conv4" 274 | top: "conv4_1" 275 | } 276 | 277 | layer { 278 | name: "scale4_1" 279 | bottom: "conv4" 280 | top: "conv4_2" 281 | type: "Scale" 282 | scale_param { 283 | axis: 1 284 | bias_term:false 285 | } 286 | } 287 | layer { 288 | name: "ReLU4_2" 289 | type: "ReLU" 290 | bottom: "conv4_2" 291 | top: "conv4_2" 292 | } 293 | layer { 294 | name: "scale4_2" 295 | bottom: "conv4_2" 296 | top: "conv4_2" 297 | type: "Scale" 298 | scale_param { 299 | axis: 1 300 | bias_term:false 301 | } 302 | } 303 | layer { 304 | name: "eltwise-sum4" 305 | type: "Eltwise" 306 | bottom: "conv4_1" 307 | bottom: "conv4_2" 308 | top: "conv4_3" 309 | eltwise_param { operation: SUM } 310 | } 311 | 312 | 313 | layer { 314 | name: "conv5-1" 315 | type: "InnerProduct" 316 | bottom: "conv4_3" 317 | top: "conv5-1" 318 | param { 319 | lr_mult: 0 320 | decay_mult: 0 321 | } 322 | param { 323 | lr_mult: 0 324 | decay_mult: 0 325 | } 326 | inner_product_param { 327 | num_output: 2 328 | #kernel_size: 1 329 | #stride: 1 330 | weight_filler { 331 | type: "xavier" 332 | } 333 | bias_filler { 334 | type: "constant" 335 | value: 0 336 | } 337 | } 338 | } 339 | layer { 340 | name: "conv5-2" 341 | type: "InnerProduct" 342 | bottom: "conv4_3" 343 | top: "conv5-2" 344 | param { 345 | lr_mult: 1 346 | decay_mult: 1 347 | } 348 | param { 349 | lr_mult: 2 350 | decay_mult: 1 351 | } 352 | inner_product_param { 353 | num_output: 4 354 | #kernel_size: 1 355 | #stride: 1 356 | weight_filler { 357 | type: "xavier" 358 | } 359 | bias_filler { 360 | type: "constant" 361 | value: 0 362 | } 363 | } 364 | } 365 | layer { 366 | name: "prob1" 367 | type: "Softmax" 368 | bottom: "conv5-1" 369 | top: "prob1" 370 | } -------------------------------------------------------------------------------- /det3_relu.caffemodel: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PKUZHOU/MTCNN_FaceDetection_TensorRT/dfad60565216a68413f434b500168c456fdd2587/det3_relu.caffemodel -------------------------------------------------------------------------------- /det3_relu.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: "relu1_1" 36 | type: "ReLU" 37 | bottom: "conv1" 38 | top: "conv1_1" 39 | } 40 | 41 | layer { 42 | name: "scale1_1" 43 | bottom: "conv1" 44 | top: "conv1_2" 45 | type: "Scale" 46 | scale_param { 47 | axis: 1 48 | bias_term:false 49 | } 50 | } 51 | layer { 52 | name: "ReLU1_2" 53 | type: "ReLU" 54 | bottom: "conv1_2" 55 | top: "conv1_2" 56 | } 57 | layer { 58 | name: "scale1_2" 59 | bottom: "conv1_2" 60 | top: "conv1_2" 61 | type: "Scale" 62 | scale_param { 63 | axis: 1 64 | bias_term:false 65 | } 66 | } 67 | layer { 68 | name: "eltwise-sum1" 69 | type: "Eltwise" 70 | bottom: "conv1_1" 71 | bottom: "conv1_2" 72 | top: "conv1_3" 73 | eltwise_param { operation: SUM } 74 | } 75 | 76 | layer { 77 | name: "pool1" 78 | type: "Pooling" 79 | bottom: "conv1_3" 80 | top: "pool1" 81 | pooling_param { 82 | pool: MAX 83 | kernel_size: 3 84 | stride: 2 85 | } 86 | } 87 | layer { 88 | name: "conv2" 89 | type: "Convolution" 90 | bottom: "pool1" 91 | top: "conv2" 92 | param { 93 | lr_mult: 1 94 | decay_mult: 1 95 | } 96 | param { 97 | lr_mult: 2 98 | decay_mult: 1 99 | } 100 | convolution_param { 101 | num_output: 64 102 | kernel_size: 3 103 | stride: 1 104 | weight_filler { 105 | type: "xavier" 106 | } 107 | bias_filler { 108 | type: "constant" 109 | value: 0 110 | } 111 | } 112 | } 113 | 114 | layer { 115 | name: "relu2_1" 116 | type: "ReLU" 117 | bottom: "conv2" 118 | top: "conv2_1" 119 | } 120 | layer { 121 | name: "scale2_1" 122 | bottom: "conv2" 123 | top: "conv2_2" 124 | type: "Scale" 125 | scale_param { 126 | axis: 1 127 | bias_term:false 128 | } 129 | } 130 | layer { 131 | name: "ReLU2_2" 132 | type: "ReLU" 133 | bottom: "conv2_2" 134 | top: "conv2_2" 135 | } 136 | layer { 137 | name: "scale2_2" 138 | bottom: "conv2_2" 139 | top: "conv2_2" 140 | type: "Scale" 141 | scale_param { 142 | axis: 1 143 | bias_term:false 144 | } 145 | } 146 | layer { 147 | name: "eltwise-sum2" 148 | type: "Eltwise" 149 | bottom: "conv2_1" 150 | bottom: "conv2_2" 151 | top: "conv2_3" 152 | eltwise_param { operation: SUM } 153 | } 154 | layer { 155 | name: "pool2" 156 | type: "Pooling" 157 | bottom: "conv2_3" 158 | top: "pool2" 159 | pooling_param { 160 | pool: MAX 161 | kernel_size: 3 162 | stride: 2 163 | } 164 | } 165 | 166 | layer { 167 | name: "conv3" 168 | type: "Convolution" 169 | bottom: "pool2" 170 | top: "conv3" 171 | param { 172 | lr_mult: 1 173 | decay_mult: 1 174 | } 175 | param { 176 | lr_mult: 2 177 | decay_mult: 1 178 | } 179 | convolution_param { 180 | num_output: 64 181 | kernel_size: 3 182 | weight_filler { 183 | type: "xavier" 184 | } 185 | bias_filler { 186 | type: "constant" 187 | value: 0 188 | } 189 | } 190 | } 191 | layer { 192 | name: "relu3_1" 193 | type: "ReLU" 194 | bottom: "conv3" 195 | top: "conv3_1" 196 | } 197 | layer { 198 | name: "scale3_1" 199 | bottom: "conv3" 200 | top: "conv3_2" 201 | type: "Scale" 202 | scale_param { 203 | axis: 1 204 | bias_term:false 205 | } 206 | } 207 | layer { 208 | name: "ReLU3_2" 209 | type: "ReLU" 210 | bottom: "conv3_2" 211 | top: "conv3_2" 212 | } 213 | layer { 214 | name: "scale3_2" 215 | bottom: "conv3_2" 216 | top: "conv3_2" 217 | type: "Scale" 218 | scale_param { 219 | axis: 1 220 | bias_term:false 221 | } 222 | } 223 | layer { 224 | name: "eltwise-sum3" 225 | type: "Eltwise" 226 | bottom: "conv3_1" 227 | bottom: "conv3_2" 228 | top: "conv3_3" 229 | eltwise_param { operation: SUM } 230 | } 231 | layer { 232 | name: "pool3" 233 | type: "Pooling" 234 | bottom: "conv3_3" 235 | top: "pool3" 236 | pooling_param { 237 | pool: MAX 238 | kernel_size: 2 239 | stride: 2 240 | } 241 | } 242 | layer { 243 | name: "conv4" 244 | type: "Convolution" 245 | bottom: "pool3" 246 | top: "conv4" 247 | param { 248 | lr_mult: 1 249 | decay_mult: 1 250 | } 251 | param { 252 | lr_mult: 2 253 | decay_mult: 1 254 | } 255 | convolution_param { 256 | num_output: 128 257 | kernel_size: 2 258 | weight_filler { 259 | type: "xavier" 260 | } 261 | bias_filler { 262 | type: "constant" 263 | value: 0 264 | } 265 | } 266 | } 267 | layer { 268 | name: "relu4" 269 | type: "ReLU" 270 | bottom: "conv4" 271 | top: "conv4_1" 272 | } 273 | 274 | layer { 275 | name: "scale4_1" 276 | bottom: "conv4" 277 | top: "conv4_2" 278 | type: "Scale" 279 | scale_param { 280 | axis: 1 281 | bias_term:false 282 | } 283 | } 284 | layer { 285 | name: "ReLU4_2" 286 | type: "ReLU" 287 | bottom: "conv4_2" 288 | top: "conv4_2" 289 | } 290 | layer { 291 | name: "scale4_2" 292 | bottom: "conv4_2" 293 | top: "conv4_2" 294 | type: "Scale" 295 | scale_param { 296 | axis: 1 297 | bias_term:false 298 | } 299 | } 300 | layer { 301 | name: "eltwise-sum4" 302 | type: "Eltwise" 303 | bottom: "conv4_1" 304 | bottom: "conv4_2" 305 | top: "conv4_3" 306 | eltwise_param { operation: SUM } 307 | } 308 | 309 | layer { 310 | name: "conv5" 311 | type: "InnerProduct" 312 | bottom: "conv4_3" 313 | top: "conv5" 314 | param { 315 | lr_mult: 1 316 | decay_mult: 1 317 | } 318 | param { 319 | lr_mult: 2 320 | decay_mult: 1 321 | } 322 | inner_product_param { 323 | #kernel_size: 3 324 | num_output: 256 325 | weight_filler { 326 | type: "xavier" 327 | } 328 | bias_filler { 329 | type: "constant" 330 | value: 0 331 | } 332 | } 333 | } 334 | 335 | layer { 336 | name: "relu5_1" 337 | type: "ReLU" 338 | bottom: "conv5" 339 | top: "conv5_1" 340 | } 341 | 342 | layer { 343 | name: "scale5_1" 344 | bottom: "conv5" 345 | top: "conv5_2" 346 | type: "Scale" 347 | scale_param { 348 | axis: 1 349 | bias_term:false 350 | } 351 | } 352 | layer { 353 | name: "ReLU5_2" 354 | type: "ReLU" 355 | bottom: "conv5_2" 356 | top: "conv5_2" 357 | } 358 | layer { 359 | name: "scale5_2" 360 | bottom: "conv5_2" 361 | top: "conv5_2" 362 | type: "Scale" 363 | scale_param { 364 | axis: 1 365 | bias_term:false 366 | } 367 | } 368 | layer { 369 | name: "eltwise-sum5" 370 | type: "Eltwise" 371 | bottom: "conv5_1" 372 | bottom: "conv5_2" 373 | top: "conv5_3" 374 | eltwise_param { operation: SUM } 375 | } 376 | 377 | layer { 378 | name: "conv6-1" 379 | type: "InnerProduct" 380 | bottom: "conv5_3" 381 | top: "conv6-1" 382 | param { 383 | lr_mult: 1 384 | decay_mult: 1 385 | } 386 | param { 387 | lr_mult: 2 388 | decay_mult: 1 389 | } 390 | inner_product_param { 391 | #kernel_size: 1 392 | num_output: 2 393 | weight_filler { 394 | type: "xavier" 395 | } 396 | bias_filler { 397 | type: "constant" 398 | value: 0 399 | } 400 | } 401 | } 402 | layer { 403 | name: "conv6-2" 404 | type: "InnerProduct" 405 | bottom: "conv5_3" 406 | top: "conv6-2" 407 | param { 408 | lr_mult: 1 409 | decay_mult: 1 410 | } 411 | param { 412 | lr_mult: 2 413 | decay_mult: 1 414 | } 415 | inner_product_param { 416 | #kernel_size: 1 417 | num_output: 4 418 | weight_filler { 419 | type: "xavier" 420 | } 421 | bias_filler { 422 | type: "constant" 423 | value: 0 424 | } 425 | } 426 | } 427 | layer { 428 | name: "conv6-3" 429 | type: "InnerProduct" 430 | bottom: "conv5_3" 431 | top: "conv6-3" 432 | param { 433 | lr_mult: 1 434 | decay_mult: 1 435 | } 436 | param { 437 | lr_mult: 2 438 | decay_mult: 1 439 | } 440 | inner_product_param { 441 | #kernel_size: 1 442 | num_output: 10 443 | weight_filler { 444 | type: "xavier" 445 | } 446 | bias_filler { 447 | type: "constant" 448 | value: 0 449 | } 450 | } 451 | } 452 | layer { 453 | name: "prob1" 454 | type: "Softmax" 455 | bottom: "conv6-1" 456 | top: "prob1" 457 | } -------------------------------------------------------------------------------- /main: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PKUZHOU/MTCNN_FaceDetection_TensorRT/dfad60565216a68413f434b500168c456fdd2587/main -------------------------------------------------------------------------------- /pictures/QR.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PKUZHOU/MTCNN_FaceDetection_TensorRT/dfad60565216a68413f434b500168c456fdd2587/pictures/QR.png -------------------------------------------------------------------------------- /pictures/modification.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PKUZHOU/MTCNN_FaceDetection_TensorRT/dfad60565216a68413f434b500168c456fdd2587/pictures/modification.png -------------------------------------------------------------------------------- /pictures/qrcode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PKUZHOU/MTCNN_FaceDetection_TensorRT/dfad60565216a68413f434b500168c456fdd2587/pictures/qrcode.png -------------------------------------------------------------------------------- /pictures/result.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PKUZHOU/MTCNN_FaceDetection_TensorRT/dfad60565216a68413f434b500168c456fdd2587/pictures/result.jpg -------------------------------------------------------------------------------- /pictures/vrcode.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PKUZHOU/MTCNN_FaceDetection_TensorRT/dfad60565216a68413f434b500168c456fdd2587/pictures/vrcode.jpg -------------------------------------------------------------------------------- /result.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PKUZHOU/MTCNN_FaceDetection_TensorRT/dfad60565216a68413f434b500168c456fdd2587/result.jpg -------------------------------------------------------------------------------- /src/baseEngine.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by zhou on 18-5-4. 3 | // 4 | 5 | #include "baseEngine.h" 6 | baseEngine::baseEngine(const char * prototxt,const char* model,const char* input_name,const char*location_name, 7 | const char* prob_name, const char *point_name) : 8 | prototxt(prototxt), 9 | model(model), 10 | INPUT_BLOB_NAME(input_name), 11 | OUTPUT_LOCATION_NAME(location_name), 12 | OUTPUT_PROB_NAME(prob_name), 13 | OUTPUT_POINT_NAME(point_name) 14 | { 15 | }; 16 | baseEngine::~baseEngine() { 17 | shutdownProtobufLibrary(); 18 | } 19 | 20 | void baseEngine::init(int row,int col) { 21 | 22 | } 23 | void baseEngine::caffeToGIEModel(const std::string &deployFile, // name for caffe prototxt 24 | const std::string &modelFile, // name for model 25 | const std::vector &outputs, // network outputs 26 | unsigned int maxBatchSize, // batch size - NB must be at least as large as the batch we want to run with) 27 | IHostMemory *&gieModelStream) // output buffer for the GIE model 28 | { 29 | // create the builder 30 | IBuilder *builder = createInferBuilder(gLogger); 31 | 32 | // parse the caffe model to populate the network, then set the outputs 33 | INetworkDefinition *network = builder->createNetwork(); 34 | ICaffeParser *parser = createCaffeParser(); 35 | 36 | const IBlobNameToTensor *blobNameToTensor = parser->parse(deployFile.c_str(), 37 | modelFile.c_str(), 38 | *network, 39 | nvinfer1::DataType::kFLOAT); 40 | // specify which tensors are outputs 41 | for (auto &s : outputs) 42 | network->markOutput(*blobNameToTensor->find(s.c_str())); 43 | 44 | // Build the engine 45 | builder->setMaxBatchSize(maxBatchSize); 46 | builder->setMaxWorkspaceSize(1 << 25); 47 | ICudaEngine*engine = builder->buildCudaEngine(*network); 48 | assert(engine); 49 | context = engine->createExecutionContext(); 50 | 51 | // we don't need the network any more, and we can destroy the parser 52 | network->destroy(); 53 | parser->destroy(); 54 | builder->destroy(); 55 | 56 | } -------------------------------------------------------------------------------- /src/baseEngine.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by zhou on 18-5-4. 3 | // 4 | #include "common.h" 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include "NvInfer.h" 13 | #include "NvCaffeParser.h" 14 | #ifndef MAIN_BASEENGINE_H 15 | #define MAIN_BASEENGINE_H 16 | using namespace nvinfer1; 17 | using namespace nvcaffeparser1; 18 | using namespace std; 19 | 20 | class baseEngine { 21 | public: 22 | baseEngine(const char *prototxt,const char*model,const char*out_name, 23 | const char*location_name,const char*prob_name,const char *point_name = NULL); 24 | virtual ~baseEngine(); 25 | virtual void caffeToGIEModel(const std::string& deployFile, // name for caffe prototxt 26 | const std::string& modelFile, // name for model 27 | const std::vector& outputs, // network outputs 28 | unsigned int maxBatchSize, // batch size - NB must be at least as large as the batch we want to run with) 29 | IHostMemory *&gieModelStream); // output buffer for the GIE model 30 | virtual void init(int row,int col); 31 | friend class Pnet; 32 | const string prototxt; 33 | const string model ; 34 | const char *INPUT_BLOB_NAME; 35 | const char *OUTPUT_PROB_NAME; 36 | const char *OUTPUT_LOCATION_NAME; 37 | const char *OUTPUT_POINT_NAME; 38 | Logger gLogger; 39 | IExecutionContext *context; 40 | }; 41 | #endif //MAIN_BASEENGINE_H 42 | -------------------------------------------------------------------------------- /src/common.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by zhou on 18-4-30. 3 | // 4 | 5 | #include "common.h" 6 | std::string locateFile(const std::string& input, const std::vector & directories) 7 | { 8 | std::string file; 9 | const int MAX_DEPTH{10}; 10 | bool found{false}; 11 | for (auto &dir : directories) 12 | { 13 | file = dir + input; 14 | for (int i = 0; i < MAX_DEPTH && !found; i++) 15 | { 16 | std::ifstream checkFile(file.c_str()); 17 | found = checkFile.is_open(); 18 | if (found) break; 19 | file = "../" + file; 20 | } 21 | if (found) break; 22 | file.clear(); 23 | } 24 | 25 | assert(!file.empty() && "Could not find a file due to it not existing in the data directory."); 26 | return file; 27 | } 28 | 29 | void readPGMFile(const std::string& fileName, uint8_t *buffer, int inH, int inW) 30 | { 31 | std::ifstream infile(fileName, std::ifstream::binary); 32 | assert(infile.is_open() && "Attempting to read from a file that is not open."); 33 | std::string magic, h, w, max; 34 | infile >> magic >> h >> w >> max; 35 | infile.seekg(1, infile.cur); 36 | infile.read(reinterpret_cast(buffer), inH*inW); 37 | } 38 | -------------------------------------------------------------------------------- /src/common.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by zhou on 18-4-30. 3 | // 4 | 5 | #ifndef _TRT_COMMON_H_ 6 | #define _TRT_COMMON_H_ 7 | #include "NvInfer.h" 8 | #include 9 | #include 10 | #include 11 | #include 12 | //#include 13 | #include 14 | #define CHECK(status) \ 15 | { \ 16 | if (status != 0) \ 17 | { \ 18 | std::cout << "Cuda failure: " << status; \ 19 | abort(); \ 20 | } \ 21 | } 22 | 23 | 24 | // Logger for GIE info/warning/errors 25 | class Logger : public nvinfer1::ILogger 26 | { 27 | public: 28 | void log(nvinfer1::ILogger::Severity severity, const char* msg) override 29 | { 30 | // suppress info-level messages 31 | if (severity == Severity::kINFO) return; 32 | 33 | switch (severity) 34 | { 35 | case Severity::kINTERNAL_ERROR: std::cerr << "INTERNAL_ERROR: "; break; 36 | case Severity::kERROR: std::cerr << "ERROR: "; break; 37 | case Severity::kWARNING: std::cerr << "WARNING: "; break; 38 | case Severity::kINFO: std::cerr << "INFO: "; break; 39 | default: std::cerr << "UNKNOWN: "; break; 40 | } 41 | std::cerr << msg << std::endl; 42 | } 43 | }; 44 | 45 | std::string locateFile(const std::string& input, const std::vector & directories); 46 | void readPGMFile(const std::string& fileName, uint8_t *buffer, int inH, int inW); 47 | #endif // _TRT_COMMON_H_ 48 | -------------------------------------------------------------------------------- /src/demo.cpp: -------------------------------------------------------------------------------- 1 | #include "network.h" 2 | #include "mtcnn.h" 3 | #include 4 | 5 | void camera_test(int frames) 6 | { 7 | Mat image; 8 | VideoCapture cap(0); 9 | if(!cap.isOpened()) 10 | cout<<"fail to open!"<>image; 12 | if(!image.data) { 13 | cout << "unable to open camera" << endl; 14 | return; 15 | } 16 | mtcnn find(image.rows, image.cols); 17 | clock_t start; 18 | int stop = frames; 19 | while(stop--){ 20 | start = clock(); 21 | cap>>image; 22 | find.findFace(image); 23 | imshow("result", image); 24 | waitKey(1); 25 | start = clock() -start; 26 | cout<<"time is "<<(double)start/CLOCKS_PER_SEC<MIN_DET_SIZE){ 18 | if(factor_count>0)m = m*factor; 19 | scales_.push_back(m); 20 | minl *= factor; 21 | factor_count++; 22 | } 23 | float minside = row::iterator it = scales_.begin(); it != scales_.end(); it++){ 26 | if (*it > 1){ 27 | cout << "the minsize is too small" << endl; 28 | while (1); 29 | } 30 | if (*it < (MIN_DET_SIZE / minside)){ 31 | scales_.resize(count); 32 | break; 33 | } 34 | count++; 35 | } 36 | 37 | cout<<"Start generating TenosrRT runtime models"<init(24,24); 51 | refineNet = new Rnet(*rnet_engine); 52 | 53 | //generate onet model 54 | onet_engine = new Onet_engine(); 55 | onet_engine->init(48,48); 56 | outNet = new Onet(*onet_engine); 57 | cout<<"End generating TensorRT runtime models"<::iterator it=(*simpleFace_[i]).boundingBox_.begin(); it!= (*simpleFace_[i]).boundingBox_.end();it++){ 83 | if((*it).exist){ 84 | firstBbox_.push_back(*it); 85 | order.score = (*it).score; 86 | order.oriOrder = count; 87 | firstOrderScore_.push_back(order); 88 | count++; 89 | } 90 | } 91 | (*simpleFace_[i]).bboxScore_.clear(); 92 | (*simpleFace_[i]).boundingBox_.clear(); 93 | } 94 | //the first stage's nms 95 | if(count<1)return; 96 | nms(firstBbox_, firstOrderScore_, nms_threshold[0]); 97 | refineAndSquareBbox(firstBbox_, image.rows, image.cols,true); 98 | #ifdef LOG 99 | first_time = clock() - first_time; 100 | cout<<"first time is "<<1000*(double)first_time/CLOCKS_PER_SEC<::iterator it=firstBbox_.begin(); it!=firstBbox_.end();it++){ 106 | if((*it).exist){ 107 | Rect temp((*it).y1, (*it).x1, (*it).y2-(*it).y1, (*it).x2-(*it).x1); 108 | Mat secImage; 109 | resize(image(temp), secImage, Size(24, 24), 0, 0, cv::INTER_LINEAR); 110 | transpose(secImage,secImage); 111 | refineNet->run(secImage,*rnet_engine); 112 | if(*(refineNet->score_->pdata+1)>refineNet->Rthreshold){ 113 | memcpy(it->regreCoord, refineNet->location_->pdata, 4*sizeof(mydataFmt)); 114 | it->area = (it->x2 - it->x1)*(it->y2 - it->y1); 115 | it->score = *(refineNet->score_->pdata+1); 116 | secondBbox_.push_back(*it); 117 | order.score = it->score; 118 | order.oriOrder = count++; 119 | secondBboxScore_.push_back(order); 120 | } 121 | else{ 122 | (*it).exist=false; 123 | } 124 | } 125 | } 126 | if(count<1)return; 127 | nms(secondBbox_, secondBboxScore_, nms_threshold[1]); 128 | refineAndSquareBbox(secondBbox_, image.rows, image.cols,true); 129 | second_time = clock() - second_time; 130 | #ifdef LOG 131 | cout<<"second time is "<<1000*(double)second_time/CLOCKS_PER_SEC<::iterator it=secondBbox_.begin(); it!=secondBbox_.end();it++){ 137 | if((*it).exist){ 138 | Rect temp((*it).y1, (*it).x1, (*it).y2-(*it).y1, (*it).x2-(*it).x1); 139 | Mat thirdImage; 140 | resize(image(temp), thirdImage, Size(48, 48), 0, 0, cv::INTER_LINEAR); 141 | transpose(thirdImage,thirdImage); 142 | outNet->run(thirdImage,*onet_engine); 143 | mydataFmt *pp=NULL; 144 | if(*(outNet->score_->pdata+1)>outNet->Othreshold){ 145 | memcpy(it->regreCoord, outNet->location_->pdata, 4*sizeof(mydataFmt)); 146 | it->area = (it->x2 - it->x1)*(it->y2 - it->y1); 147 | it->score = *(outNet->score_->pdata+1); 148 | pp = outNet->points_->pdata; 149 | for(int num=0;num<5;num++){ 150 | (it->ppoint)[num] = it->y1 + (it->y2 - it->y1)*(*(pp+num)); 151 | } 152 | for(int num=0;num<5;num++){ 153 | (it->ppoint)[num+5] = it->x1 + (it->x2 - it->x1)*(*(pp+num+5)); 154 | } 155 | thirdBbox_.push_back(*it); 156 | order.score = it->score; 157 | order.oriOrder = count++; 158 | thirdBboxScore_.push_back(order); 159 | } 160 | else{ 161 | it->exist=false; 162 | } 163 | } 164 | } 165 | 166 | if(count<1)return; 167 | refineAndSquareBbox(thirdBbox_, image.rows, image.cols, true); 168 | nms(thirdBbox_, thirdBboxScore_, nms_threshold[2], "Min"); 169 | #ifdef LOG 170 | third_time = clock() - third_time; 171 | cout<<"third time is "<<1000*(double)third_time/CLOCKS_PER_SEC<::iterator it=thirdBbox_.begin(); it!=thirdBbox_.end();it++){ 174 | if((*it).exist){ 175 | rectangle(image, Point((*it).y1, (*it).x1), Point((*it).y2, (*it).x2), Scalar(0,0,255), 2,8,0); 176 | for(int num=0;num<5;num++)circle(image,Point((int)*(it->ppoint+num), (int)*(it->ppoint+num+5)),3,Scalar(0,255,255), -1); 177 | } 178 | } 179 | firstBbox_.clear(); 180 | firstOrderScore_.clear(); 181 | secondBbox_.clear(); 182 | secondBboxScore_.clear(); 183 | thirdBbox_.clear(); 184 | thirdBboxScore_.clear(); 185 | } 186 | -------------------------------------------------------------------------------- /src/mtcnn.h: -------------------------------------------------------------------------------- 1 | #ifndef MTCNN_H 2 | #define MTCNN_H 3 | #include "network.h" 4 | #include "pnet_rt.h" 5 | #include "rnet_rt.h" 6 | #include "onet_rt.h" 7 | class mtcnn 8 | { 9 | public: 10 | mtcnn(int row, int col); 11 | ~mtcnn(); 12 | void findFace(Mat &image); 13 | private: 14 | Mat reImage; 15 | float nms_threshold[3]; 16 | vector scales_; 17 | Pnet_engine *pnet_engine; 18 | Pnet **simpleFace_; 19 | vector firstBbox_; 20 | vector firstOrderScore_; 21 | Rnet *refineNet; 22 | Rnet_engine *rnet_engine; 23 | vector secondBbox_; 24 | vector secondBboxScore_; 25 | Onet *outNet; 26 | Onet_engine *onet_engine; 27 | vector thirdBbox_; 28 | vector thirdBboxScore_; 29 | }; 30 | 31 | #endif -------------------------------------------------------------------------------- /src/network.cpp: -------------------------------------------------------------------------------- 1 | #include "network.h" 2 | void image2Matrix(const Mat &image, const struct pBox *pbox){ 3 | if ((image.data == NULL) || (image.type() != CV_8UC3)){ 4 | cout << "image's type is wrong!!Please set CV_8UC3" << endl; 5 | return; 6 | } 7 | if (pbox->pdata == NULL){ 8 | return; 9 | } 10 | mydataFmt *p = pbox->pdata; 11 | for (int rowI = 0; rowI < image.rows; rowI++){ 12 | for (int colK = 0; colK < image.cols; colK++){ 13 | *p = (image.at(rowI, colK)[2] - 127.5)*0.007812; 14 | *(p + image.rows*image.cols) = (image.at(rowI, colK)[1] - 127.5)*0.0078125; 15 | *(p + 2*image.rows*image.cols) = (image.at(rowI, colK)[0] - 127.5)*0.0078125; 16 | p++; 17 | } 18 | } 19 | } 20 | bool cmpScore(struct orderScore lsh, struct orderScore rsh){ 21 | if(lsh.score &boundingBox_, vector &bboxScore_, const float overlap_threshold, string modelname){ 27 | if(boundingBox_.empty()){ 28 | return; 29 | } 30 | std::vector heros; 31 | //sort the score 32 | sort(bboxScore_.begin(), bboxScore_.end(), cmpScore); 33 | 34 | int order = 0; 35 | float IOU = 0; 36 | float maxX = 0; 37 | float maxY = 0; 38 | float minX = 0; 39 | float minY = 0; 40 | while(bboxScore_.size()>0){ 41 | order = bboxScore_.back().oriOrder; 42 | bboxScore_.pop_back(); 43 | if(order<0)continue; 44 | heros.push_back(order); 45 | boundingBox_.at(order).exist = false;//delete it 46 | 47 | for(int num=0;numboundingBox_.at(order).x1)?boundingBox_.at(num).x1:boundingBox_.at(order).x1; 51 | maxY = (boundingBox_.at(num).y1>boundingBox_.at(order).y1)?boundingBox_.at(num).y1:boundingBox_.at(order).y1; 52 | minX = (boundingBox_.at(num).x20)?(minX-maxX+1):0; 56 | maxY = ((minY-maxY+1)>0)?(minY-maxY+1):0; 57 | //IOU reuse for the area of two bbox 58 | IOU = maxX * maxY; 59 | if(!modelname.compare("Union")) 60 | IOU = IOU/(boundingBox_.at(num).area + boundingBox_.at(order).area - IOU); 61 | else if(!modelname.compare("Min")){ 62 | IOU = IOU/((boundingBox_.at(num).areaoverlap_threshold){ 65 | boundingBox_.at(num).exist=false; 66 | for(vector::iterator it=bboxScore_.begin(); it!=bboxScore_.end();it++){ 67 | if((*it).oriOrder == num) { 68 | (*it).oriOrder = -1; 69 | break; 70 | } 71 | } 72 | } 73 | } 74 | } 75 | } 76 | for(int i=0;i &vecBbox, const int &height, const int &width, bool square = true){ 80 | if(vecBbox.empty()){ 81 | cout<<"Bbox is empty!!"<::iterator it=vecBbox.begin(); it!=vecBbox.end();it++){ 88 | if((*it).exist){ 89 | bbh = (*it).x2 - (*it).x1 + 1; 90 | bbw = (*it).y2 - (*it).y1 + 1; 91 | x1 = (*it).x1 + (*it).regreCoord[1]*bbh; 92 | y1 = (*it).y1 + (*it).regreCoord[0]*bbw; 93 | x2 = (*it).x2 + (*it).regreCoord[3]*bbh; 94 | y2 = (*it).y2 + (*it).regreCoord[2]*bbw; 95 | 96 | 97 | 98 | h = x2 - x1 + 1; 99 | w = y2 - y1 + 1; 100 | 101 | if(square) 102 | { 103 | maxSide = (h>w)?h:w; 104 | x1 = x1 + h*0.5 - maxSide*0.5; 105 | y1 = y1 + w*0.5 - maxSide*0.5; 106 | (*it).x2 = round(x1 + maxSide - 1); 107 | (*it).y2 = round(y1 + maxSide - 1); 108 | (*it).x1 = round(x1); 109 | (*it).y1 = round(y1); 110 | } else 111 | { 112 | (*it).x1 = x1; 113 | (*it).y1 = y1; 114 | (*it).x2 = x2; 115 | (*it).y2 = y2; 116 | } 117 | 118 | 119 | 120 | //boundary check 121 | if((*it).x1<0)(*it).x1=0; 122 | if((*it).y1<0)(*it).y1=0; 123 | if((*it).x2>height)(*it).x2 = height - 1; 124 | if((*it).y2>width)(*it).y2 = width - 1; 125 | 126 | it->area = (it->x2 - it->x1)*(it->y2 - it->y1); 127 | } 128 | } 129 | } -------------------------------------------------------------------------------- /src/network.h: -------------------------------------------------------------------------------- 1 | //c++ network author : liqi 2 | //Nangjing University of Posts and Telecommunications 3 | //date 2017.5.21,20:27 4 | #ifndef NETWORK_H 5 | #define NETWORK_H 6 | #include "opencv2/imgproc/imgproc.hpp" 7 | #include "opencv2/highgui/highgui.hpp" 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include "pBox.h" 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include "NvInfer.h" 25 | #include "NvCaffeParser.h" 26 | using namespace cv; 27 | 28 | void image2Matrix(const Mat &image, const struct pBox *pbox); 29 | bool cmpScore(struct orderScore lsh, struct orderScore rsh); 30 | void nms(vector &boundingBox_, vector &bboxScore_, const float overlap_threshold, string modelname = "Union"); 31 | void refineAndSquareBbox(vector &vecBbox, const int &height, const int &width,bool square); 32 | 33 | #endif -------------------------------------------------------------------------------- /src/onet_rt.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by zhou on 18-10-2. 3 | // 4 | 5 | #include "onet_rt.h" 6 | 7 | Onet_engine::Onet_engine() : baseEngine("det3_relu.prototxt", 8 | "det3_relu.caffemodel", 9 | "data", 10 | "conv6-2", 11 | "prob1", 12 | "conv6-3" 13 | ) { 14 | }; 15 | 16 | Onet_engine::~Onet_engine() { 17 | shutdownProtobufLibrary(); 18 | } 19 | 20 | void Onet_engine::init(int row, int col) { 21 | IHostMemory *gieModelStream{nullptr}; 22 | const int max_batch_size = 1; 23 | //generate Tensorrt model 24 | caffeToGIEModel(prototxt, model, std::vector{OUTPUT_PROB_NAME, OUTPUT_LOCATION_NAME,OUTPUT_POINT_NAME}, max_batch_size, 25 | gieModelStream); 26 | 27 | } 28 | 29 | 30 | Onet::Onet(const Onet_engine &onet_engine) : BatchSize(1), 31 | INPUT_C(3), 32 | Engine(onet_engine.context->getEngine()) { 33 | 34 | Othreshold = 0.8; 35 | this->score_ = new pBox; 36 | this->location_ = new pBox; 37 | this->rgb = new pBox; 38 | this->points_ = new pBox; 39 | INPUT_W = 48; 40 | INPUT_H = 48; 41 | //calculate output shape 42 | this->score_->width = 1; 43 | this->score_->height = 1; 44 | this->score_->channel = 2; 45 | 46 | this->location_->width = 1; 47 | this->location_->height = 1; 48 | this->location_->channel = 4; 49 | 50 | this->points_->width = 1; 51 | this->points_->height = 1; 52 | this->points_->channel = 10; 53 | 54 | 55 | OUT_PROB_SIZE = this->score_->width * this->score_->height * this->score_->channel; 56 | OUT_LOCATION_SIZE = this->location_->width * this->location_->height * this->location_->channel; 57 | OUT_POINTS_SIZE = this->points_->width * this->points_->height * this->points_->channel; 58 | //allocate memory for outputs 59 | this->rgb->pdata = (float *) malloc(INPUT_C * INPUT_H * INPUT_W * sizeof(float)); 60 | this->score_->pdata = (float *) malloc(2 * sizeof(float)); 61 | this->location_->pdata = (float *) malloc(4 * sizeof(float)); 62 | this->points_->pdata = (float *) malloc(10 * sizeof(float)); 63 | 64 | assert(Engine.getNbBindings() == 4); 65 | inputIndex = Engine.getBindingIndex(onet_engine.INPUT_BLOB_NAME); 66 | outputProb = Engine.getBindingIndex(onet_engine.OUTPUT_PROB_NAME); 67 | outputLocation = Engine.getBindingIndex(onet_engine.OUTPUT_LOCATION_NAME); 68 | outputPoints = Engine.getBindingIndex(onet_engine.OUTPUT_POINT_NAME); 69 | 70 | //creat GPU buffers and stream 71 | CHECK(cudaMalloc(&buffers[inputIndex], BatchSize * INPUT_C * INPUT_H * INPUT_W * sizeof(float))); 72 | CHECK(cudaMalloc(&buffers[outputProb], BatchSize * OUT_PROB_SIZE * sizeof(float))); 73 | CHECK(cudaMalloc(&buffers[outputLocation], BatchSize * OUT_LOCATION_SIZE * sizeof(float))); 74 | CHECK(cudaMalloc(&buffers[outputPoints], BatchSize * OUT_POINTS_SIZE * sizeof(float))); 75 | CHECK(cudaStreamCreate(&stream)); 76 | } 77 | 78 | Onet::~Onet() { 79 | 80 | delete (score_); 81 | delete (location_); 82 | cudaStreamDestroy(stream); 83 | CHECK(cudaFree(buffers[inputIndex])); 84 | CHECK(cudaFree(buffers[outputProb])); 85 | CHECK(cudaFree(buffers[outputLocation])); 86 | CHECK(cudaFree(buffers[outputPoints])); 87 | } 88 | 89 | void Onet::run(Mat &image, const Onet_engine &onet_engine) { 90 | 91 | 92 | //DMA the input to the GPU ,execute the batch asynchronously and DMA it back; 93 | image2Matrix(image, this->rgb); 94 | CHECK(cudaMemcpyAsync(buffers[inputIndex], this->rgb->pdata, 95 | BatchSize * INPUT_C * INPUT_H * INPUT_W * sizeof(float), 96 | cudaMemcpyHostToDevice, stream)); 97 | onet_engine.context->enqueue(BatchSize, buffers, stream, nullptr); 98 | CHECK(cudaMemcpyAsync(this->location_->pdata, buffers[outputLocation], BatchSize * OUT_LOCATION_SIZE* sizeof(float), 99 | cudaMemcpyDeviceToHost, stream)); 100 | CHECK(cudaMemcpyAsync(this->score_->pdata, buffers[outputProb], BatchSize * OUT_PROB_SIZE* sizeof(float), 101 | cudaMemcpyDeviceToHost, stream)); 102 | CHECK(cudaMemcpyAsync(this->points_->pdata, buffers[outputPoints], BatchSize * OUT_POINTS_SIZE* sizeof(float), 103 | cudaMemcpyDeviceToHost, stream)); 104 | cudaStreamSynchronize(stream); 105 | 106 | } 107 | -------------------------------------------------------------------------------- /src/onet_rt.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by zhou on 18-10-2. 3 | // 4 | 5 | #ifndef MAIN_ONET_RT_H 6 | #define MAIN_ONET_RT_H 7 | #include "baseEngine.h" 8 | #include "network.h" 9 | 10 | 11 | class Onet_engine : public baseEngine { 12 | 13 | public: 14 | Onet_engine(); 15 | ~Onet_engine(); 16 | void init(int row, int col); 17 | friend class Onet; 18 | 19 | }; 20 | 21 | class Onet { 22 | public: 23 | Onet(const Onet_engine &onet_engine); 24 | ~Onet(); 25 | void run(Mat &image, const Onet_engine &engine); 26 | mydataFmt Othreshold; 27 | cudaStream_t stream; 28 | struct pBox *location_; 29 | struct pBox *score_; 30 | struct pBox *points_; 31 | struct pBox *rgb; 32 | private: 33 | const int BatchSize; 34 | const int INPUT_C; 35 | const ICudaEngine &Engine; 36 | //must be computed at runtime 37 | int INPUT_H; 38 | int INPUT_W; 39 | int OUT_PROB_SIZE; 40 | int OUT_LOCATION_SIZE; 41 | int OUT_POINTS_SIZE; 42 | int inputIndex,outputProb,outputLocation,outputPoints; 43 | void *buffers[4]; 44 | 45 | }; 46 | #endif //MAIN_ONET_RT_H 47 | -------------------------------------------------------------------------------- /src/pBox.h: -------------------------------------------------------------------------------- 1 | #ifndef PBOX_H 2 | #define PBOX_H 3 | #include 4 | #include 5 | 6 | using namespace std; 7 | #define mydataFmt float 8 | 9 | 10 | struct pBox 11 | { 12 | mydataFmt *pdata; 13 | int width; 14 | int height; 15 | int channel; 16 | }; 17 | struct Bbox 18 | { 19 | float score; 20 | int x1; 21 | int y1; 22 | int x2; 23 | int y2; 24 | float area; 25 | bool exist; 26 | mydataFmt ppoint[10]; 27 | mydataFmt regreCoord[4]; 28 | }; 29 | 30 | struct orderScore 31 | { 32 | mydataFmt score; 33 | int oriOrder; 34 | }; 35 | #endif -------------------------------------------------------------------------------- /src/pnet_rt.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by zhou on 18-4-30. 3 | // 4 | #include "pnet_rt.h" 5 | #include 6 | 7 | // stuff we know about the network and the caffe input/output blobs 8 | Pnet_engine::Pnet_engine() : baseEngine("det1_relu.prototxt", 9 | "det1_relu.caffemodel", 10 | "data", 11 | "conv4-2", 12 | "prob1") { 13 | }; 14 | 15 | Pnet_engine::~Pnet_engine() { 16 | shutdownProtobufLibrary(); 17 | } 18 | 19 | void Pnet_engine::init(int row, int col) { 20 | 21 | //modifiy the input shape of prototxt, write to temp.prototxt 22 | int first_spce = 16, second_space = 4; 23 | fstream protofile; 24 | protofile.open(prototxt, ios::in); 25 | std::stringstream buffer; 26 | buffer << protofile.rdbuf(); 27 | std::string contents(buffer.str()); 28 | string::size_type position_h, position_w; 29 | position_h = contents.find("dim"); 30 | while (isdigit(contents[position_h + first_spce])) { 31 | contents.erase(position_h + first_spce, 1); 32 | } 33 | contents.insert(position_h + first_spce, to_string(row)); 34 | position_w = contents.find("dim", position_h + first_spce); 35 | while (isdigit(contents[position_w + second_space])) { 36 | contents.erase(position_w + second_space, 1); 37 | } 38 | contents.insert(position_w + second_space, to_string(col)); 39 | protofile.close(); 40 | protofile.open("temp.prototxt", ios::out); 41 | protofile.write(contents.c_str(), contents.size()); 42 | protofile.close(); 43 | IHostMemory *gieModelStream{nullptr}; 44 | //generate Tensorrt model 45 | caffeToGIEModel("temp.prototxt", model, std::vector{OUTPUT_PROB_NAME, OUTPUT_LOCATION_NAME}, 1, 46 | gieModelStream); 47 | 48 | } 49 | 50 | 51 | Pnet::Pnet(int row, int col, const Pnet_engine &pnet_engine) : BatchSize(1), 52 | INPUT_C(3), Engine(pnet_engine.context->getEngine()) { 53 | Pthreshold = 0.6; 54 | nms_threshold = 0.5; 55 | this->score_ = new pBox; 56 | this->location_ = new pBox; 57 | this->rgb = new pBox; 58 | INPUT_W = col; 59 | INPUT_H = row; 60 | //calculate output shape 61 | this->score_->width = int(ceil((INPUT_W - 2) / 2.) - 4); 62 | this->score_->height = int(ceil((INPUT_H - 2) / 2.) - 4); 63 | this->score_->channel = 2; 64 | 65 | this->location_->width = int(ceil((INPUT_W - 2) / 2.) - 4); 66 | this->location_->height = int(ceil((INPUT_H - 2) / 2.) - 4); 67 | this->location_->channel = 4; 68 | 69 | OUT_PROB_SIZE = this->score_->width * this->score_->height * this->score_->channel; 70 | OUT_LOCATION_SIZE = this->location_->width * this->location_->height * this->location_->channel; 71 | //allocate memory for outputs 72 | this->rgb->pdata = (float *) malloc(INPUT_C * INPUT_H * INPUT_W * sizeof(float)); 73 | this->score_->pdata = (float *) malloc(OUT_PROB_SIZE * sizeof(float)); 74 | this->location_->pdata = (float *) malloc(OUT_LOCATION_SIZE * sizeof(float)); 75 | 76 | assert(Engine.getNbBindings() == 3); 77 | inputIndex = Engine.getBindingIndex(pnet_engine.INPUT_BLOB_NAME), 78 | outputProb = Engine.getBindingIndex(pnet_engine.OUTPUT_PROB_NAME), 79 | outputLocation = Engine.getBindingIndex(pnet_engine.OUTPUT_LOCATION_NAME); 80 | 81 | //creat GPU buffers and stream 82 | CHECK(cudaMalloc(&buffers[inputIndex], BatchSize * INPUT_C * INPUT_H * INPUT_W * sizeof(float))); 83 | CHECK(cudaMalloc(&buffers[outputProb], BatchSize * OUT_PROB_SIZE * sizeof(float))); 84 | CHECK(cudaMalloc(&buffers[outputLocation], BatchSize * OUT_LOCATION_SIZE * sizeof(float))); 85 | CHECK(cudaStreamCreate(&stream)); 86 | } 87 | 88 | Pnet::~Pnet() { 89 | 90 | delete (score_); 91 | delete (location_); 92 | 93 | cudaStreamDestroy(stream); 94 | CHECK(cudaFree(buffers[inputIndex])); 95 | CHECK(cudaFree(buffers[outputProb])); 96 | CHECK(cudaFree(buffers[outputLocation])); 97 | } 98 | 99 | void Pnet::run(Mat &image, float scale, const Pnet_engine &pnet_engine) { 100 | 101 | 102 | //DMA the input to the GPU ,execute the batch asynchronously and DMA it back; 103 | image2Matrix(image, this->rgb); 104 | CHECK(cudaMemcpyAsync(buffers[inputIndex], this->rgb->pdata, 105 | BatchSize * INPUT_C * INPUT_H * INPUT_W * sizeof(float), 106 | cudaMemcpyHostToDevice, stream)); 107 | pnet_engine.context->enqueue(BatchSize, buffers, stream, nullptr); 108 | CHECK(cudaMemcpyAsync(this->score_->pdata, buffers[outputProb], BatchSize * OUT_PROB_SIZE * sizeof(float), 109 | cudaMemcpyDeviceToHost, stream)); 110 | CHECK(cudaMemcpyAsync(this->location_->pdata, buffers[outputLocation], 111 | BatchSize * OUT_LOCATION_SIZE * sizeof(float), cudaMemcpyDeviceToHost, stream)); 112 | cudaStreamSynchronize(stream); 113 | generateBbox(this->score_, this->location_, scale); 114 | 115 | } 116 | 117 | void Pnet::generateBbox(const struct pBox *score, const struct pBox *location, mydataFmt scale) { 118 | //for pooling 119 | int stride = 2; 120 | int cellsize = 12; 121 | int count = 0; 122 | //score p 123 | mydataFmt *p = score->pdata + score->width * score->height; 124 | mydataFmt *plocal = location->pdata; 125 | struct Bbox bbox; 126 | struct orderScore order; 127 | for (int row = 0; row < score->height; row++) { 128 | for (int col = 0; col < score->width; col++) { 129 | if (*p > Pthreshold) { 130 | bbox.score = *p; 131 | order.score = *p; 132 | order.oriOrder = count; 133 | bbox.x1 = round((stride * row + 1) / scale); 134 | bbox.y1 = round((stride * col + 1) / scale); 135 | bbox.x2 = round((stride * row + 1 + cellsize) / scale); 136 | bbox.y2 = round((stride * col + 1 + cellsize) / scale); 137 | bbox.exist = true; 138 | bbox.area = (bbox.x2 - bbox.x1) * (bbox.y2 - bbox.y1); 139 | for (int channel = 0; channel < 4; channel++) 140 | bbox.regreCoord[channel] = *(plocal + channel * location->width * location->height); 141 | boundingBox_.push_back(bbox); 142 | bboxScore_.push_back(order); 143 | count++; 144 | } 145 | p++; 146 | plocal++; 147 | } 148 | } 149 | 150 | } -------------------------------------------------------------------------------- /src/pnet_rt.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by zhou on 18-4-30. 3 | // 4 | 5 | #ifndef MAIN_PNET_RT_H 6 | #define MAIN_PNET_RT_H 7 | 8 | #include "network.h" 9 | #include "common.h" 10 | #include "baseEngine.h" 11 | #endif //MAIN_PNET_RT_H 12 | using namespace nvinfer1; 13 | using namespace nvcaffeparser1; 14 | 15 | class Pnet_engine:public baseEngine 16 | { 17 | 18 | public: 19 | Pnet_engine(); 20 | ~Pnet_engine(); 21 | void init(int row,int col); 22 | friend class Pnet; 23 | 24 | }; 25 | 26 | 27 | 28 | class Pnet 29 | { 30 | public: 31 | Pnet(int row,int col,const Pnet_engine& pnet_engine); 32 | ~Pnet(); 33 | void run(Mat &image, float scale,const Pnet_engine& engine); 34 | float nms_threshold; 35 | mydataFmt Pthreshold; 36 | cudaStream_t stream; 37 | 38 | vector boundingBox_; 39 | vector bboxScore_; 40 | private: 41 | 42 | const int BatchSize ; 43 | const int INPUT_C ; 44 | const ICudaEngine &Engine; 45 | //must be computed at runtime 46 | int INPUT_H ; 47 | int INPUT_W ; 48 | int OUT_PROB_SIZE; 49 | int OUT_LOCATION_SIZE; 50 | int inputIndex, 51 | outputProb, 52 | outputLocation; 53 | void *buffers[3]; 54 | struct pBox *location_; 55 | struct pBox *score_; 56 | struct pBox *rgb; 57 | 58 | void generateBbox(const struct pBox *score, const struct pBox *location, mydataFmt scale); 59 | }; 60 | 61 | -------------------------------------------------------------------------------- /src/rnet_rt.cpp: -------------------------------------------------------------------------------- 1 | 2 | //Created by zhou on 18-5-4. 3 | 4 | #include "rnet_rt.h" 5 | 6 | 7 | Rnet_engine::Rnet_engine() : baseEngine("det2_relu.prototxt", 8 | "det2_relu.caffemodel", 9 | "data", 10 | "conv5-2", 11 | "prob1" 12 | 13 | ) { 14 | }; 15 | 16 | Rnet_engine::~Rnet_engine() { 17 | shutdownProtobufLibrary(); 18 | } 19 | 20 | void Rnet_engine::init(int row, int col) { 21 | 22 | IHostMemory *gieModelStream{nullptr}; 23 | const int max_batch_size = 1; 24 | //generate Tensorrt model 25 | caffeToGIEModel(prototxt, model, std::vector{OUTPUT_PROB_NAME, OUTPUT_LOCATION_NAME}, max_batch_size, 26 | gieModelStream); 27 | 28 | } 29 | 30 | 31 | Rnet::Rnet(const Rnet_engine &rnet_engine) : BatchSize(1), 32 | INPUT_C(3), 33 | Engine(rnet_engine.context->getEngine()) { 34 | 35 | Rthreshold = 0.7; 36 | this->score_ = new pBox; 37 | this->location_ = new pBox; 38 | this->rgb = new pBox; 39 | INPUT_W = 24; 40 | INPUT_H = 24; 41 | //calculate output shape 42 | this->score_->width = 1; 43 | this->score_->height = 1; 44 | this->score_->channel = 2; 45 | 46 | this->location_->width = 1; 47 | this->location_->height = 1; 48 | this->location_->channel= 4; 49 | 50 | OUT_PROB_SIZE = this->score_->width * this->score_->height * this->score_->channel; 51 | OUT_LOCATION_SIZE = this->location_->width * this->location_->height * this->location_->channel; 52 | //allocate memory for outputs 53 | this->rgb->pdata = (float *) malloc(INPUT_C * INPUT_H * INPUT_W * sizeof(float)); 54 | this->score_->pdata = (float *) malloc(2 * sizeof(float)); 55 | this->location_->pdata = (float *) malloc(4 * sizeof(float)); 56 | 57 | assert(Engine.getNbBindings() == 3); 58 | inputIndex = Engine.getBindingIndex(rnet_engine.INPUT_BLOB_NAME); 59 | outputProb = Engine.getBindingIndex(rnet_engine.OUTPUT_PROB_NAME); 60 | outputLocation = Engine.getBindingIndex(rnet_engine.OUTPUT_LOCATION_NAME); 61 | //creat GPU buffers and stream 62 | CHECK(cudaMalloc(&buffers[inputIndex], BatchSize * INPUT_C * INPUT_H * INPUT_W * sizeof(float))); 63 | CHECK(cudaMalloc(&buffers[outputProb], BatchSize * OUT_PROB_SIZE * sizeof(float))); 64 | CHECK(cudaMalloc(&buffers[outputLocation], BatchSize * OUT_LOCATION_SIZE * sizeof(float))); 65 | CHECK(cudaStreamCreate(&stream)); 66 | } 67 | 68 | Rnet::~Rnet() { 69 | delete (score_); 70 | delete (location_); 71 | cudaStreamDestroy(stream); 72 | CHECK(cudaFree(buffers[inputIndex])); 73 | CHECK(cudaFree(buffers[outputProb])); 74 | CHECK(cudaFree(buffers[outputLocation])); 75 | } 76 | 77 | void Rnet::run(Mat &image, const Rnet_engine &rnet_engine) { 78 | //DMA the input to the GPU ,execute the batch asynchronously and DMA it back; 79 | image2Matrix(image, this->rgb); 80 | CHECK(cudaMemcpyAsync(buffers[inputIndex], this->rgb->pdata, 81 | BatchSize * INPUT_C * INPUT_H * INPUT_W * sizeof(float), 82 | cudaMemcpyHostToDevice, stream)); 83 | rnet_engine.context->enqueue(BatchSize, buffers, stream, nullptr); 84 | CHECK(cudaMemcpyAsync(this->location_->pdata, buffers[outputLocation], BatchSize * OUT_LOCATION_SIZE* sizeof(float), 85 | cudaMemcpyDeviceToHost, stream)); 86 | CHECK(cudaMemcpyAsync(this->score_->pdata, buffers[outputProb], BatchSize * OUT_PROB_SIZE* sizeof(float), 87 | cudaMemcpyDeviceToHost, stream)); 88 | cudaStreamSynchronize(stream); 89 | 90 | } 91 | -------------------------------------------------------------------------------- /src/rnet_rt.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by zhou on 18-5-4. 3 | // 4 | 5 | #ifndef MAIN_RNET_RT_H 6 | #define MAIN_RNET_RT_H 7 | 8 | #include "baseEngine.h" 9 | #include "network.h" 10 | 11 | 12 | class Rnet_engine : public baseEngine { 13 | 14 | public: 15 | Rnet_engine(); 16 | ~Rnet_engine(); 17 | void init(int row, int col); 18 | friend class Rnet; 19 | 20 | }; 21 | 22 | class Rnet { 23 | public: 24 | Rnet(const Rnet_engine &rnet_engine); 25 | ~Rnet(); 26 | void run(Mat &image, const Rnet_engine &engine); 27 | mydataFmt Rthreshold; 28 | cudaStream_t stream; 29 | struct pBox *location_; 30 | struct pBox *score_; 31 | struct pBox *rgb; 32 | private: 33 | const int BatchSize; 34 | const int INPUT_C; 35 | const ICudaEngine &Engine; 36 | //must be computed at runtime 37 | int INPUT_H; 38 | int INPUT_W; 39 | int OUT_PROB_SIZE; 40 | int OUT_LOCATION_SIZE; 41 | int inputIndex,outputProb,outputLocation; 42 | void *buffers[3]; 43 | 44 | }; 45 | 46 | 47 | #endif //MAIN_RNET_RT_H 48 | -------------------------------------------------------------------------------- /temp.prototxt: -------------------------------------------------------------------------------- 1 | name: "PNet" 2 | layer 3 | { 4 | name: "data" 5 | type: "Input" 6 | top: "data" 7 | input_param{shape:{dim:1 dim:3 dim:13 dim:17}} 8 | } 9 | 10 | layer { 11 | name: "conv1" 12 | type: "Convolution" 13 | bottom: "data" 14 | top: "conv1" 15 | param { 16 | lr_mult: 1 17 | } 18 | param { 19 | lr_mult: 2 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 | } 31 | } 32 | } 33 | layer { 34 | name: "ReLU1" 35 | type: "ReLU" 36 | bottom: "conv1" 37 | top: "conv1_1" 38 | } 39 | 40 | layer { 41 | name: "scale1_1" 42 | bottom: "conv1" 43 | top: "conv1_2" 44 | type: "Scale" 45 | scale_param { 46 | axis: 1 47 | bias_term:false 48 | } 49 | } 50 | layer { 51 | name: "ReLU1_2" 52 | type: "ReLU" 53 | bottom: "conv1_2" 54 | top: "conv1_2" 55 | } 56 | layer { 57 | name: "scale1_2" 58 | bottom: "conv1_2" 59 | top: "conv1_2" 60 | type: "Scale" 61 | scale_param { 62 | axis: 1 63 | bias_term:false 64 | 65 | } 66 | } 67 | layer { 68 | name: "eltwise-sum1" 69 | type: "Eltwise" 70 | bottom: "conv1_1" 71 | bottom: "conv1_2" 72 | top: "conv1_3" 73 | eltwise_param { operation: SUM } 74 | } 75 | layer { 76 | name: "pool1" 77 | type: "Pooling" 78 | bottom: "conv1_3" 79 | top: "pool1" 80 | pooling_param { 81 | pool: MAX 82 | kernel_size: 2 83 | stride: 2 84 | } 85 | } 86 | 87 | layer { 88 | name: "conv2" 89 | type: "Convolution" 90 | bottom: "pool1" 91 | top: "conv2" 92 | param { 93 | lr_mult: 1 94 | } 95 | param { 96 | lr_mult: 2 97 | } 98 | convolution_param { 99 | num_output: 16 100 | kernel_size: 3 101 | stride: 1 102 | weight_filler { 103 | type: "xavier" 104 | } 105 | bias_filler { 106 | type: "constant" 107 | } 108 | } 109 | } 110 | layer { 111 | name: "ReLU2" 112 | type: "ReLU" 113 | bottom: "conv2" 114 | top: "conv2_1" 115 | } 116 | 117 | layer { 118 | name: "scale2_1" 119 | bottom: "conv2" 120 | top: "conv2_2" 121 | type: "Scale" 122 | scale_param { 123 | axis: 1 124 | bias_term:false 125 | 126 | } 127 | } 128 | layer { 129 | name: "ReLU2_2" 130 | type: "ReLU" 131 | bottom: "conv2_2" 132 | top: "conv2_2" 133 | } 134 | layer { 135 | name: "scale2_2" 136 | bottom: "conv2_2" 137 | top: "conv2_2" 138 | type: "Scale" 139 | scale_param { 140 | axis: 1 141 | bias_term:false 142 | } 143 | } 144 | layer { 145 | name: "eltwise-sum2" 146 | type: "Eltwise" 147 | bottom: "conv2_1" 148 | bottom: "conv2_2" 149 | top: "conv2_3" 150 | eltwise_param { operation: SUM } 151 | } 152 | 153 | 154 | layer { 155 | name: "conv3" 156 | type: "Convolution" 157 | bottom: "conv2_3" 158 | top: "conv3" 159 | param { 160 | lr_mult: 1 161 | } 162 | param { 163 | lr_mult: 2 164 | } 165 | convolution_param { 166 | num_output: 32 167 | kernel_size: 3 168 | stride: 1 169 | weight_filler { 170 | type: "xavier" 171 | } 172 | bias_filler { 173 | type: "constant" 174 | } 175 | } 176 | } 177 | layer { 178 | name: "ReLU3" 179 | type: "ReLU" 180 | bottom: "conv3" 181 | top: "conv3_1" 182 | } 183 | layer { 184 | name: "scale3_1" 185 | bottom: "conv3" 186 | top: "conv3_2" 187 | type: "Scale" 188 | scale_param { 189 | axis: 1 190 | bias_term:false 191 | } 192 | } 193 | layer { 194 | name: "ReLU3_2" 195 | type: "ReLU" 196 | bottom: "conv3_2" 197 | top: "conv3_2" 198 | } 199 | layer { 200 | name: "scale3_2" 201 | bottom: "conv3_2" 202 | top: "conv3_2" 203 | type: "Scale" 204 | scale_param { 205 | axis: 1 206 | bias_term:false 207 | } 208 | } 209 | layer { 210 | name: "eltwise-sum3" 211 | type: "Eltwise" 212 | bottom: "conv3_1" 213 | bottom: "conv3_2" 214 | top: "conv3_3" 215 | eltwise_param { operation: SUM } 216 | } 217 | 218 | layer { 219 | name: "conv4-1" 220 | type: "Convolution" 221 | bottom: "conv3_3" 222 | top: "conv4-1" 223 | param { 224 | lr_mult: 1 225 | decay_mult: 1 226 | } 227 | param { 228 | lr_mult: 2 229 | } 230 | convolution_param { 231 | num_output: 2 232 | kernel_size: 1 233 | stride: 1 234 | weight_filler { 235 | type: "xavier" 236 | } 237 | bias_filler { 238 | type: "constant" 239 | } 240 | } 241 | } 242 | 243 | layer { 244 | name: "conv4-2" 245 | type: "Convolution" 246 | bottom: "conv3_3" 247 | top: "conv4-2" 248 | param { 249 | lr_mult: 1 250 | } 251 | param { 252 | lr_mult: 2 253 | } 254 | convolution_param { 255 | num_output: 4 256 | kernel_size: 1 257 | stride: 1 258 | weight_filler { 259 | type: "xavier" 260 | } 261 | bias_filler { 262 | type: "constant" 263 | } 264 | } 265 | } 266 | layer { 267 | name: "prob1" 268 | type: "Softmax" 269 | bottom: "conv4-1" 270 | top: "prob1" 271 | } --------------------------------------------------------------------------------