[
  {
    "path": "README.md",
    "content": "# Fast-MTCNN\n\nA casual work about retainining mtcnn Pnet and Onet. make it a little bit fast,which achiciving 100fps+ (1920*1080 minSize 60) at intel i7 6700k (st),but the accuracy is not so well.\n\n## Dependencies\n\n+ OpenCV 3.4.1 only\n\nThe demo base on [OpenCV](https://github.com/opencv/opencv) DNN module. my computer with Intel i7 6700k (st) can achicive 100fps+ (1920*1080 minSize 60)compiled with OpenBLAS (OpenCV 3.4.1) ,if you wanna achieve the better performance.you can compile with [Intel MKL-DNN Inference Engine package](https://github.com/opencv/opencv/wiki/Intel%27s-Deep-Learning-Inference-Engine-backend) to accelerate.\n\n### Demo Image\n\n![Screen Shot 2018-05-25 at 2.25.02 AM](images/test.png)\n\n### TODO\n+ Optimize PNet Rnet Onet with modern net desigin (bottleneck , depthwise conv ,inverted residual block...) .\n+ Benchmark on FDDB.\n+ Computing sharing to accelerate speed when the detected faces increased.\n\n\n## Anthor\n\n+ Jack Yu\n"
  },
  {
    "path": "model/det1.prototxt",
    "content": "name: \"PNet\"\ninput: \"data\"\ninput_dim: 1\ninput_dim: 3\ninput_dim: 12\ninput_dim: 12\n\nlayer {\n  name: \"conv1\"\n  type: \"Convolution\"\n  bottom: \"data\"\n  top: \"conv1\"\n  param {\n    lr_mult: 1\n    decay_mult: 1\n  }\n  param {\n    lr_mult: 2\n    decay_mult: 0\n  }\n  convolution_param {\n    num_output: 10\n    kernel_size: 3\n    stride: 1\n    weight_filler {\n      type: \"xavier\"\n    }\n    bias_filler {\n      type: \"constant\"\n      value: 0\n    }\n  }\n}\nlayer {\n  name: \"PReLU1\"\n  type: \"PReLU\"\n  bottom: \"conv1\"\n  top: \"conv1\"\n}\nlayer {\n  name: \"pool1\"\n  type: \"Pooling\"\n  bottom: \"conv1\"\n  top: \"pool1\"\n  pooling_param {\n    pool: MAX\n    kernel_size: 2\n    stride: 2\n  }\n}\n\nlayer {\n  name: \"conv2\"\n  type: \"Convolution\"\n  bottom: \"pool1\"\n  top: \"conv2\"\n  param {\n    lr_mult: 1\n    decay_mult: 1\n  }\n  param {\n    lr_mult: 2\n    decay_mult: 0\n  }\n  convolution_param {\n    num_output: 16\n    kernel_size: 3\n    stride: 1\n     weight_filler {\n      type: \"xavier\"\n    }\n    bias_filler {\n      type: \"constant\"\n      value: 0\n    }\n  }\n}\nlayer {\n  name: \"PReLU2\"\n  type: \"PReLU\"\n  bottom: \"conv2\"\n  top: \"conv2\"\n}\n\nlayer {\n  name: \"conv3\"\n  type: \"Convolution\"\n  bottom: \"conv2\"\n  top: \"conv3\"\n  param {\n    lr_mult: 1\n    decay_mult: 1\n  }\n  param {\n    lr_mult: 2\n    decay_mult: 0\n  }\n  convolution_param {\n    num_output: 32\n    kernel_size: 3\n    stride: 1\n     weight_filler {\n      type: \"xavier\"\n    }\n    bias_filler {\n\t  type: \"constant\"\n      value: 0\n    }\n  }\n}\nlayer {\n  name: \"PReLU3\"\n  type: \"PReLU\"\n  bottom: \"conv3\"\n  top: \"conv3\"\n}\n\n\nlayer {\n  name: \"conv4-1\"\n  type: \"Convolution\"\n  bottom: \"conv3\"\n  top: \"conv4-1\"\n  param {\n    lr_mult: 1\n    decay_mult: 1\n  }\n  param {\n    lr_mult: 2\n    decay_mult: 0\n  }\n  convolution_param {\n    num_output: 2\n    kernel_size: 1\n    stride: 1\n     weight_filler {\n      type: \"xavier\"\n    }\n    bias_filler {\n      type: \"constant\"\n      value: 0\n    }\n  }\n}\n\nlayer {\n  name: \"conv4-2\"\n  type: \"Convolution\"\n  bottom: \"conv3\"\n  top: \"conv4-2\"\n  param {\n    lr_mult: 1\n    decay_mult: 1\n  }\n  param {\n    lr_mult: 2\n    decay_mult: 0\n  }\n  convolution_param {\n    num_output: 4\n    kernel_size: 1\n    stride: 1\n     weight_filler {\n      type: \"xavier\"\n\t}\n    bias_filler {\n      type: \"constant\"\n      value: 0\n    }\n  }\n}\nlayer {\n  name: \"prob1\"\n  type: \"Softmax\"\n  bottom: \"conv4-1\"\n  top: \"prob1\"\n}\n"
  },
  {
    "path": "model/det1_.prototxt",
    "content": "input: \"data\"\ninput_dim: 1\ninput_dim: 3\ninput_dim: 12\ninput_dim: 12\nlayer {\n  name: \"conv1\"\n  type: \"Convolution\"\n  bottom: \"data\"\n  top: \"conv1\"\n  convolution_param {\n    num_output: 10\n    bias_term: true\n    pad_h: 0\n    pad_w: 0\n    kernel_h: 3\n    kernel_w: 3\n    stride_h: 1\n    stride_w: 1\n  }\n}\nlayer {\n  name: \"batch_normalization_5\"\n  type: \"BatchNorm\"\n  bottom: \"conv1\"\n  top: \"batch_normalization_5\"\n  batch_norm_param {\n    moving_average_fraction: 0.990000009537\n    eps: 0.0010000000475\n  }\n}\nlayer {\n  name: \"batch_normalization_5_scale\"\n  type: \"Scale\"\n  bottom: \"batch_normalization_5\"\n  top: \"batch_normalization_5\"\n  scale_param {\n    bias_term: true\n  }\n}\nlayer {\n  name: \"prelu1\"\n  type: \"PReLU\"\n  bottom: \"batch_normalization_5\"\n  top: \"prelu1\"\n}\nlayer {\n  name: \"max_pooling2d_3\"\n  type: \"Pooling\"\n  bottom: \"prelu1\"\n  top: \"max_pooling2d_3\"\n  pooling_param {\n    pool: MAX\n    kernel_h: 2\n    kernel_w: 2\n    stride_h: 2\n    stride_w: 2\n    pad_h: 0\n    pad_w: 0\n  }\n}\nlayer {\n  name: \"conv2_\"\n  type: \"Convolution\"\n  bottom: \"max_pooling2d_3\"\n  top: \"conv2_\"\n  convolution_param {\n    num_output: 14\n    bias_term: true\n    pad_h: 0\n    pad_w: 0\n    kernel_h: 3\n    kernel_w: 3\n    stride_h: 1\n    stride_w: 1\n  }\n}\nlayer {\n  name: \"batch_normalization_6\"\n  type: \"BatchNorm\"\n  bottom: \"conv2_\"\n  top: \"batch_normalization_6\"\n  batch_norm_param {\n    moving_average_fraction: 0.990000009537\n    eps: 0.0010000000475\n  }\n}\nlayer {\n  name: \"batch_normalization_6_scale\"\n  type: \"Scale\"\n  bottom: \"batch_normalization_6\"\n  top: \"batch_normalization_6\"\n  scale_param {\n    bias_term: true\n  }\n}\nlayer {\n  name: \"prelu2\"\n  type: \"PReLU\"\n  bottom: \"batch_normalization_6\"\n  top: \"prelu2\"\n}\nlayer {\n  name: \"conv3\"\n  type: \"Convolution\"\n  bottom: \"prelu2\"\n  top: \"conv3\"\n  convolution_param {\n    num_output: 16\n    bias_term: true\n    pad_h: 0\n    pad_w: 0\n    kernel_h: 3\n    kernel_w: 3\n    stride_h: 1\n    stride_w: 1\n  }\n}\nlayer {\n  name: \"batch_normalization_7\"\n  type: \"BatchNorm\"\n  bottom: \"conv3\"\n  top: \"batch_normalization_7\"\n  batch_norm_param {\n    moving_average_fraction: 0.990000009537\n    eps: 0.0010000000475\n  }\n}\nlayer {\n  name: \"batch_normalization_7_scale\"\n  type: \"Scale\"\n  bottom: \"batch_normalization_7\"\n  top: \"batch_normalization_7\"\n  scale_param {\n    bias_term: true\n  }\n}\nlayer {\n  name: \"prelu3\"\n  type: \"PReLU\"\n  bottom: \"batch_normalization_7\"\n  top: \"prelu3\"\n}\nlayer {\n  name: \"classifier1\"\n  type: \"Convolution\"\n  bottom: \"prelu3\"\n  top: \"classifier1\"\n  convolution_param {\n    num_output: 2\n    bias_term: true\n    pad_h: 0\n    pad_w: 0\n    kernel_h: 1\n    kernel_w: 1\n    stride_h: 1\n    stride_w: 1\n  }\n}\nlayer {\n  name: \"prob1\"\n  type: \"Softmax\"\n  bottom: \"classifier1\"\n  top: \"prob1\"\n}\nlayer {\n  name: \"conv4-2\"\n  type: \"Convolution\"\n  bottom: \"prelu3\"\n  top: \"conv4-2\"\n  convolution_param {\n    num_output: 4\n    bias_term: true\n    pad_h: 0\n    pad_w: 0\n    kernel_h: 1\n    kernel_w: 1\n    stride_h: 1\n    stride_w: 1\n  }\n}\n"
  },
  {
    "path": "model/det2.prototxt",
    "content": "name: \"RNet\"\ninput: \"data\"\ninput_dim: 1\ninput_dim: 3\ninput_dim: 24\ninput_dim: 24\n\nlayer {\n  name: \"conv1\"\n  type: \"Convolution\"\n  bottom: \"data\"\n  top: \"conv1\"\n  param {\n    lr_mult: 0\n    decay_mult: 0\n  }\n  param {\n    lr_mult: 0\n    decay_mult: 0\n  }\n  convolution_param {\n    num_output: 28\n    kernel_size: 3\n    stride: 1\n     weight_filler {\n      type: \"xavier\"\n\t}\n    bias_filler {\n      type: \"constant\"\n      value: 0\n    }\n  }\n}\nlayer {\n  name: \"prelu1\"\n  type: \"PReLU\"\n  bottom: \"conv1\"\n  top: \"conv1\"\n  propagate_down: true\n}\nlayer {\n  name: \"pool1\"\n  type: \"Pooling\"\n  bottom: \"conv1\"\n  top: \"pool1\"\n  pooling_param {\n    pool: MAX\n    kernel_size: 3\n    stride: 2\n  }\n}\n\nlayer {\n  name: \"conv2\"\n  type: \"Convolution\"\n  bottom: \"pool1\"\n  top: \"conv2\"\n  param {\n    lr_mult: 0\n    decay_mult: 0\n  }\n  param {\n    lr_mult: 0\n    decay_mult: 0\n  }\n  convolution_param {\n    num_output: 48\n    kernel_size: 3\n    stride: 1\n    weight_filler {\n      type: \"xavier\"\n\t}\n    bias_filler {\n      type: \"constant\"\n      value: 0\n    }\n  }\n}\nlayer {\n  name: \"prelu2\"\n  type: \"PReLU\"\n  bottom: \"conv2\"\n  top: \"conv2\"\n  propagate_down: true\n}\nlayer {\n  name: \"pool2\"\n  type: \"Pooling\"\n  bottom: \"conv2\"\n  top: \"pool2\"\n  pooling_param {\n    pool: MAX\n    kernel_size: 3\n    stride: 2\n  }\n}\n####################################\n\n##################################\nlayer {\n  name: \"conv3\"\n  type: \"Convolution\"\n  bottom: \"pool2\"\n  top: \"conv3\"\n  param {\n    lr_mult: 0\n    decay_mult: 0\n  }\n  param {\n    lr_mult: 0\n    decay_mult: 0\n  }\n  convolution_param {\n    num_output: 64\n    kernel_size: 2\n    stride: 1\n    weight_filler {\n      type: \"xavier\"\n\t}\n    bias_filler {\n      type: \"constant\"\n      value: 0\n    }\n  }\n}\nlayer {\n  name: \"prelu3\"\n  type: \"PReLU\"\n  bottom: \"conv3\"\n  top: \"conv3\"\n  propagate_down: true\n}\n###############################\n\n###############################\n\nlayer {\n  name: \"conv4\"\n  type: \"InnerProduct\"\n  bottom: \"conv3\"\n  top: \"conv4\"\n  param {\n    lr_mult: 0\n    decay_mult: 0\n  }\n  param {\n    lr_mult: 0\n    decay_mult: 0\n  }\n  inner_product_param {\n    num_output: 128\n    weight_filler {\n      type: \"xavier\"\n\t}\n    bias_filler {\n      type: \"constant\"\n      value: 0\n    }\n  }\n}\nlayer {\n  name: \"prelu4\"\n  type: \"PReLU\"\n  bottom: \"conv4\"\n  top: \"conv4\"\n}\n\nlayer {\n  name: \"conv5-1\"\n  type: \"InnerProduct\"\n  bottom: \"conv4\"\n  top: \"conv5-1\"\n  param {\n    lr_mult: 0\n    decay_mult: 0\n  }\n  param {\n    lr_mult: 0\n    decay_mult: 0\n  }\n  inner_product_param {\n    num_output: 2\n    #kernel_size: 1\n    #stride: 1\n    weight_filler {\n      type: \"xavier\"\n\t}\n    bias_filler {\n      type: \"constant\"\n      value: 0\n    }\n  }\n}\nlayer {\n  name: \"conv5-2\"\n  type: \"InnerProduct\"\n  bottom: \"conv4\"\n  top: \"conv5-2\"\n  param {\n    lr_mult: 1\n    decay_mult: 1\n  }\n  param {\n    lr_mult: 2\n    decay_mult: 1\n  }\n  inner_product_param {\n    num_output: 4\n    #kernel_size: 1\n    #stride: 1\n     weight_filler {\n      type: \"xavier\"\n\t}\n    bias_filler {\n      type: \"constant\"\n      value: 0\n    }\n  }\n}\nlayer {\n  name: \"prob1\"\n  type: \"Softmax\"\n  bottom: \"conv5-1\"\n  top: \"prob1\"\n}"
  },
  {
    "path": "model/det3-half.prototxt",
    "content": "name: \"ONet\"\r\ninput: \"data\"\r\ninput_dim: 1\r\ninput_dim: 3\r\ninput_dim: 48\r\ninput_dim: 48\r\n\r\n##################################\r\nlayer {\r\n  name: \"conv1\"\r\n  type: \"Convolution\"\r\n  bottom: \"data\"\r\n  top: \"conv1\"\r\n  param {\r\n    lr_mult: 1\r\n    decay_mult: 1\r\n  }\r\n  param {\r\n    lr_mult: 2\r\n    decay_mult: 1\r\n  }\r\n  convolution_param {\r\n    num_output: 16\r\n    kernel_size: 3\r\n    stride: 1\r\n     weight_filler {\r\n      type: \"xavier\"\r\n\t}\r\n    bias_filler {\r\n      type: \"constant\"\r\n      value: 0\r\n    }\r\n  }\r\n}\r\nlayer {\r\n  name: \"prelu1\"\r\n  type: \"PReLU\"\r\n  bottom: \"conv1\"\r\n  top: \"conv1\"\r\n}\r\nlayer {\r\n  name: \"pool1\"\r\n  type: \"Pooling\"\r\n  bottom: \"conv1\"\r\n  top: \"pool1\"\r\n  pooling_param {\r\n    pool: MAX\r\n    kernel_size: 3\r\n    stride: 2\r\n  }\r\n}\r\nlayer {\r\n  name: \"conv2\"\r\n  type: \"Convolution\"\r\n  bottom: \"pool1\"\r\n  top: \"conv2\"\r\n  param {\r\n    lr_mult: 1\r\n    decay_mult: 1\r\n  }\r\n  param {\r\n    lr_mult: 2\r\n    decay_mult: 1\r\n  }\r\n  convolution_param {\r\n    num_output: 32\r\n    kernel_size: 3\r\n    stride: 1\r\n     weight_filler {\r\n      type: \"xavier\"\r\n\t}\r\n    bias_filler {\r\n      type: \"constant\"\r\n      value: 0\r\n    }\r\n  }\r\n}\r\n\r\nlayer {\r\n  name: \"prelu2\"\r\n  type: \"PReLU\"\r\n  bottom: \"conv2\"\r\n  top: \"conv2\"\r\n}\r\nlayer {\r\n  name: \"pool2\"\r\n  type: \"Pooling\"\r\n  bottom: \"conv2\"\r\n  top: \"pool2\"\r\n  pooling_param {\r\n    pool: MAX\r\n    kernel_size: 3\r\n    stride: 2\r\n  }\r\n}\r\n\r\nlayer {\r\n  name: \"conv3\"\r\n  type: \"Convolution\"\r\n  bottom: \"pool2\"\r\n  top: \"conv3\"\r\n  param {\r\n    lr_mult: 1\r\n    decay_mult: 1\r\n  }\r\n  param {\r\n    lr_mult: 2\r\n    decay_mult: 1\r\n  }\r\n  convolution_param {\r\n\tnum_output: 32\r\n\tkernel_size: 3\r\n    weight_filler {\r\n      type: \"xavier\"\r\n\t}\r\n    bias_filler {\r\n      type: \"constant\"\r\n      value: 0\r\n    }\r\n  }\r\n}\r\nlayer {\r\n  name: \"prelu3\"\r\n  type: \"PReLU\"\r\n  bottom: \"conv3\"\r\n  top: \"conv3\"\r\n}\r\nlayer {\r\n  name: \"pool3\"\r\n  type: \"Pooling\"\r\n  bottom: \"conv3\"\r\n  top: \"pool3\"\r\n  pooling_param {\r\n    pool: MAX\r\n    kernel_size: 2\r\n    stride: 2\r\n  }\r\n}\r\nlayer {\r\n  name: \"conv4\"\r\n  type: \"Convolution\"\r\n  bottom: \"pool3\"\r\n  top: \"conv4\"\r\n  param {\r\n    lr_mult: 1\r\n    decay_mult: 1\r\n  }\r\n  param {\r\n    lr_mult: 2\r\n    decay_mult: 1\r\n  }\r\n  convolution_param {\r\n\tnum_output: 64\r\n\tkernel_size: 2\r\n    weight_filler {\r\n      type: \"xavier\"\r\n\t}\r\n    bias_filler {\r\n      type: \"constant\"\r\n      value: 0\r\n    }\r\n  }\r\n}\r\nlayer {\r\n  name: \"prelu4\"\r\n  type: \"PReLU\"\r\n  bottom: \"conv4\"\r\n  top: \"conv4\"\r\n}\r\n\r\n\r\nlayer {\r\n  name: \"conv5\"\r\n  type: \"InnerProduct\"\r\n  bottom: \"conv4\"\r\n  top: \"conv5\"\r\n  param {\r\n    lr_mult: 1\r\n    decay_mult: 1\r\n  }\r\n  param {\r\n    lr_mult: 2\r\n    decay_mult: 1\r\n  }\r\n  inner_product_param {\r\n\t#kernel_size: 3\r\n\tnum_output: 128\r\n    weight_filler {\r\n      type: \"xavier\"\r\n\t}\r\n    bias_filler {\r\n      type: \"constant\"\r\n      value: 0\r\n    }\r\n  }\r\n}\r\nlayer {\r\n  name: \"prelu5\"\r\n type: \"PReLU\"\r\n  # type: \"TanH\"\r\n  bottom: \"conv5\"\r\n  top: \"conv5\"\r\n}\r\n\r\n\r\nlayer {\r\n  name: \"conv6-1\"\r\n  type: \"InnerProduct\"\r\n  bottom: \"conv5\"\r\n  top: \"conv6-1\"\r\n  param {\r\n    lr_mult: 1\r\n    decay_mult: 1\r\n  }\r\n  param {\r\n    lr_mult: 2\r\n    decay_mult: 1\r\n  }\r\n  inner_product_param {\r\n    #kernel_size: 1\r\n\tnum_output: 2\r\n    weight_filler {\r\n      type: \"xavier\"\r\n\t}\r\n    bias_filler {\r\n      type: \"constant\"\r\n      value: 0\r\n    }\r\n  }\r\n}\r\nlayer {\r\n  name: \"conv6-2\"\r\n  type: \"InnerProduct\"\r\n  bottom: \"conv5\"\r\n  top: \"conv6-2\"\r\n  param {\r\n    lr_mult: 1\r\n    decay_mult: 1\r\n  }\r\n  param {\r\n    lr_mult: 2\r\n    decay_mult: 1\r\n  }\r\n  inner_product_param {\r\n  \t#kernel_size: 1\r\n\tnum_output: 4\r\n    weight_filler {\r\n      type: \"xavier\"\r\n\t}\r\n    bias_filler {\r\n      type: \"constant\"\r\n      value: 0\r\n    }\r\n  }\r\n}\r\nlayer {\r\n  name: \"conv6-3\"\r\n  type: \"InnerProduct\"\r\n  bottom: \"conv5\"\r\n  top: \"conv6-3\"\r\n  param {\r\n    lr_mult: 1\r\n    decay_mult: 1\r\n  }\r\n  param {\r\n    lr_mult: 2\r\n    decay_mult: 1\r\n  }\r\n  inner_product_param {\r\n  \t#kernel_size: 1\r\n\tnum_output: 10\r\n    weight_filler {\r\n      type: \"xavier\"\r\n\t}\r\n    bias_filler {\r\n      type: \"constant\"\r\n      value: 0\r\n    }\r\n  }\r\n}\r\n  \r\nlayer {\r\n  name: \"prob1\"\r\n  type: \"Softmax\"\r\n  bottom: \"conv6-1\"\r\n  top: \"prob1\"\r\n}\r\n"
  },
  {
    "path": "model/det3.prototxt",
    "content": "name: \"ONet\"\r\ninput: \"data\"\r\ninput_dim: 1\r\ninput_dim: 3\r\ninput_dim: 48\r\ninput_dim: 48\r\n\r\n##################################\r\nlayer {\r\n  name: \"conv1\"\r\n  type: \"Convolution\"\r\n  bottom: \"data\"\r\n  top: \"conv1\"\r\n  param {\r\n    lr_mult: 1\r\n    decay_mult: 1\r\n  }\r\n  param {\r\n    lr_mult: 2\r\n    decay_mult: 1\r\n  }\r\n  convolution_param {\r\n    num_output: 32\r\n    kernel_size: 3\r\n    stride: 1\r\n     weight_filler {\r\n      type: \"xavier\"\r\n\t}\r\n    bias_filler {\r\n      type: \"constant\"\r\n      value: 0\r\n    }\r\n  }\r\n}\r\nlayer {\r\n  name: \"prelu1\"\r\n  type: \"PReLU\"\r\n  bottom: \"conv1\"\r\n  top: \"conv1\"\r\n}\r\nlayer {\r\n  name: \"pool1\"\r\n  type: \"Pooling\"\r\n  bottom: \"conv1\"\r\n  top: \"pool1\"\r\n  pooling_param {\r\n    pool: MAX\r\n    kernel_size: 3\r\n    stride: 2\r\n  }\r\n}\r\nlayer {\r\n  name: \"conv2\"\r\n  type: \"Convolution\"\r\n  bottom: \"pool1\"\r\n  top: \"conv2\"\r\n  param {\r\n    lr_mult: 1\r\n    decay_mult: 1\r\n  }\r\n  param {\r\n    lr_mult: 2\r\n    decay_mult: 1\r\n  }\r\n  convolution_param {\r\n    num_output: 64\r\n    kernel_size: 3\r\n    stride: 1\r\n     weight_filler {\r\n      type: \"xavier\"\r\n\t}\r\n    bias_filler {\r\n      type: \"constant\"\r\n      value: 0\r\n    }\r\n  }\r\n}\r\n\r\nlayer {\r\n  name: \"prelu2\"\r\n  type: \"PReLU\"\r\n  bottom: \"conv2\"\r\n  top: \"conv2\"\r\n}\r\nlayer {\r\n  name: \"pool2\"\r\n  type: \"Pooling\"\r\n  bottom: \"conv2\"\r\n  top: \"pool2\"\r\n  pooling_param {\r\n    pool: MAX\r\n    kernel_size: 3\r\n    stride: 2\r\n  }\r\n}\r\n\r\nlayer {\r\n  name: \"conv3\"\r\n  type: \"Convolution\"\r\n  bottom: \"pool2\"\r\n  top: \"conv3\"\r\n  param {\r\n    lr_mult: 1\r\n    decay_mult: 1\r\n  }\r\n  param {\r\n    lr_mult: 2\r\n    decay_mult: 1\r\n  }\r\n  convolution_param {\r\n\tnum_output: 64\r\n\tkernel_size: 3\r\n    weight_filler {\r\n      type: \"xavier\"\r\n\t}\r\n    bias_filler {\r\n      type: \"constant\"\r\n      value: 0\r\n    }\r\n  }\r\n}\r\nlayer {\r\n  name: \"prelu3\"\r\n  type: \"PReLU\"\r\n  bottom: \"conv3\"\r\n  top: \"conv3\"\r\n}\r\nlayer {\r\n  name: \"pool3\"\r\n  type: \"Pooling\"\r\n  bottom: \"conv3\"\r\n  top: \"pool3\"\r\n  pooling_param {\r\n    pool: MAX\r\n    kernel_size: 2\r\n    stride: 2\r\n  }\r\n}\r\nlayer {\r\n  name: \"conv4\"\r\n  type: \"Convolution\"\r\n  bottom: \"pool3\"\r\n  top: \"conv4\"\r\n  param {\r\n    lr_mult: 1\r\n    decay_mult: 1\r\n  }\r\n  param {\r\n    lr_mult: 2\r\n    decay_mult: 1\r\n  }\r\n  convolution_param {\r\n\tnum_output: 128\r\n\tkernel_size: 2\r\n    weight_filler {\r\n      type: \"xavier\"\r\n\t}\r\n    bias_filler {\r\n      type: \"constant\"\r\n      value: 0\r\n    }\r\n  }\r\n}\r\nlayer {\r\n  name: \"prelu4\"\r\n  type: \"PReLU\"\r\n  bottom: \"conv4\"\r\n  top: \"conv4\"\r\n}\r\n\r\n\r\nlayer {\r\n  name: \"conv5\"\r\n  type: \"InnerProduct\"\r\n  bottom: \"conv4\"\r\n  top: \"conv5\"\r\n  param {\r\n    lr_mult: 1\r\n    decay_mult: 1\r\n  }\r\n  param {\r\n    lr_mult: 2\r\n    decay_mult: 1\r\n  }\r\n  inner_product_param {\r\n\t#kernel_size: 3\r\n\tnum_output: 256\r\n    weight_filler {\r\n      type: \"xavier\"\r\n\t}\r\n    bias_filler {\r\n      type: \"constant\"\r\n      value: 0\r\n    }\r\n  }\r\n}\r\n\r\nlayer {\r\n  name: \"drop5\"\r\n  type: \"Dropout\"\r\n  bottom: \"conv5\"\r\n  top: \"conv5\"\r\n  dropout_param {\r\n    dropout_ratio: 0.25\r\n  }\r\n}\r\nlayer {\r\n  name: \"prelu5\"\r\n type: \"PReLU\"\r\n  # type: \"TanH\"\r\n  bottom: \"conv5\"\r\n  top: \"conv5\"\r\n}\r\n\r\n\r\nlayer {\r\n  name: \"conv6-1\"\r\n  type: \"InnerProduct\"\r\n  bottom: \"conv5\"\r\n  top: \"conv6-1\"\r\n  param {\r\n    lr_mult: 1\r\n    decay_mult: 1\r\n  }\r\n  param {\r\n    lr_mult: 2\r\n    decay_mult: 1\r\n  }\r\n  inner_product_param {\r\n    #kernel_size: 1\r\n\tnum_output: 2\r\n    weight_filler {\r\n      type: \"xavier\"\r\n\t}\r\n    bias_filler {\r\n      type: \"constant\"\r\n      value: 0\r\n    }\r\n  }\r\n}\r\nlayer {\r\n  name: \"conv6-2\"\r\n  type: \"InnerProduct\"\r\n  bottom: \"conv5\"\r\n  top: \"conv6-2\"\r\n  param {\r\n    lr_mult: 1\r\n    decay_mult: 1\r\n  }\r\n  param {\r\n    lr_mult: 2\r\n    decay_mult: 1\r\n  }\r\n  inner_product_param {\r\n  \t#kernel_size: 1\r\n\tnum_output: 4\r\n    weight_filler {\r\n      type: \"xavier\"\r\n\t}\r\n    bias_filler {\r\n      type: \"constant\"\r\n      value: 0\r\n    }\r\n  }\r\n}\r\nlayer {\r\n  name: \"conv6-3\"\r\n  type: \"InnerProduct\"\r\n  bottom: \"conv5\"\r\n  top: \"conv6-3\"\r\n  param {\r\n    lr_mult: 1\r\n    decay_mult: 1\r\n  }\r\n  param {\r\n    lr_mult: 2\r\n    decay_mult: 1\r\n  }\r\n  inner_product_param {\r\n  \t#kernel_size: 1\r\n\tnum_output: 10\r\n    weight_filler {\r\n      type: \"xavier\"\r\n\t}\r\n    bias_filler {\r\n      type: \"constant\"\r\n      value: 0\r\n    }\r\n  }\r\n}\r\n  \r\nlayer {\r\n  name: \"prob1\"\r\n  type: \"Softmax\"\r\n  bottom: \"conv6-1\"\r\n  top: \"prob1\"\r\n}\r\n"
  },
  {
    "path": "mtcnn_opencv.cpp",
    "content": "//Created by Jack Yu\r\n#include <fstream>\r\n#include <iostream>\r\n#include <opencv2/opencv.hpp>\r\n#include <opencv2/dnn.hpp>\r\nusing namespace std;\r\nusing namespace cv;\r\n\r\nconst float pnet_stride = 2;\r\nconst float pnet_cell_size = 12;\r\nconst int pnet_max_detect_num = 5000;\r\n//mean & std\r\nconst float mean_val = 127.5f;\r\nconst float std_val = 0.0078125f;\r\n//minibatch size\r\nconst int step_size = 128;\r\n\r\n\r\ntypedef struct FaceBox {\r\n    float xmin;\r\n    float ymin;\r\n    float xmax;\r\n    float ymax;\r\n    float score;\r\n} FaceBox;\r\ntypedef struct FaceInfo {\r\n    float bbox_reg[4];\r\n    float landmark_reg[10];\r\n    float landmark[10];\r\n    FaceBox bbox;\r\n} FaceInfo;\r\n\r\n\r\n\r\nclass MTCNN {\r\npublic:\r\n    MTCNN(const string& proto_model_dir);\r\n    vector<FaceInfo> Detect_mtcnn(const cv::Mat& img, const int min_size, const float* threshold, const float factor, const int stage);\r\n//protected:\r\n    vector<FaceInfo> ProposalNet(const cv::Mat& img, int min_size, float threshold, float factor);\r\n    vector<FaceInfo> NextStage(const cv::Mat& image, vector<FaceInfo> &pre_stage_res, int input_w, int input_h, int stage_num, const float threshold);\r\n    void BBoxRegression(vector<FaceInfo>& bboxes);\r\n    void BBoxPadSquare(vector<FaceInfo>& bboxes, int width, int height);\r\n    void BBoxPad(vector<FaceInfo>& bboxes, int width, int height);\r\n    void GenerateBBox(Mat* confidence, Mat* reg_box, float scale, float thresh);\r\n    std::vector<FaceInfo> NMS(std::vector<FaceInfo>& bboxes, float thresh, char methodType);\r\n    float IoU(float xmin, float ymin, float xmax, float ymax, float xmin_, float ymin_, float xmax_, float ymax_, bool is_iom = false);\r\n\r\n\r\n\r\n//    std::shared_ptr<dnn::Net> PNet_;\r\n//    std::shared_ptr<dnn::Net> ONet_;\r\n//    std::shared_ptr<dnn::Net> RNet_;\r\npublic:\r\n    dnn::Net PNet_;\r\n    dnn::Net RNet_;\r\n    dnn::Net ONet_;\r\n\r\n    std::vector<FaceInfo> candidate_boxes_;\r\n    std::vector<FaceInfo> total_boxes_;\r\n};\r\n\r\n\r\nMTCNN::MTCNN(const string& proto_model_dir) {\r\n//    PNet_ = cv::dnn::readNetFromCaffe(proto_model_dir + \"/det1.prototxt\", proto_model_dir + \"/det1_half.caffemodel\");\r\n    PNet_ = cv::dnn::readNetFromCaffe(proto_model_dir + \"/det1_.prototxt\", proto_model_dir + \"/det1_.caffemodel\");\r\n\r\n    RNet_ = cv::dnn::readNetFromCaffe(proto_model_dir + \"/det2.prototxt\", proto_model_dir + \"/det2_half.caffemodel\");\r\n    ONet_ = cv::dnn::readNetFromCaffe(proto_model_dir + \"/det3-half.prototxt\", proto_model_dir + \"/det3-half.caffemodel\");\r\n}\r\n\r\nbool CompareBBox(const FaceInfo & a, const FaceInfo & b) {\r\n    return a.bbox.score > b.bbox.score;\r\n}\r\n\r\n\r\n\r\nfloat MTCNN::IoU(float xmin, float ymin, float xmax, float ymax,\r\n                 float xmin_, float ymin_, float xmax_, float ymax_, bool is_iom) {\r\n    float iw = std::min(xmax, xmax_) - std::max(xmin, xmin_) + 1;\r\n    float ih = std::min(ymax, ymax_) - std::max(ymin, ymin_) + 1;\r\n    if (iw <= 0 || ih <= 0)\r\n        return 0;\r\n    float s = iw*ih;\r\n    if (is_iom) {\r\n        float ov = s / min((xmax - xmin + 1)*(ymax - ymin + 1), (xmax_ - xmin_ + 1)*(ymax_ - ymin_ + 1));\r\n        return ov;\r\n    }\r\n    else {\r\n        float ov = s / ((xmax - xmin + 1)*(ymax - ymin + 1) + (xmax_ - xmin_ + 1)*(ymax_ - ymin_ + 1) - s);\r\n        return ov;\r\n    }\r\n}\r\nvoid MTCNN::BBoxRegression(vector<FaceInfo>& bboxes) {\r\n//#pragma omp parallel for num_threads(threads_num)\r\n    for (int i = 0; i < bboxes.size(); ++i) {\r\n        FaceBox &bbox = bboxes[i].bbox;\r\n        float *bbox_reg = bboxes[i].bbox_reg;\r\n        float w = bbox.xmax - bbox.xmin + 1;\r\n        float h = bbox.ymax - bbox.ymin + 1;\r\n        bbox.xmin += bbox_reg[0] * w;\r\n        bbox.ymin += bbox_reg[1] * h;\r\n        bbox.xmax += bbox_reg[2] * w;\r\n        bbox.ymax += bbox_reg[3] * h;\r\n    }\r\n}\r\nvoid MTCNN::BBoxPad(vector<FaceInfo>& bboxes, int width, int height) {\r\n//#pragma omp parallel for num_threads(threads_num)\r\n    for (int i = 0; i < bboxes.size(); ++i) {\r\n        FaceBox &bbox = bboxes[i].bbox;\r\n        bbox.xmin = round(max(bbox.xmin, 0.f));\r\n        bbox.ymin = round(max(bbox.ymin, 0.f));\r\n        bbox.xmax = round(min(bbox.xmax, width - 1.f));\r\n        bbox.ymax = round(min(bbox.ymax, height - 1.f));\r\n    }\r\n}\r\nvoid MTCNN::BBoxPadSquare(vector<FaceInfo>& bboxes, int width, int height) {\r\n//#pragma omp parallel for num_threads(threads_num)\r\n    for (int i = 0; i < bboxes.size(); ++i) {\r\n        FaceBox &bbox = bboxes[i].bbox;\r\n        float w = bbox.xmax - bbox.xmin + 1;\r\n        float h = bbox.ymax - bbox.ymin + 1;\r\n        float side = h>w ? h : w;\r\n        bbox.xmin = round(max(bbox.xmin + (w - side)*0.5f, 0.f));\r\n\r\n        bbox.ymin = round(max(bbox.ymin + (h - side)*0.5f, 0.f));\r\n        bbox.xmax = round(min(bbox.xmin + side - 1, width - 1.f));\r\n        bbox.ymax = round(min(bbox.ymin + side - 1, height - 1.f));\r\n    }\r\n}\r\nvoid MTCNN::GenerateBBox(Mat* confidence, Mat* reg_box,\r\n                         float scale, float thresh) {\r\n    int feature_map_w_ = confidence->size[3];\r\n    int feature_map_h_ = confidence->size[2];\r\n    int spatical_size = feature_map_w_*feature_map_h_;\r\n//    const float* confidence_data = (float*)(confidence->data + spatical_size);\r\n\r\n    std::cout<<confidence->size;\r\n    std::cout<<\" \"<<scale<<std::endl;\r\n\r\n\r\n    const float* confidence_data = (float*)(confidence->data);\r\n    confidence_data += spatical_size;\r\n\r\n    cv::Mat image(feature_map_h_,feature_map_w_,confidence->type());\r\n\r\n    image.data =(unsigned  char*)(confidence_data);\r\n//    cv::imshow(\"image\",image);\r\n//    cv::waitKey(0);\r\n\r\n\r\n\r\n\r\n//    std::cout<<confidence_data[0]<<std::endl;\r\n\r\n    const float* reg_data = (float*)(reg_box->data);\r\n    candidate_boxes_.clear();\r\n    for (int i = 0; i<spatical_size; i++) {\r\n//        if (confidence_data[i] >= thresh) {\r\n        if (confidence_data[i] <= 1-thresh) {\r\n\r\n            int y = i / feature_map_w_;\r\n            int x = i - feature_map_w_ * y;\r\n            FaceInfo faceInfo;\r\n            FaceBox &faceBox = faceInfo.bbox;\r\n\r\n            faceBox.xmin = (float)(x * pnet_stride) / scale;\r\n            faceBox.ymin = (float)(y * pnet_stride) / scale;\r\n            faceBox.xmax = (float)(x * pnet_stride + pnet_cell_size - 1.f) / scale;\r\n            faceBox.ymax = (float)(y * pnet_stride + pnet_cell_size - 1.f) / scale;\r\n            faceInfo.bbox_reg[0] = reg_data[i];\r\n            faceInfo.bbox_reg[1] = reg_data[i + spatical_size];\r\n            faceInfo.bbox_reg[2] = reg_data[i + 2 * spatical_size];\r\n            faceInfo.bbox_reg[3] = reg_data[i + 3 * spatical_size];\r\n            faceBox.score = confidence_data[i];\r\n            candidate_boxes_.push_back(faceInfo);\r\n        }\r\n    }\r\n}\r\nstd::vector<FaceInfo> MTCNN::NMS(std::vector<FaceInfo>& bboxes,\r\n                                 float thresh, char methodType) {\r\n    std::vector<FaceInfo> bboxes_nms;\r\n    if (bboxes.size() == 0) {\r\n        return bboxes_nms;\r\n    }\r\n    std::sort(bboxes.begin(), bboxes.end(), CompareBBox);\r\n\r\n    int32_t select_idx = 0;\r\n    int32_t num_bbox = static_cast<int32_t>(bboxes.size());\r\n    std::vector<int32_t> mask_merged(num_bbox, 0);\r\n    bool all_merged = false;\r\n\r\n    while (!all_merged) {\r\n        while (select_idx < num_bbox && mask_merged[select_idx] == 1)\r\n            select_idx++;\r\n        if (select_idx == num_bbox) {\r\n            all_merged = true;\r\n            continue;\r\n        }\r\n\r\n        bboxes_nms.push_back(bboxes[select_idx]);\r\n        mask_merged[select_idx] = 1;\r\n\r\n        FaceBox select_bbox = bboxes[select_idx].bbox;\r\n        float area1 = static_cast<float>((select_bbox.xmax - select_bbox.xmin + 1) * (select_bbox.ymax - select_bbox.ymin + 1));\r\n        float x1 = static_cast<float>(select_bbox.xmin);\r\n        float y1 = static_cast<float>(select_bbox.ymin);\r\n        float x2 = static_cast<float>(select_bbox.xmax);\r\n        float y2 = static_cast<float>(select_bbox.ymax);\r\n\r\n        select_idx++;\r\n//#pragma omp parallel for num_threads(threads_num)\r\n        for (int32_t i = select_idx; i < num_bbox; i++) {\r\n            if (mask_merged[i] == 1)\r\n                continue;\r\n\r\n            FaceBox & bbox_i = bboxes[i].bbox;\r\n            float x = std::max<float>(x1, static_cast<float>(bbox_i.xmin));\r\n            float y = std::max<float>(y1, static_cast<float>(bbox_i.ymin));\r\n            float w = std::min<float>(x2, static_cast<float>(bbox_i.xmax)) - x + 1;\r\n            float h = std::min<float>(y2, static_cast<float>(bbox_i.ymax)) - y + 1;\r\n            if (w <= 0 || h <= 0)\r\n                continue;\r\n\r\n            float area2 = static_cast<float>((bbox_i.xmax - bbox_i.xmin + 1) * (bbox_i.ymax - bbox_i.ymin + 1));\r\n            float area_intersect = w * h;\r\n\r\n            switch (methodType) {\r\n                case 'u':\r\n                    if (static_cast<float>(area_intersect) / (area1 + area2 - area_intersect) > thresh)\r\n                        mask_merged[i] = 1;\r\n                    break;\r\n                case 'm':\r\n                    if (static_cast<float>(area_intersect) / std::min(area1, area2) > thresh)\r\n                        mask_merged[i] = 1;\r\n                    break;\r\n                default:\r\n                    break;\r\n            }\r\n        }\r\n    }\r\n    return bboxes_nms;\r\n}\r\n\r\nvector<FaceInfo> MTCNN::NextStage(const cv::Mat& image, vector<FaceInfo> &pre_stage_res, int input_w, int input_h, int stage_num, const float threshold) {\r\n    vector<FaceInfo> res;\r\n    int batch_size = (int)pre_stage_res.size();\r\n    if (batch_size == 0)\r\n        return res;\r\n    Mat* input_layer = nullptr;\r\n    Mat* confidence = nullptr;\r\n    Mat* reg_box = nullptr;\r\n    Mat* reg_landmark = nullptr;\r\n\r\n    std::vector< Mat > targets_blobs;\r\n\r\n\r\n\r\n    switch (stage_num) {\r\n        case 2: {\r\n//            input_layer = RNet_->input_blobs()[0];\r\n//            input_layer->Reshape(batch_size, 3, input_h, input_w);\r\n//            RNet_->Reshape();\r\n        }break;\r\n        case 3: {\r\n//            input_layer = ONet_->input_blobs()[0];\r\n//            input_layer->Reshape(batch_size, 3, input_h, input_w);\r\n//            ONet_->Reshape();\r\n        }break;\r\n        default:\r\n            return res;\r\n            break;\r\n    }\r\n//    float * input_data = input_layer->mutable_cpu_data();\r\n    int spatial_size = input_h*input_w;\r\n\r\n//#pragma omp parallel for num_threads(threads_num)\r\n\r\n    std::vector<cv::Mat> inputs;\r\n\r\n    for (int n = 0; n < batch_size; ++n) {\r\n        FaceBox &box = pre_stage_res[n].bbox;\r\n        Mat roi = image(Rect(Point((int)box.xmin, (int)box.ymin), Point((int)box.xmax, (int)box.ymax))).clone();\r\n        resize(roi, roi, Size(input_w, input_h));\r\n        inputs.push_back(roi);\r\n        //resize好的face roi 里面\r\n    }\r\n\r\n    //\r\n//    cv::Mat inputBlob = cv::dnn::blobFromImage(resized, std_val,cv::Size(),mean_val);\r\n\r\n//    cv::imshow(\"image\",inputs[0]);\r\n//    cv::waitKey(0);\r\n\r\n\r\n    Mat blob_input = dnn::blobFromImages(inputs, std_val,cv::Size(),cv::Scalar(mean_val,mean_val,mean_val),false);\r\n\r\n//    PNet_.setInput(inputBlob, \"data\");\r\n//    const std::vector< String >  targets_node{\"conv4-2\",\"prob1\"};\r\n//    std::vector< Mat > targets_blobs;\r\n//    PNet_.forward(targets_blobs,targets_node);\r\n\r\n    switch (stage_num) {\r\n        case 2: {\r\n            RNet_.setInput(blob_input, \"data\");\r\n            const std::vector< String >  targets_node{\"conv5-2\",\"prob1\"};\r\n            RNet_.forward(targets_blobs,targets_node);\r\n            confidence = &targets_blobs[1];\r\n            reg_box = &targets_blobs[0];\r\n\r\n            float* confidence_data = (float*)confidence->data;\r\n        }break;\r\n        case 3: {\r\n\r\n            ONet_.setInput(blob_input, \"data\");\r\n            const std::vector< String >  targets_node{\"conv6-2\",\"conv6-3\",\"prob1\"};\r\n            ONet_.forward(targets_blobs,targets_node);\r\n            reg_box = &targets_blobs[0];\r\n            reg_landmark = &targets_blobs[1];\r\n            confidence = &targets_blobs[2];\r\n\r\n        }break;\r\n    }\r\n\r\n\r\n    const float* confidence_data = (float*)confidence->data;\r\n//    std::cout<<\"confidence_data[0] \"<<confidence_data[0]<<std::endl;\r\n\r\n    const float* reg_data = (float*)reg_box->data;\r\n    const float* landmark_data = nullptr;\r\n    if (reg_landmark) {\r\n        landmark_data = (float*)reg_landmark->data;\r\n    }\r\n    for (int k = 0; k < batch_size; ++k) {\r\n        if (confidence_data[2 * k + 1] >= threshold) {\r\n            FaceInfo info;\r\n            info.bbox.score = confidence_data[2 * k + 1];\r\n            info.bbox.xmin = pre_stage_res[k].bbox.xmin;\r\n            info.bbox.ymin = pre_stage_res[k].bbox.ymin;\r\n            info.bbox.xmax = pre_stage_res[k].bbox.xmax;\r\n            info.bbox.ymax = pre_stage_res[k].bbox.ymax;\r\n            for (int i = 0; i < 4; ++i) {\r\n                info.bbox_reg[i] = reg_data[4 * k + i];\r\n            }\r\n            if (reg_landmark) {\r\n                float w = info.bbox.xmax - info.bbox.xmin + 1.f;\r\n                float h = info.bbox.ymax - info.bbox.ymin + 1.f;\r\n                for (int i = 0; i < 5; ++i){\r\n                    info.landmark[2 * i] = landmark_data[10 * k + 2 * i] * w + info.bbox.xmin;\r\n                    info.landmark[2 * i + 1] = landmark_data[10 * k + 2 * i + 1] * h + info.bbox.ymin;\r\n                }\r\n            }\r\n            res.push_back(info);\r\n        }\r\n    }\r\n    return res;\r\n}\r\n\r\nvector<FaceInfo> MTCNN::ProposalNet(const cv::Mat& img, int minSize, float threshold, float factor) {\r\n    cv::Mat  resized;\r\n    int width = img.cols;\r\n    int height = img.rows;\r\n    float scale = 12.f / minSize;\r\n    float minWH = std::min(height, width) *scale;\r\n    std::vector<float> scales;\r\n    while (minWH >= 12) {\r\n        scales.push_back(scale);\r\n        minWH *= factor;\r\n        scale *= factor;\r\n    }\r\n\r\n//    Mat* input_layer = PNet_->input_blobs()[0];\r\n    total_boxes_.clear();\r\n    for (int i = 0; i < scales.size(); i++) {\r\n        int ws = (int)std::ceil(width*scales[i]);\r\n        int hs = (int)std::ceil(height*scales[i]);\r\n        cv::resize(img, resized, cv::Size(ws, hs), 0, 0, cv::INTER_LINEAR);\r\n//\r\n//        input_layer->Reshape(1, 3, hs, ws);\r\n//        PNet_->Reshape();\r\n//\r\n//        float * input_data = input_layer->mutable_cpu_data();\r\n//        cv::Vec3b * img_data = (cv::Vec3b *)resized.data;\r\n//        int spatial_size = ws* hs;\r\n//        for (int k = 0; k < spatial_size; ++k) {\r\n//            input_data[k] = float((img_data[k][0] - mean_val)* std_val);\r\n//            input_data[k + spatial_size] = float((img_data[k][1] - mean_val) * std_val);\r\n//            input_data[k + 2 * spatial_size] = float((img_data[k][2] - mean_val) * std_val);\r\n//        }\r\n\r\n\r\n        cv::Mat inputBlob = cv::dnn::blobFromImage(resized, 1/255.0,cv::Size(),cv::Scalar(0,0,0),false);\r\n\r\n        float* c = (float*)inputBlob.data;\r\n        PNet_.setInput(inputBlob, \"data\");\r\n        const std::vector< cv::String >  targets_node{\"conv4-2\",\"prob1\"};\r\n        std::vector< cv::Mat > targets_blobs;\r\n        PNet_.forward(targets_blobs,targets_node);\r\n\r\n        cv::Mat prob = targets_blobs[1]\r\n        ;\r\n        cv::Mat reg = targets_blobs[0];\r\n        GenerateBBox(&prob, &reg, scales[i], threshold);\r\n//\r\n        std::vector<FaceInfo> bboxes_nms = NMS(candidate_boxes_, 0.5, 'u');\r\n        if (bboxes_nms.size()>0) {\r\n            total_boxes_.insert(total_boxes_.end(), bboxes_nms.begin(), bboxes_nms.end());\r\n        }\r\n    }\r\n    int num_box = (int)total_boxes_.size();\r\n//    std::cout<<num_box<<std::endl;\r\n\r\n    vector<FaceInfo> res_boxes;\r\n    if (num_box != 0) {\r\n        res_boxes = NMS(total_boxes_, 0.7f, 'u');\r\n        BBoxRegression(res_boxes);\r\n        BBoxPadSquare(res_boxes, width, height);\r\n    }\r\n    return res_boxes;\r\n}\r\n\r\nvector<FaceInfo> MTCNN::Detect_mtcnn(const cv::Mat& image, const int minSize, const float* threshold, const float factor, const int stage) {\r\n    vector<FaceInfo> pnet_res;\r\n    vector<FaceInfo> rnet_res;\r\n    vector<FaceInfo> onet_res;\r\n    if (stage >= 1){\r\n        pnet_res = ProposalNet(image, minSize, threshold[0], factor);\r\n    }\r\n    if (stage >= 2 && pnet_res.size()>0){\r\n        if (pnet_max_detect_num < (int)pnet_res.size()){\r\n            pnet_res.resize(pnet_max_detect_num);\r\n        }\r\n        int num = (int)pnet_res.size();\r\n        int size = (int)ceil(1.f*num / step_size);\r\n        for (int iter = 0; iter < size; ++iter){\r\n            int start = iter*step_size;\r\n            int end = min(start + step_size, num);\r\n            vector<FaceInfo> input(pnet_res.begin() + start, pnet_res.begin() + end);\r\n            vector<FaceInfo> res = NextStage(image, input, 24, 24, 2, threshold[1]);\r\n            rnet_res.insert(rnet_res.end(), res.begin(), res.end());\r\n        }\r\n        rnet_res = NMS(rnet_res, 0.4f, 'm');\r\n        BBoxRegression(rnet_res);\r\n        BBoxPadSquare(rnet_res, image.cols, image.rows);\r\n\r\n    }\r\n    if (stage >= 3 && rnet_res.size()>0){\r\n        int num = (int)rnet_res.size();\r\n        int size = (int)ceil(1.f*num / step_size);\r\n        for (int iter = 0; iter < size; ++iter){\r\n            int start = iter*step_size;\r\n            int end = min(start + step_size, num);\r\n            vector<FaceInfo> input(rnet_res.begin() + start, rnet_res.begin() + end);\r\n            vector<FaceInfo> res = NextStage(image, input, 48, 48, 3, threshold[2]);\r\n            onet_res.insert(onet_res.end(), res.begin(), res.end());\r\n        }\r\n        BBoxRegression(onet_res);\r\n        onet_res = NMS(onet_res, 0.4f, 'm');\r\n        BBoxPad(onet_res, image.cols, image.rows);\r\n\r\n    }\r\n    if (stage == 1){\r\n        return pnet_res;\r\n    }\r\n    else if (stage == 2){\r\n        return rnet_res;\r\n    }\r\n    else if (stage == 3){\r\n        return onet_res;\r\n    }\r\n    else{\r\n        return onet_res;\r\n    }\r\n}\r\n\r\nint main(int argc, char **argv)\r\n{\r\n\r\n    MTCNN detector(\"model\");\r\n    string name_list[1] = {\r\n\t\t\"test.jpg\",\r\n\t};\r\n\r\n//\tMTCNN detector(\"./model\");\r\n\tfloat factor = 0.709f;\r\n\tfloat threshold[3] = { 0.7f, 0.6f, 0.6f };\r\n\tint minSize = 12;\r\n\tfor (int n = 0; n < 1;++n){\r\n\t\tcv::Mat image = cv::imread(name_list[n], 1);\r\n\r\n        for(int i = 0 ; i < 10 ; i ++) {\r\n            double t = (double) cv::getTickCount();\r\n            vector<FaceInfo> faceInfo = detector.Detect_mtcnn(image, minSize, threshold, factor, 3);\r\n            std::cout << name_list[n] << \" time,\" << (double) (cv::getTickCount() - t) / cv::getTickFrequency() << \"s\"\r\n                      << std::endl;\r\n\r\n            for (int i = 0; i < faceInfo.size(); i++) {\r\n                int x = (int) faceInfo[i].bbox.xmin;\r\n                int y = (int) faceInfo[i].bbox.ymin;\r\n                int w = (int) (faceInfo[i].bbox.xmax - faceInfo[i].bbox.xmin + 1);\r\n                int h = (int) (faceInfo[i].bbox.ymax - faceInfo[i].bbox.ymin + 1);\r\n                cv::rectangle(image, cv::Rect(x, y, w, h), cv::Scalar(255, 0, 0), 2);\r\n            }\r\n            cv::imwrite(\"test.png\", image);\r\n            cv::imshow(\"image\", image);\r\n            cv::waitKey(0);\r\n\r\n        }\r\n\r\n\r\n    }\r\n \r\n\t \r\n\treturn 1;\r\n}\r\n"
  }
]