├── README.md ├── models ├── symbol_10_320_20L_5scales_v2_deploy.param ├── symbol_10_560_25L_8scales_v1_deploy.param ├── train_10_320_20L_5scales_v2_iter_1000000.bin └── train_10_560_25L_8scales_v1_iter_1400000.bin ├── src ├── LFFD.cpp └── LFFD.h └── test.cpp /README.md: -------------------------------------------------------------------------------- 1 | ## the C++ implemententation of LFFD with ncnn 2 | I have implemented the LFFD referring to the official python implementation 3 | the Inference time of LFFD with the input shape of 320x240 is about 20ms on the Qualcomm Snapdragon 632 CPU 4 | 5 | paper:[LFFD: A Light and Fast Face Detector for Edge Devices](https://arxiv.org/abs/1904.10633) 6 | 7 | official github: [LFFD](https://github.com/YonghaoHe/A-Light-and-Fast-Face-Detector-for-Edge-Devices) 8 | 9 | My MNN implementation [MNN](https://github.com/SyGoing/LFFD-MNN). 10 | 11 | My OpenVINO [implementation](https://github.com/SyGoing/LFFD-OpenVINO) 12 | ## some tips 13 | * You can set the input tensor shape smaller ,since you need to reduce the memory and accelerate the inference. 14 | * You can set the scale_num=8 to use another larger model. 15 | * I just test it on vs2019 PC and the result is correct compared to original implementation,you can use the code to another device such as android、RK3399、and so on. 16 | 17 | ## how to convert the original model to ncnn 18 | The original mxnet model has merged the preporcess(means and norms) and the detection output tensor has been sliced with the mxnet slice op in the symbol ,which caused convert failure. 19 | so,you need to remove these ops ,in that way you can convert the model to onnx/ncnn successfully.I will show you how to do that step by step, so when you train the model by yourself, 20 | you can convert to your own model to onnx , and do more things. 21 | 22 | * First ,follow the author's original github to build the devolopment environment. 23 | 24 | * Modify symbol_10_320_20L_5scales_v2.py (your_path/A-Light-and-Fast-Face-Detector-for-Edge-Devices\face_detection\symbol_farm) 25 | 26 | in function loss_branch,Note out(注释掉) the line 57(predict_score = mxnet.symbol.slice_axis(predict_score, axis=1, begin=0, end=1) 27 | 28 | in function get_net_symbol, Note out(注释掉)the line 99(data = (data - 127.5) / 127.5,preprocess). 29 | 30 | * Next,in this path , by doing "python symbol_10_320_20L_5scales_v2.py ",generate the symbol.json. symbol_10_560_25L_8scales_v1.py do the same thing . 31 | 32 | 33 | ## TODO(you can refer this implementation to do more) 34 | - [x] MNN demo finished 35 | - [x] openvino demo: mxnet model-->onnx-->openvino 36 | - [x] TensorRT demo: mxnet model --> onnx-->trt engine(coming soon) 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /models/symbol_10_320_20L_5scales_v2_deploy.param: -------------------------------------------------------------------------------- 1 | 7767517 2 | 109 125 3 | Input data 0 1 data 4 | Convolution conv1 1 1 data conv1 0=64 1=3 11=3 2=1 12=1 3=2 13=2 4=0 14=0 5=1 6=1728 5 | ReLU relu_conv1 1 1 conv1 relu_conv1 6 | Convolution conv2 1 1 relu_conv1 conv2 0=64 1=3 11=3 2=1 12=1 3=2 13=2 4=0 14=0 5=1 6=36864 7 | Split splitncnn_0 1 2 conv2 conv2_splitncnn_0 conv2_splitncnn_1 8 | ReLU relu_conv2 1 1 conv2_splitncnn_1 relu_conv2 9 | Convolution conv3 1 1 relu_conv2 conv3 0=64 1=3 11=3 2=1 12=1 3=1 13=1 4=1 14=1 5=1 6=36864 10 | ReLU relu_conv3 1 1 conv3 relu_conv3 11 | Convolution conv4 1 1 relu_conv3 conv4 0=64 1=3 11=3 2=1 12=1 3=1 13=1 4=1 14=1 5=1 6=36864 12 | BinaryOp _plus7 2 1 conv2_splitncnn_0 conv4 _plus7 0=0 13 | Split splitncnn_1 1 2 _plus7 _plus7_splitncnn_0 _plus7_splitncnn_1 14 | ReLU relu_conv4 1 1 _plus7_splitncnn_1 relu_conv4 15 | Convolution conv5 1 1 relu_conv4 conv5 0=64 1=3 11=3 2=1 12=1 3=1 13=1 4=1 14=1 5=1 6=36864 16 | ReLU relu_conv5 1 1 conv5 relu_conv5 17 | Convolution conv6 1 1 relu_conv5 conv6 0=64 1=3 11=3 2=1 12=1 3=1 13=1 4=1 14=1 5=1 6=36864 18 | BinaryOp _plus8 2 1 _plus7_splitncnn_0 conv6 _plus8 0=0 19 | Split splitncnn_2 1 2 _plus8 _plus8_splitncnn_0 _plus8_splitncnn_1 20 | ReLU relu_conv6 1 1 _plus8_splitncnn_1 relu_conv6 21 | Convolution conv7 1 1 relu_conv6 conv7 0=64 1=3 11=3 2=1 12=1 3=1 13=1 4=1 14=1 5=1 6=36864 22 | ReLU relu_conv7 1 1 conv7 relu_conv7 23 | Convolution conv8 1 1 relu_conv7 conv8 0=64 1=3 11=3 2=1 12=1 3=1 13=1 4=1 14=1 5=1 6=36864 24 | BinaryOp _plus9 2 1 _plus8_splitncnn_0 conv8 _plus9 0=0 25 | ReLU relu_conv8 1 1 _plus9 relu_conv8 26 | Split splitncnn_3 1 2 relu_conv8 relu_conv8_splitncnn_0 relu_conv8_splitncnn_1 27 | Convolution conv8_1 1 1 relu_conv8_splitncnn_1 conv8_1 0=128 1=1 11=1 2=1 12=1 3=1 13=1 4=0 14=0 5=1 6=8192 28 | ReLU relu_conv8_1 1 1 conv8_1 relu_conv8_1 29 | Split splitncnn_4 1 2 relu_conv8_1 relu_conv8_1_splitncnn_0 relu_conv8_1_splitncnn_1 30 | Convolution conv8_2_score 1 1 relu_conv8_1_splitncnn_1 conv8_2_score 0=128 1=1 11=1 2=1 12=1 3=1 13=1 4=0 14=0 5=1 6=16384 31 | ReLU relu_conv8_2_score 1 1 conv8_2_score relu_conv8_2_score 32 | Convolution conv8_3_score 1 1 relu_conv8_2_score conv8_3_score 0=2 1=1 11=1 2=1 12=1 3=1 13=1 4=0 14=0 5=1 6=256 33 | Softmax softmax0 1 1 conv8_3_score softmax0 0=0 34 | Convolution conv8_2_bbox 1 1 relu_conv8_1_splitncnn_0 conv8_2_bbox 0=128 1=1 11=1 2=1 12=1 3=1 13=1 4=0 14=0 5=1 6=16384 35 | ReLU relu_conv8_2_bbox 1 1 conv8_2_bbox relu_conv8_2_bbox 36 | Convolution conv8_3_bbox 1 1 relu_conv8_2_bbox conv8_3_bbox 0=4 1=1 11=1 2=1 12=1 3=1 13=1 4=0 14=0 5=1 6=512 37 | Convolution conv9 1 1 relu_conv8_splitncnn_0 conv9 0=64 1=3 11=3 2=1 12=1 3=2 13=2 4=0 14=0 5=1 6=36864 38 | Split splitncnn_5 1 2 conv9 conv9_splitncnn_0 conv9_splitncnn_1 39 | ReLU relu_conv9 1 1 conv9_splitncnn_1 relu_conv9 40 | Convolution conv10 1 1 relu_conv9 conv10 0=64 1=3 11=3 2=1 12=1 3=1 13=1 4=1 14=1 5=1 6=36864 41 | ReLU relu_conv10 1 1 conv10 relu_conv10 42 | Convolution conv11 1 1 relu_conv10 conv11 0=64 1=3 11=3 2=1 12=1 3=1 13=1 4=1 14=1 5=1 6=36864 43 | BinaryOp _plus10 2 1 conv9_splitncnn_0 conv11 _plus10 0=0 44 | ReLU relu_conv11 1 1 _plus10 relu_conv11 45 | Split splitncnn_6 1 2 relu_conv11 relu_conv11_splitncnn_0 relu_conv11_splitncnn_1 46 | Convolution conv11_1 1 1 relu_conv11_splitncnn_1 conv11_1 0=128 1=1 11=1 2=1 12=1 3=1 13=1 4=0 14=0 5=1 6=8192 47 | ReLU relu_conv11_1 1 1 conv11_1 relu_conv11_1 48 | Split splitncnn_7 1 2 relu_conv11_1 relu_conv11_1_splitncnn_0 relu_conv11_1_splitncnn_1 49 | Convolution conv11_2_score 1 1 relu_conv11_1_splitncnn_1 conv11_2_score 0=128 1=1 11=1 2=1 12=1 3=1 13=1 4=0 14=0 5=1 6=16384 50 | ReLU relu_conv11_2_score 1 1 conv11_2_score relu_conv11_2_score 51 | Convolution conv11_3_score 1 1 relu_conv11_2_score conv11_3_score 0=2 1=1 11=1 2=1 12=1 3=1 13=1 4=0 14=0 5=1 6=256 52 | Softmax softmax1 1 1 conv11_3_score softmax1 0=0 53 | Convolution conv11_2_bbox 1 1 relu_conv11_1_splitncnn_0 conv11_2_bbox 0=128 1=1 11=1 2=1 12=1 3=1 13=1 4=0 14=0 5=1 6=16384 54 | ReLU relu_conv11_2_bbox 1 1 conv11_2_bbox relu_conv11_2_bbox 55 | Convolution conv11_3_bbox 1 1 relu_conv11_2_bbox conv11_3_bbox 0=4 1=1 11=1 2=1 12=1 3=1 13=1 4=0 14=0 5=1 6=512 56 | Convolution conv12 1 1 relu_conv11_splitncnn_0 conv12 0=64 1=3 11=3 2=1 12=1 3=2 13=2 4=0 14=0 5=1 6=36864 57 | Split splitncnn_8 1 2 conv12 conv12_splitncnn_0 conv12_splitncnn_1 58 | ReLU relu_conv12 1 1 conv12_splitncnn_1 relu_conv12 59 | Convolution conv13 1 1 relu_conv12 conv13 0=64 1=3 11=3 2=1 12=1 3=1 13=1 4=1 14=1 5=1 6=36864 60 | ReLU relu_conv13 1 1 conv13 relu_conv13 61 | Convolution conv14 1 1 relu_conv13 conv14 0=64 1=3 11=3 2=1 12=1 3=1 13=1 4=1 14=1 5=1 6=36864 62 | BinaryOp _plus11 2 1 conv12_splitncnn_0 conv14 _plus11 0=0 63 | ReLU relu_conv14 1 1 _plus11 relu_conv14 64 | Split splitncnn_9 1 2 relu_conv14 relu_conv14_splitncnn_0 relu_conv14_splitncnn_1 65 | Convolution conv14_1 1 1 relu_conv14_splitncnn_1 conv14_1 0=128 1=1 11=1 2=1 12=1 3=1 13=1 4=0 14=0 5=1 6=8192 66 | ReLU relu_conv14_1 1 1 conv14_1 relu_conv14_1 67 | Split splitncnn_10 1 2 relu_conv14_1 relu_conv14_1_splitncnn_0 relu_conv14_1_splitncnn_1 68 | Convolution conv14_2_score 1 1 relu_conv14_1_splitncnn_1 conv14_2_score 0=128 1=1 11=1 2=1 12=1 3=1 13=1 4=0 14=0 5=1 6=16384 69 | ReLU relu_conv14_2_score 1 1 conv14_2_score relu_conv14_2_score 70 | Convolution conv14_3_score 1 1 relu_conv14_2_score conv14_3_score 0=2 1=1 11=1 2=1 12=1 3=1 13=1 4=0 14=0 5=1 6=256 71 | Softmax softmax2 1 1 conv14_3_score softmax2 0=0 72 | Convolution conv14_2_bbox 1 1 relu_conv14_1_splitncnn_0 conv14_2_bbox 0=128 1=1 11=1 2=1 12=1 3=1 13=1 4=0 14=0 5=1 6=16384 73 | ReLU relu_conv14_2_bbox 1 1 conv14_2_bbox relu_conv14_2_bbox 74 | Convolution conv14_3_bbox 1 1 relu_conv14_2_bbox conv14_3_bbox 0=4 1=1 11=1 2=1 12=1 3=1 13=1 4=0 14=0 5=1 6=512 75 | Convolution conv15 1 1 relu_conv14_splitncnn_0 conv15 0=128 1=3 11=3 2=1 12=1 3=2 13=2 4=0 14=0 5=1 6=73728 76 | Split splitncnn_11 1 2 conv15 conv15_splitncnn_0 conv15_splitncnn_1 77 | ReLU relu_conv15 1 1 conv15_splitncnn_1 relu_conv15 78 | Convolution conv16 1 1 relu_conv15 conv16 0=128 1=3 11=3 2=1 12=1 3=1 13=1 4=1 14=1 5=1 6=147456 79 | ReLU relu_conv16 1 1 conv16 relu_conv16 80 | Convolution conv17 1 1 relu_conv16 conv17 0=128 1=3 11=3 2=1 12=1 3=1 13=1 4=1 14=1 5=1 6=147456 81 | BinaryOp _plus12 2 1 conv15_splitncnn_0 conv17 _plus12 0=0 82 | ReLU relu_conv17 1 1 _plus12 relu_conv17 83 | Split splitncnn_12 1 2 relu_conv17 relu_conv17_splitncnn_0 relu_conv17_splitncnn_1 84 | Convolution conv17_1 1 1 relu_conv17_splitncnn_1 conv17_1 0=128 1=1 11=1 2=1 12=1 3=1 13=1 4=0 14=0 5=1 6=16384 85 | ReLU relu_conv17_1 1 1 conv17_1 relu_conv17_1 86 | Split splitncnn_13 1 2 relu_conv17_1 relu_conv17_1_splitncnn_0 relu_conv17_1_splitncnn_1 87 | Convolution conv17_2_score 1 1 relu_conv17_1_splitncnn_1 conv17_2_score 0=128 1=1 11=1 2=1 12=1 3=1 13=1 4=0 14=0 5=1 6=16384 88 | ReLU relu_conv17_2_score 1 1 conv17_2_score relu_conv17_2_score 89 | Convolution conv17_3_score 1 1 relu_conv17_2_score conv17_3_score 0=2 1=1 11=1 2=1 12=1 3=1 13=1 4=0 14=0 5=1 6=256 90 | Softmax softmax3 1 1 conv17_3_score softmax3 0=0 91 | Convolution conv17_2_bbox 1 1 relu_conv17_1_splitncnn_0 conv17_2_bbox 0=128 1=1 11=1 2=1 12=1 3=1 13=1 4=0 14=0 5=1 6=16384 92 | ReLU relu_conv17_2_bbox 1 1 conv17_2_bbox relu_conv17_2_bbox 93 | Convolution conv17_3_bbox 1 1 relu_conv17_2_bbox conv17_3_bbox 0=4 1=1 11=1 2=1 12=1 3=1 13=1 4=0 14=0 5=1 6=512 94 | Convolution conv18 1 1 relu_conv17_splitncnn_0 conv18 0=128 1=3 11=3 2=1 12=1 3=2 13=2 4=0 14=0 5=1 6=147456 95 | Split splitncnn_14 1 2 conv18 conv18_splitncnn_0 conv18_splitncnn_1 96 | ReLU relu_conv18 1 1 conv18_splitncnn_1 relu_conv18 97 | Convolution conv19 1 1 relu_conv18 conv19 0=128 1=3 11=3 2=1 12=1 3=1 13=1 4=1 14=1 5=1 6=147456 98 | ReLU relu_conv19 1 1 conv19 relu_conv19 99 | Convolution conv20 1 1 relu_conv19 conv20 0=128 1=3 11=3 2=1 12=1 3=1 13=1 4=1 14=1 5=1 6=147456 100 | BinaryOp _plus13 2 1 conv18_splitncnn_0 conv20 _plus13 0=0 101 | ReLU relu_conv20 1 1 _plus13 relu_conv20 102 | Convolution conv20_1 1 1 relu_conv20 conv20_1 0=128 1=1 11=1 2=1 12=1 3=1 13=1 4=0 14=0 5=1 6=16384 103 | ReLU relu_conv20_1 1 1 conv20_1 relu_conv20_1 104 | Split splitncnn_15 1 2 relu_conv20_1 relu_conv20_1_splitncnn_0 relu_conv20_1_splitncnn_1 105 | Convolution conv20_2_score 1 1 relu_conv20_1_splitncnn_1 conv20_2_score 0=128 1=1 11=1 2=1 12=1 3=1 13=1 4=0 14=0 5=1 6=16384 106 | ReLU relu_conv20_2_score 1 1 conv20_2_score relu_conv20_2_score 107 | Convolution conv20_3_score 1 1 relu_conv20_2_score conv20_3_score 0=2 1=1 11=1 2=1 12=1 3=1 13=1 4=0 14=0 5=1 6=256 108 | Softmax softmax4 1 1 conv20_3_score softmax4 0=0 109 | Convolution conv20_2_bbox 1 1 relu_conv20_1_splitncnn_0 conv20_2_bbox 0=128 1=1 11=1 2=1 12=1 3=1 13=1 4=0 14=0 5=1 6=16384 110 | ReLU relu_conv20_2_bbox 1 1 conv20_2_bbox relu_conv20_2_bbox 111 | Convolution conv20_3_bbox 1 1 relu_conv20_2_bbox conv20_3_bbox 0=4 1=1 11=1 2=1 12=1 3=1 13=1 4=0 14=0 5=1 6=512 112 | -------------------------------------------------------------------------------- /models/symbol_10_560_25L_8scales_v1_deploy.param: -------------------------------------------------------------------------------- 1 | 7767517 2 | 158 183 3 | Input data 0 1 data 4 | Convolution conv1 1 1 data conv1 0=64 1=3 11=3 3=2 13=2 4=0 14=0 5=1 6=1728 5 | ReLU relu_conv1 1 1 conv1 relu_conv1 6 | Convolution conv2 1 1 relu_conv1 conv2 0=64 1=3 11=3 3=2 13=2 4=0 14=0 5=1 6=36864 7 | Split splitncnn_0 1 2 conv2 conv2_splitncnn_0 conv2_splitncnn_1 8 | ReLU relu_conv2 1 1 conv2_splitncnn_1 relu_conv2 9 | Convolution conv3 1 1 relu_conv2 conv3 0=64 1=3 11=3 3=1 13=1 4=1 14=1 5=1 6=36864 10 | ReLU relu_conv3 1 1 conv3 relu_conv3 11 | Convolution conv4 1 1 relu_conv3 conv4 0=64 1=3 11=3 3=1 13=1 4=1 14=1 5=1 6=36864 12 | BinaryOp _plus10 2 1 conv2_splitncnn_0 conv4 _plus10 0=0 13 | Split splitncnn_1 1 2 _plus10 _plus10_splitncnn_0 _plus10_splitncnn_1 14 | ReLU relu_conv4 1 1 _plus10_splitncnn_1 relu_conv4 15 | Convolution conv5 1 1 relu_conv4 conv5 0=64 1=3 11=3 3=1 13=1 4=1 14=1 5=1 6=36864 16 | ReLU relu_conv5 1 1 conv5 relu_conv5 17 | Convolution conv6 1 1 relu_conv5 conv6 0=64 1=3 11=3 3=1 13=1 4=1 14=1 5=1 6=36864 18 | BinaryOp _plus11 2 1 _plus10_splitncnn_0 conv6 _plus11 0=0 19 | Split splitncnn_2 1 2 _plus11 _plus11_splitncnn_0 _plus11_splitncnn_1 20 | ReLU relu_conv6 1 1 _plus11_splitncnn_1 relu_conv6 21 | Convolution conv7 1 1 relu_conv6 conv7 0=64 1=3 11=3 3=1 13=1 4=1 14=1 5=1 6=36864 22 | ReLU relu_conv7 1 1 conv7 relu_conv7 23 | Convolution conv8 1 1 relu_conv7 conv8 0=64 1=3 11=3 3=1 13=1 4=1 14=1 5=1 6=36864 24 | BinaryOp _plus12 2 1 _plus11_splitncnn_0 conv8 _plus12 0=0 25 | Split splitncnn_3 1 2 _plus12 _plus12_splitncnn_0 _plus12_splitncnn_1 26 | ReLU relu_conv8 1 1 _plus12_splitncnn_1 relu_conv8 27 | Split splitncnn_4 1 2 relu_conv8 relu_conv8_splitncnn_0 relu_conv8_splitncnn_1 28 | Convolution conv8_1 1 1 relu_conv8_splitncnn_1 conv8_1 0=128 1=1 11=1 3=1 13=1 4=0 14=0 5=1 6=8192 29 | ReLU relu_conv8_1 1 1 conv8_1 relu_conv8_1 30 | Split splitncnn_5 1 2 relu_conv8_1 relu_conv8_1_splitncnn_0 relu_conv8_1_splitncnn_1 31 | Convolution conv8_2_score 1 1 relu_conv8_1_splitncnn_1 conv8_2_score 0=128 1=1 11=1 3=1 13=1 4=0 14=0 5=1 6=16384 32 | ReLU relu_conv8_2_score 1 1 conv8_2_score relu_conv8_2_score 33 | Convolution conv8_3_score 1 1 relu_conv8_2_score conv8_3_score 0=2 1=1 11=1 3=1 13=1 4=0 14=0 5=1 6=256 34 | Softmax softmax0 1 1 conv8_3_score softmax0 1=1 35 | Convolution conv8_2_bbox 1 1 relu_conv8_1_splitncnn_0 conv8_2_bbox 0=128 1=1 11=1 3=1 13=1 4=0 14=0 5=1 6=16384 36 | ReLU relu_conv8_2_bbox 1 1 conv8_2_bbox relu_conv8_2_bbox 37 | Convolution conv8_3_bbox 1 1 relu_conv8_2_bbox conv8_3_bbox 0=4 1=1 11=1 3=1 13=1 4=0 14=0 5=1 6=512 38 | Convolution conv9 1 1 relu_conv8_splitncnn_0 conv9 0=64 1=3 11=3 3=1 13=1 4=1 14=1 5=1 6=36864 39 | ReLU relu_conv9 1 1 conv9 relu_conv9 40 | Convolution conv10 1 1 relu_conv9 conv10 0=64 1=3 11=3 3=1 13=1 4=1 14=1 5=1 6=36864 41 | BinaryOp _plus13 2 1 _plus12_splitncnn_0 conv10 _plus13 0=0 42 | ReLU relu_conv10 1 1 _plus13 relu_conv10 43 | Split splitncnn_6 1 2 relu_conv10 relu_conv10_splitncnn_0 relu_conv10_splitncnn_1 44 | Convolution conv10_1 1 1 relu_conv10_splitncnn_1 conv10_1 0=128 1=1 11=1 3=1 13=1 4=0 14=0 5=1 6=8192 45 | ReLU relu_conv10_1 1 1 conv10_1 relu_conv10_1 46 | Split splitncnn_7 1 2 relu_conv10_1 relu_conv10_1_splitncnn_0 relu_conv10_1_splitncnn_1 47 | Convolution conv10_2_score 1 1 relu_conv10_1_splitncnn_1 conv10_2_score 0=128 1=1 11=1 3=1 13=1 4=0 14=0 5=1 6=16384 48 | ReLU relu_conv10_2_score 1 1 conv10_2_score relu_conv10_2_score 49 | Convolution conv10_3_score 1 1 relu_conv10_2_score conv10_3_score 0=2 1=1 11=1 3=1 13=1 4=0 14=0 5=1 6=256 50 | Softmax softmax1 1 1 conv10_3_score softmax1 1=1 51 | Convolution conv10_2_bbox 1 1 relu_conv10_1_splitncnn_0 conv10_2_bbox 0=128 1=1 11=1 3=1 13=1 4=0 14=0 5=1 6=16384 52 | ReLU relu_conv10_2_bbox 1 1 conv10_2_bbox relu_conv10_2_bbox 53 | Convolution conv10_3_bbox 1 1 relu_conv10_2_bbox conv10_3_bbox 0=4 1=1 11=1 3=1 13=1 4=0 14=0 5=1 6=512 54 | Convolution conv11 1 1 relu_conv10_splitncnn_0 conv11 0=64 1=3 11=3 3=2 13=2 4=0 14=0 5=1 6=36864 55 | Split splitncnn_8 1 2 conv11 conv11_splitncnn_0 conv11_splitncnn_1 56 | ReLU relu_conv11 1 1 conv11_splitncnn_1 relu_conv11 57 | Convolution conv12 1 1 relu_conv11 conv12 0=64 1=3 11=3 3=1 13=1 4=1 14=1 5=1 6=36864 58 | ReLU relu_conv12 1 1 conv12 relu_conv12 59 | Convolution conv13 1 1 relu_conv12 conv13 0=64 1=3 11=3 3=1 13=1 4=1 14=1 5=1 6=36864 60 | BinaryOp _plus14 2 1 conv11_splitncnn_0 conv13 _plus14 0=0 61 | Split splitncnn_9 1 2 _plus14 _plus14_splitncnn_0 _plus14_splitncnn_1 62 | ReLU relu_conv13 1 1 _plus14_splitncnn_1 relu_conv13 63 | Split splitncnn_10 1 2 relu_conv13 relu_conv13_splitncnn_0 relu_conv13_splitncnn_1 64 | Convolution conv13_1 1 1 relu_conv13_splitncnn_1 conv13_1 0=128 1=1 11=1 3=1 13=1 4=0 14=0 5=1 6=8192 65 | ReLU relu_conv13_1 1 1 conv13_1 relu_conv13_1 66 | Split splitncnn_11 1 2 relu_conv13_1 relu_conv13_1_splitncnn_0 relu_conv13_1_splitncnn_1 67 | Convolution conv13_2_score 1 1 relu_conv13_1_splitncnn_1 conv13_2_score 0=128 1=1 11=1 3=1 13=1 4=0 14=0 5=1 6=16384 68 | ReLU relu_conv13_2_score 1 1 conv13_2_score relu_conv13_2_score 69 | Convolution conv13_3_score 1 1 relu_conv13_2_score conv13_3_score 0=2 1=1 11=1 3=1 13=1 4=0 14=0 5=1 6=256 70 | Softmax softmax2 1 1 conv13_3_score softmax2 1=1 71 | Convolution conv13_2_bbox 1 1 relu_conv13_1_splitncnn_0 conv13_2_bbox 0=128 1=1 11=1 3=1 13=1 4=0 14=0 5=1 6=16384 72 | ReLU relu_conv13_2_bbox 1 1 conv13_2_bbox relu_conv13_2_bbox 73 | Convolution conv13_3_bbox 1 1 relu_conv13_2_bbox conv13_3_bbox 0=4 1=1 11=1 3=1 13=1 4=0 14=0 5=1 6=512 74 | Convolution conv14 1 1 relu_conv13_splitncnn_0 conv14 0=64 1=3 11=3 3=1 13=1 4=1 14=1 5=1 6=36864 75 | ReLU relu_conv14 1 1 conv14 relu_conv14 76 | Convolution conv15 1 1 relu_conv14 conv15 0=64 1=3 11=3 3=1 13=1 4=1 14=1 5=1 6=36864 77 | BinaryOp _plus15 2 1 _plus14_splitncnn_0 conv15 _plus15 0=0 78 | ReLU relu_conv15 1 1 _plus15 relu_conv15 79 | Split splitncnn_12 1 2 relu_conv15 relu_conv15_splitncnn_0 relu_conv15_splitncnn_1 80 | Convolution conv15_1 1 1 relu_conv15_splitncnn_1 conv15_1 0=128 1=1 11=1 3=1 13=1 4=0 14=0 5=1 6=8192 81 | ReLU relu_conv15_1 1 1 conv15_1 relu_conv15_1 82 | Split splitncnn_13 1 2 relu_conv15_1 relu_conv15_1_splitncnn_0 relu_conv15_1_splitncnn_1 83 | Convolution conv15_2_score 1 1 relu_conv15_1_splitncnn_1 conv15_2_score 0=128 1=1 11=1 3=1 13=1 4=0 14=0 5=1 6=16384 84 | ReLU relu_conv15_2_score 1 1 conv15_2_score relu_conv15_2_score 85 | Convolution conv15_3_score 1 1 relu_conv15_2_score conv15_3_score 0=2 1=1 11=1 3=1 13=1 4=0 14=0 5=1 6=256 86 | Softmax softmax3 1 1 conv15_3_score softmax3 1=1 87 | Convolution conv15_2_bbox 1 1 relu_conv15_1_splitncnn_0 conv15_2_bbox 0=128 1=1 11=1 3=1 13=1 4=0 14=0 5=1 6=16384 88 | ReLU relu_conv15_2_bbox 1 1 conv15_2_bbox relu_conv15_2_bbox 89 | Convolution conv15_3_bbox 1 1 relu_conv15_2_bbox conv15_3_bbox 0=4 1=1 11=1 3=1 13=1 4=0 14=0 5=1 6=512 90 | Convolution conv16 1 1 relu_conv15_splitncnn_0 conv16 0=128 1=3 11=3 3=2 13=2 4=0 14=0 5=1 6=73728 91 | Split splitncnn_14 1 2 conv16 conv16_splitncnn_0 conv16_splitncnn_1 92 | ReLU relu_conv16 1 1 conv16_splitncnn_1 relu_conv16 93 | Convolution conv17 1 1 relu_conv16 conv17 0=128 1=3 11=3 3=1 13=1 4=1 14=1 5=1 6=147456 94 | ReLU relu_conv17 1 1 conv17 relu_conv17 95 | Convolution conv18 1 1 relu_conv17 conv18 0=128 1=3 11=3 3=1 13=1 4=1 14=1 5=1 6=147456 96 | BinaryOp _plus16 2 1 conv16_splitncnn_0 conv18 _plus16 0=0 97 | ReLU relu_conv18 1 1 _plus16 relu_conv18 98 | Split splitncnn_15 1 2 relu_conv18 relu_conv18_splitncnn_0 relu_conv18_splitncnn_1 99 | Convolution conv18_1 1 1 relu_conv18_splitncnn_1 conv18_1 0=128 1=1 11=1 3=1 13=1 4=0 14=0 5=1 6=16384 100 | ReLU relu_conv18_1 1 1 conv18_1 relu_conv18_1 101 | Split splitncnn_16 1 2 relu_conv18_1 relu_conv18_1_splitncnn_0 relu_conv18_1_splitncnn_1 102 | Convolution conv18_2_score 1 1 relu_conv18_1_splitncnn_1 conv18_2_score 0=128 1=1 11=1 3=1 13=1 4=0 14=0 5=1 6=16384 103 | ReLU relu_conv18_2_score 1 1 conv18_2_score relu_conv18_2_score 104 | Convolution conv18_3_score 1 1 relu_conv18_2_score conv18_3_score 0=2 1=1 11=1 3=1 13=1 4=0 14=0 5=1 6=256 105 | Softmax softmax4 1 1 conv18_3_score softmax4 1=1 106 | Convolution conv18_2_bbox 1 1 relu_conv18_1_splitncnn_0 conv18_2_bbox 0=128 1=1 11=1 3=1 13=1 4=0 14=0 5=1 6=16384 107 | ReLU relu_conv18_2_bbox 1 1 conv18_2_bbox relu_conv18_2_bbox 108 | Convolution conv18_3_bbox 1 1 relu_conv18_2_bbox conv18_3_bbox 0=4 1=1 11=1 3=1 13=1 4=0 14=0 5=1 6=512 109 | Convolution conv19 1 1 relu_conv18_splitncnn_0 conv19 0=128 1=3 11=3 3=2 13=2 4=0 14=0 5=1 6=147456 110 | Split splitncnn_17 1 2 conv19 conv19_splitncnn_0 conv19_splitncnn_1 111 | ReLU relu_conv19 1 1 conv19_splitncnn_1 relu_conv19 112 | Convolution conv20 1 1 relu_conv19 conv20 0=128 1=3 11=3 3=1 13=1 4=1 14=1 5=1 6=147456 113 | ReLU relu_conv20 1 1 conv20 relu_conv20 114 | Convolution conv21 1 1 relu_conv20 conv21 0=128 1=3 11=3 3=1 13=1 4=1 14=1 5=1 6=147456 115 | BinaryOp _plus17 2 1 conv19_splitncnn_0 conv21 _plus17 0=0 116 | Split splitncnn_18 1 2 _plus17 _plus17_splitncnn_0 _plus17_splitncnn_1 117 | ReLU relu_conv21 1 1 _plus17_splitncnn_1 relu_conv21 118 | Split splitncnn_19 1 2 relu_conv21 relu_conv21_splitncnn_0 relu_conv21_splitncnn_1 119 | Convolution conv21_1 1 1 relu_conv21_splitncnn_1 conv21_1 0=128 1=1 11=1 3=1 13=1 4=0 14=0 5=1 6=16384 120 | ReLU relu_conv21_1 1 1 conv21_1 relu_conv21_1 121 | Split splitncnn_20 1 2 relu_conv21_1 relu_conv21_1_splitncnn_0 relu_conv21_1_splitncnn_1 122 | Convolution conv21_2_score 1 1 relu_conv21_1_splitncnn_1 conv21_2_score 0=128 1=1 11=1 3=1 13=1 4=0 14=0 5=1 6=16384 123 | ReLU relu_conv21_2_score 1 1 conv21_2_score relu_conv21_2_score 124 | Convolution conv21_3_score 1 1 relu_conv21_2_score conv21_3_score 0=2 1=1 11=1 3=1 13=1 4=0 14=0 5=1 6=256 125 | Softmax softmax5 1 1 conv21_3_score softmax5 1=1 126 | Convolution conv21_2_bbox 1 1 relu_conv21_1_splitncnn_0 conv21_2_bbox 0=128 1=1 11=1 3=1 13=1 4=0 14=0 5=1 6=16384 127 | ReLU relu_conv21_2_bbox 1 1 conv21_2_bbox relu_conv21_2_bbox 128 | Convolution conv21_3_bbox 1 1 relu_conv21_2_bbox conv21_3_bbox 0=4 1=1 11=1 3=1 13=1 4=0 14=0 5=1 6=512 129 | Convolution conv22 1 1 relu_conv21_splitncnn_0 conv22 0=128 1=3 11=3 3=1 13=1 4=1 14=1 5=1 6=147456 130 | ReLU relu_conv22 1 1 conv22 relu_conv22 131 | Convolution conv23 1 1 relu_conv22 conv23 0=128 1=3 11=3 3=1 13=1 4=1 14=1 5=1 6=147456 132 | BinaryOp _plus18 2 1 _plus17_splitncnn_0 conv23 _plus18 0=0 133 | Split splitncnn_21 1 2 _plus18 _plus18_splitncnn_0 _plus18_splitncnn_1 134 | ReLU relu_conv23 1 1 _plus18_splitncnn_1 relu_conv23 135 | Split splitncnn_22 1 2 relu_conv23 relu_conv23_splitncnn_0 relu_conv23_splitncnn_1 136 | Convolution conv23_1 1 1 relu_conv23_splitncnn_1 conv23_1 0=128 1=1 11=1 3=1 13=1 4=0 14=0 5=1 6=16384 137 | ReLU relu_conv23_1 1 1 conv23_1 relu_conv23_1 138 | Split splitncnn_23 1 2 relu_conv23_1 relu_conv23_1_splitncnn_0 relu_conv23_1_splitncnn_1 139 | Convolution conv23_2_score 1 1 relu_conv23_1_splitncnn_1 conv23_2_score 0=128 1=1 11=1 3=1 13=1 4=0 14=0 5=1 6=16384 140 | ReLU relu_conv23_2_score 1 1 conv23_2_score relu_conv23_2_score 141 | Convolution conv23_3_score 1 1 relu_conv23_2_score conv23_3_score 0=2 1=1 11=1 3=1 13=1 4=0 14=0 5=1 6=256 142 | Softmax softmax6 1 1 conv23_3_score softmax6 1=1 143 | Convolution conv23_2_bbox 1 1 relu_conv23_1_splitncnn_0 conv23_2_bbox 0=128 1=1 11=1 3=1 13=1 4=0 14=0 5=1 6=16384 144 | ReLU relu_conv23_2_bbox 1 1 conv23_2_bbox relu_conv23_2_bbox 145 | Convolution conv23_3_bbox 1 1 relu_conv23_2_bbox conv23_3_bbox 0=4 1=1 11=1 3=1 13=1 4=0 14=0 5=1 6=512 146 | Convolution conv24 1 1 relu_conv23_splitncnn_0 conv24 0=128 1=3 11=3 3=1 13=1 4=1 14=1 5=1 6=147456 147 | ReLU relu_conv24 1 1 conv24 relu_conv24 148 | Convolution conv25 1 1 relu_conv24 conv25 0=128 1=3 11=3 3=1 13=1 4=1 14=1 5=1 6=147456 149 | BinaryOp _plus19 2 1 _plus18_splitncnn_0 conv25 _plus19 0=0 150 | ReLU relu_conv25 1 1 _plus19 relu_conv25 151 | Convolution conv25_1 1 1 relu_conv25 conv25_1 0=128 1=1 11=1 3=1 13=1 4=0 14=0 5=1 6=16384 152 | ReLU relu_conv25_1 1 1 conv25_1 relu_conv25_1 153 | Split splitncnn_24 1 2 relu_conv25_1 relu_conv25_1_splitncnn_0 relu_conv25_1_splitncnn_1 154 | Convolution conv25_2_score 1 1 relu_conv25_1_splitncnn_1 conv25_2_score 0=128 1=1 11=1 3=1 13=1 4=0 14=0 5=1 6=16384 155 | ReLU relu_conv25_2_score 1 1 conv25_2_score relu_conv25_2_score 156 | Convolution conv25_3_score 1 1 relu_conv25_2_score conv25_3_score 0=2 1=1 11=1 3=1 13=1 4=0 14=0 5=1 6=256 157 | Softmax softmax7 1 1 conv25_3_score softmax7 1=1 158 | Convolution conv25_2_bbox 1 1 relu_conv25_1_splitncnn_0 conv25_2_bbox 0=128 1=1 11=1 3=1 13=1 4=0 14=0 5=1 6=16384 159 | ReLU relu_conv25_2_bbox 1 1 conv25_2_bbox relu_conv25_2_bbox 160 | Convolution conv25_3_bbox 1 1 relu_conv25_2_bbox conv25_3_bbox 0=4 1=1 11=1 3=1 13=1 4=0 14=0 5=1 6=512 161 | -------------------------------------------------------------------------------- /models/train_10_320_20L_5scales_v2_iter_1000000.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SyGoing/LFFD-with-ncnn/f636b1ddac049bad350e66e9452d40a38ed996ed/models/train_10_320_20L_5scales_v2_iter_1000000.bin -------------------------------------------------------------------------------- /models/train_10_560_25L_8scales_v1_iter_1400000.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SyGoing/LFFD-with-ncnn/f636b1ddac049bad350e66e9452d40a38ed996ed/models/train_10_560_25L_8scales_v1_iter_1400000.bin -------------------------------------------------------------------------------- /src/LFFD.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "LFFD.h" 3 | 4 | LFFD::LFFD(const std::string& model_path, int scale_num, int num_thread_) 5 | { 6 | num_output_scales = scale_num; 7 | num_thread = num_thread_; 8 | if (num_output_scales == 5) { 9 | param_file_name = model_path+ "/symbol_10_320_20L_5scales_v2_deploy.param"; 10 | bin_file_name = model_path+"/train_10_320_20L_5scales_v2_iter_1800000.bin"; 11 | receptive_field_list = { 20, 40, 80, 160, 320 }; 12 | receptive_field_stride = { 4, 8, 16, 32, 64 }; 13 | bbox_small_list = { 10, 20, 40, 80, 160 }; 14 | bbox_large_list = { 20, 40, 80, 160, 320 }; 15 | receptive_field_center_start = { 3, 7, 15, 31, 63 }; 16 | 17 | for (int i = 0; i < receptive_field_list.size(); i++) { 18 | constant.push_back(receptive_field_list[i] / 2); 19 | } 20 | 21 | output_blob_names = { "softmax0","conv8_3_bbox", 22 | "softmax1","conv11_3_bbox", 23 | "softmax2","conv14_3_bbox", 24 | "softmax3","conv17_3_bbox", 25 | "softmax4","conv20_3_bbox" }; 26 | 27 | } 28 | else if (num_output_scales == 8) { 29 | param_file_name = model_path+"/symbol_10_560_25L_8scales_v1_deploy.param"; 30 | bin_file_name = model_path+"/train_10_560_25L_8scales_v1_iter_1400000.bin"; 31 | receptive_field_list = { 15, 20, 40, 70, 110, 250, 400, 560 }; 32 | receptive_field_stride = { 4, 4, 8, 8, 16, 32, 32, 32 }; 33 | bbox_small_list = { 10, 15, 20, 40, 70, 110, 250, 400 }; 34 | bbox_large_list = { 15, 20, 40, 70, 110, 250, 400, 560 }; 35 | receptive_field_center_start = { 3, 3, 7, 7, 15, 31, 31, 31 }; 36 | 37 | for (int i = 0; i < receptive_field_list.size(); i++) { 38 | constant.push_back(receptive_field_list[i] / 2); 39 | } 40 | 41 | output_blob_names = { "softmax0","conv8_3_bbox", 42 | "softmax1","conv10_3_bbox", 43 | "softmax2","conv13_3_bbox", 44 | "softmax3","conv15_3_bbox", 45 | "softmax4","conv18_3_bbox", 46 | "softmax5","conv21_3_bbox", 47 | "softmax6","conv23_3_bbox", 48 | "softmax7","conv25_3_bbox" }; 49 | } 50 | 51 | lffd.load_param(param_file_name.data()); 52 | lffd.load_model(bin_file_name.data()); 53 | 54 | } 55 | 56 | LFFD::~LFFD() 57 | { 58 | lffd.clear(); 59 | } 60 | 61 | int LFFD::detect(ncnn::Mat& img, std::vector& face_list, int resize_h, int resize_w, 62 | float score_threshold, float nms_threshold, int top_k, std::vector skip_scale_branch_list) 63 | { 64 | 65 | if (img.empty()) { 66 | std::cout << "image is empty ,please check!" << std::endl; 67 | return -1; 68 | } 69 | 70 | image_h = img.h; 71 | image_w = img.w; 72 | 73 | ncnn::Mat in; 74 | ncnn::resize_bilinear(img,in,resize_w,resize_h); 75 | float ratio_w=(float)image_w/in.w; 76 | float ratio_h=(float)image_h/in.h; 77 | 78 | ncnn::Mat ncnn_img = in; 79 | ncnn_img.substract_mean_normalize(mean_vals, norm_vals); 80 | 81 | std::vector bbox_collection; 82 | ncnn::Extractor ex = lffd.create_extractor(); 83 | ex.set_num_threads(num_thread); 84 | ex.input("data", ncnn_img); 85 | 86 | for (int i = 0; i valid_input; 96 | get_topk_bbox(bbox_collection, valid_input, top_k); 97 | nms(valid_input, face_list, nms_threshold); 98 | 99 | for(int i=0;i h ? w : h; 111 | cenx=face_list[i].x1+w/2; 112 | ceny=face_list[i].y1+h/2; 113 | face_list[i].x1=cenx-maxSize/2>0? cenx - maxSize / 2:0; 114 | face_list[i].y1=ceny-maxSize/2>0? ceny - maxSize / 2:0; 115 | face_list[i].x2=cenx+maxSize/2>image_w? image_w-1: cenx + maxSize / 2; 116 | face_list[i].y2=ceny+maxSize/2> image_h? image_h-1: ceny + maxSize / 2; 117 | 118 | } 119 | return 0; 120 | } 121 | 122 | void LFFD::generateBBox(std::vector& bbox_collection, ncnn::Mat score_map, ncnn::Mat box_map, float score_threshold, int fea_w, int fea_h, int cols, int rows, int scale_id) 123 | { 124 | float* RF_center_Xs = new float[fea_w]; 125 | float* RF_center_Xs_mat = new float[fea_w * fea_h]; 126 | float* RF_center_Ys = new float[fea_h]; 127 | float* RF_center_Ys_mat = new float[fea_h * fea_w]; 128 | 129 | for (int x = 0; x < fea_w; x++) { 130 | RF_center_Xs[x] = receptive_field_center_start[scale_id] + receptive_field_stride[scale_id] * x; 131 | } 132 | for (int x = 0; x < fea_h; x++) { 133 | for (int y = 0; y < fea_w; y++) { 134 | RF_center_Xs_mat[x * fea_w + y] = RF_center_Xs[y]; 135 | } 136 | } 137 | 138 | for (int x = 0; x < fea_h; x++) { 139 | RF_center_Ys[x] = receptive_field_center_start[scale_id] + receptive_field_stride[scale_id] * x; 140 | for (int y = 0; y < fea_w; y++) { 141 | RF_center_Ys_mat[x * fea_w + y] = RF_center_Ys[x]; 142 | } 143 | } 144 | 145 | float* x_lt_mat = new float[fea_h * fea_w]; 146 | float* y_lt_mat = new float[fea_h * fea_w]; 147 | float* x_rb_mat = new float[fea_h * fea_w]; 148 | float* y_rb_mat = new float[fea_h * fea_w]; 149 | 150 | 151 | 152 | //x-left-top 153 | float mid_value = 0; 154 | for (int j = 0; j < fea_h * fea_w; j++) { 155 | mid_value = RF_center_Xs_mat[j] - box_map.channel(0)[j] * constant[scale_id]; 156 | x_lt_mat[j] = mid_value < 0 ? 0 : mid_value; 157 | } 158 | //y-left-top 159 | for (int j = 0; j < fea_h * fea_w; j++) { 160 | mid_value = RF_center_Ys_mat[j] - box_map.channel(1)[j] * constant[scale_id]; 161 | y_lt_mat[j] = mid_value < 0 ? 0 : mid_value; 162 | } 163 | //x-right-bottom 164 | for (int j = 0; j < fea_h * fea_w; j++) { 165 | mid_value = RF_center_Xs_mat[j] - box_map.channel(2)[j] * constant[scale_id]; 166 | x_rb_mat[j] = mid_value > cols - 1 ? cols - 1 : mid_value; 167 | } 168 | //y-right-bottom 169 | for (int j = 0; j < fea_h * fea_w; j++) { 170 | mid_value = RF_center_Ys_mat[j] - box_map.channel(3)[j] * constant[scale_id]; 171 | y_rb_mat[j] = mid_value > rows - 1 ? rows - 1 : mid_value; 172 | } 173 | 174 | for (int k = 0; k < fea_h * fea_w; k++) { 175 | if (score_map.channel(0)[k] > score_threshold) { 176 | FaceInfo faceinfo; 177 | faceinfo.x1 = x_lt_mat[k]; 178 | faceinfo.y1 = y_lt_mat[k]; 179 | faceinfo.x2 = x_rb_mat[k]; 180 | faceinfo.y2 = y_rb_mat[k]; 181 | faceinfo.score = score_map[k]; 182 | faceinfo.area = (faceinfo.x2 - faceinfo.x1) * (faceinfo.y2 - faceinfo.y1); 183 | bbox_collection.push_back(faceinfo); 184 | } 185 | } 186 | 187 | delete[] RF_center_Xs; RF_center_Xs = NULL; 188 | delete[] RF_center_Ys; RF_center_Ys = NULL; 189 | delete[] RF_center_Xs_mat; RF_center_Xs_mat = NULL; 190 | delete[] RF_center_Ys_mat; RF_center_Ys_mat = NULL; 191 | delete[] x_lt_mat; x_lt_mat = NULL; 192 | delete[] y_lt_mat; y_lt_mat = NULL; 193 | delete[] x_rb_mat; x_rb_mat = NULL; 194 | delete[] y_rb_mat; y_rb_mat = NULL; 195 | } 196 | 197 | void LFFD::get_topk_bbox(std::vector& input, std::vector& output, int top_k) 198 | { 199 | std::sort(input.begin(), input.end(), 200 | [](const FaceInfo& a, const FaceInfo& b) 201 | { 202 | return a.score > b.score; 203 | }); 204 | 205 | if (input.size() > top_k) { 206 | for (int k = 0; k < top_k; k++) { 207 | output.push_back(input[k]); 208 | } 209 | } 210 | else { 211 | output = input; 212 | } 213 | } 214 | 215 | void LFFD::nms(std::vector& input, std::vector& output, float threshold, int type) 216 | { 217 | if(input.empty()) 218 | return; 219 | 220 | std::sort(input.begin(), input.end(), 221 | [](const FaceInfo& a, const FaceInfo& b) 222 | { 223 | return a.score > b.score; 224 | }); 225 | 226 | int box_num = input.size(); 227 | 228 | std::vector merged(box_num, 0); 229 | 230 | for (int i = 0; i < box_num; i++) 231 | { 232 | if (merged[i]) 233 | continue; 234 | 235 | output.push_back(input[i]); 236 | 237 | float h0 = input[i].y2 - input[i].y1 + 1; 238 | float w0 = input[i].x2 - input[i].x1 + 1; 239 | 240 | float area0 = h0 * w0; 241 | 242 | 243 | for (int j = i + 1; j < box_num; j++) 244 | { 245 | if (merged[j]) 246 | continue; 247 | 248 | float inner_x0 = input[i].x1 > input[j].x1 ? input[i].x1 : input[j].x1;//std::max(input[i].x1, input[j].x1); 249 | float inner_y0 = input[i].y1 > input[j].y1 ? input[i].y1 : input[j].y1; 250 | 251 | float inner_x1 = input[i].x2 < input[j].x2 ? input[i].x2 : input[j].x2; //bug fixed ,sorry 252 | float inner_y1 = input[i].y2 < input[j].y2 ? input[i].y2 : input[j].y2; 253 | 254 | float inner_h = inner_y1 - inner_y0 + 1; 255 | float inner_w = inner_x1 - inner_x0 + 1; 256 | 257 | 258 | if (inner_h <= 0 || inner_w <= 0) 259 | continue; 260 | 261 | float inner_area = inner_h * inner_w; 262 | 263 | float h1 = input[j].y2 - input[j].y1 + 1; 264 | float w1 = input[j].x2 - input[j].x1 + 1; 265 | 266 | float area1 = h1 * w1; 267 | 268 | float score= inner_area/area1; 269 | 270 | if (score > threshold) 271 | merged[j] = 1; 272 | } 273 | 274 | } 275 | } 276 | -------------------------------------------------------------------------------- /src/LFFD.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "net.h" 3 | #include "gpu.h" 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #define NMS_UNION 1 10 | #define NMS_MIN 2 11 | 12 | typedef struct FaceInfo { 13 | float x1; 14 | float y1; 15 | float x2; 16 | float y2; 17 | float score; 18 | float area; 19 | 20 | float landmarks[10]; 21 | }; 22 | 23 | class LFFD { 24 | public: 25 | LFFD(const std::string& model_path, int scale_num, int num_thread_ ); 26 | ~LFFD(); 27 | 28 | int detect(ncnn::Mat& img, std::vector& face_lis,int resize_h,int resize_w, 29 | float score_threshold = 0.6, float nms_threshold = 0.4, int top_k = 10000, 30 | std::vector skip_scale_branch_list = {}); 31 | 32 | private: 33 | void generateBBox(std::vector& collection, ncnn::Mat score_map, ncnn::Mat box_map, float score_threshold, 34 | int fea_w, int fea_h, int cols, int rows, int scale_id); 35 | void get_topk_bbox(std::vector& input, std::vector& output, int topk); 36 | void nms(std::vector& input, std::vector& output, 37 | float threshold, int type = NMS_MIN); 38 | private: 39 | ncnn::Net lffd; 40 | 41 | int num_thread; 42 | int num_output_scales; 43 | int image_w; 44 | int image_h; 45 | 46 | std::string param_file_name; 47 | std::string bin_file_name; 48 | 49 | std::vector receptive_field_list; 50 | std::vector receptive_field_stride; 51 | std::vector bbox_small_list; 52 | std::vector bbox_large_list; 53 | std::vector receptive_field_center_start; 54 | std::vector constant; 55 | 56 | std::vector output_blob_names; 57 | 58 | const float mean_vals[3] = { 127.5, 127.5, 127.5 }; 59 | const float norm_vals[3] = { 0.0078125, 0.0078125, 0.0078125 }; 60 | }; 61 | -------------------------------------------------------------------------------- /test.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "LFFD.h" 3 | #include 4 | 5 | using namespace cv; 6 | 7 | int main(int argc, char** argv) { 8 | 9 | if (argc !=3) 10 | { 11 | std::cout << " .exe mode_path image_file" << std::endl; 12 | return -1; 13 | } 14 | 15 | std::string model_path = argv[1]; 16 | std::string image_file = argv[2]; 17 | 18 | LFFD lffd(model_path); 19 | cv::Mat frame = cv::imread(image_file); 20 | std::vector face_info; 21 | 22 | ncnn::Mat inmat = ncnn::Mat::from_pixels(frame.data, ncnn::Mat::PIXEL_BGR, frame.cols, frame.rows); 23 | lffd.detect(inmat, face_info, 240, 320); 24 | 25 | for (int i = 0; i < face_info.size(); i++) 26 | { 27 | auto face = face_info[i]; 28 | cv::Point pt1(face.x1, face.y1); 29 | cv::Point pt2(face.x2, face.y2); 30 | cv::rectangle(frame, pt1, pt2, cv::Scalar(0, 255, 0), 2); 31 | } 32 | 33 | cv::namedWindow("lffd", CV_WINDOW_NORMAL); 34 | cv::imshow("lffd", frame); 35 | cv::waitKey(); 36 | return 0; 37 | } --------------------------------------------------------------------------------