├── .gitignore
├── doc
├── logo.png
├── output1.jpg
├── output2.jpg
├── getting_started_01.png
├── getting_started_02.png
├── getting_started.md
└── logo.svg
├── resources
└── project
│ ├── Root.type.Files
│ ├── code.type.File.xml
│ ├── doc.type.File.xml
│ ├── test.type.File.xml
│ ├── .circleci.type.File.xml
│ ├── LICENSE.type.File.xml
│ ├── README.md.type.File.xml
│ ├── mtcnn.prj.type.File.xml
│ ├── .gitignore.type.File.xml
│ ├── code.type.File
│ │ ├── mtcnn.type.File.xml
│ │ ├── 1.type.DIR_SIGNIFIER.xml
│ │ └── mtcnn.type.File
│ │ │ ├── doc.type.File.xml
│ │ │ ├── +mtcnn.type.File.xml
│ │ │ ├── weights.type.File.xml
│ │ │ ├── 1.type.DIR_SIGNIFIER.xml
│ │ │ ├── +mtcnn.type.File
│ │ │ ├── +util.type.File.xml
│ │ │ ├── 1.type.DIR_SIGNIFIER.xml
│ │ │ ├── +util.type.File
│ │ │ │ ├── 1.type.DIR_SIGNIFIER.xml
│ │ │ │ ├── prelu.m.type.File.xml
│ │ │ │ ├── cropImage.m.type.File.xml
│ │ │ │ ├── makeSquare.m.type.File.xml
│ │ │ │ ├── preluLayer.m.type.File.xml
│ │ │ │ ├── DagNetworkStrategy.m.type.File.xml
│ │ │ │ ├── DlNetworkStrategy.m.type.File.xml
│ │ │ │ ├── NetworkStrategy.m.type.File.xml
│ │ │ │ ├── applyCorrection.m.type.File.xml
│ │ │ │ ├── calculateScales.m.type.File.xml
│ │ │ │ └── convertToDagNet.m.type.File.xml
│ │ │ ├── onet.m.type.File.xml
│ │ │ ├── pnet.m.type.File.xml
│ │ │ ├── rnet.m.type.File.xml
│ │ │ ├── Detector.m.type.File.xml
│ │ │ ├── detectFaces.m.type.File.xml
│ │ │ └── proposeRegions.m.type.File.xml
│ │ │ ├── doc.type.File
│ │ │ ├── 1.type.DIR_SIGNIFIER.xml
│ │ │ ├── helptoc.xml.type.File.xml
│ │ │ ├── GettingStarted.mlx.type.File.xml
│ │ │ └── GettingStarted.html.type.File.xml
│ │ │ ├── weights.type.File
│ │ │ ├── 1.type.DIR_SIGNIFIER.xml
│ │ │ ├── onet.mat.type.File.xml
│ │ │ ├── pnet.mat.type.File.xml
│ │ │ └── rnet.mat.type.File.xml
│ │ │ ├── Contents.m.type.File.xml
│ │ │ ├── info.xml.type.File.xml
│ │ │ └── mtcnnRoot.m.type.File.xml
│ ├── doc.type.File
│ │ ├── 1.type.DIR_SIGNIFIER.xml
│ │ ├── logo.png.type.File.xml
│ │ ├── logo.svg.type.File.xml
│ │ ├── output1.jpg.type.File.xml
│ │ ├── output2.jpg.type.File.xml
│ │ ├── getting_started.md.type.File.xml
│ │ ├── getting_started_01.png.type.File.xml
│ │ └── getting_started_02.png.type.File.xml
│ ├── test.type.File
│ │ ├── +tests.type.File.xml
│ │ ├── resources.type.File.xml
│ │ ├── 1.type.DIR_SIGNIFIER.xml
│ │ ├── +tests.type.File
│ │ │ ├── 1.type.DIR_SIGNIFIER.xml
│ │ │ ├── DetectorTest.m.type.File.xml
│ │ │ ├── UtilTest.m.type.File.xml
│ │ │ ├── DetectFacesTest.m.type.File.xml
│ │ │ ├── PerformanceTest.m.type.File.xml
│ │ │ └── ProposeRegionsTest.m.type.File.xml
│ │ ├── resources.type.File
│ │ │ ├── 1.type.DIR_SIGNIFIER.xml
│ │ │ └── ref.mat.type.File.xml
│ │ ├── mtcnnTestRoot.m.type.File.xml
│ │ └── makeDetectionReference.m.type.File.xml
│ ├── .circleci.type.File
│ │ ├── 1.type.DIR_SIGNIFIER.xml
│ │ └── config.yml.type.File.xml
│ ├── kpzhang93-MTCNN_face_detection_alignment.rights.txt.type.File.xml
│ └── generateDAGNetVersions.m.type.File.xml
│ ├── Project.xml
│ ├── uuid-888b3c04-163a-4681-b133-4e6d0607d560.xml
│ ├── ProjectData.type.Info.xml
│ ├── Root.type.Categories
│ ├── FileClassCategory.type.Category
│ │ ├── design.type.Label.xml
│ │ ├── none.type.Label.xml
│ │ ├── other.type.Label.xml
│ │ ├── test.type.Label.xml
│ │ ├── artifact.type.Label.xml
│ │ ├── derived.type.Label.xml
│ │ └── convenience.type.Label.xml
│ └── FileClassCategory.type.Category.xml
│ ├── Root.type.ProjectPath
│ └── cc5a25c3-9c36-4121-bf9f-975cb273e5c8.type.Reference.xml
│ └── Root.type.EntryPoints
│ └── 6e86f0ef-faba-4a6f-a9aa-491caaa23a05.type.EntryPoint.xml
├── test
├── resources
│ └── ref.mat
├── mtcnnTestRoot.m
├── makeDetectionReference.m
└── +tests
│ ├── RegressionTest.m
│ ├── DocTest
│ ├── ProposeRegionsTest.m
│ ├── PerformanceTest.m
│ ├── DetectFacesTest.m
│ ├── UtilTest.m
│ └── DetectorTest.m
├── code
└── mtcnn
│ ├── weights
│ ├── onet.mat
│ ├── pnet.mat
│ └── rnet.mat
│ ├── doc
│ ├── GettingStarted.mlx
│ └── helptoc.xml
│ ├── +mtcnn
│ ├── +util
│ │ ├── prelu.m
│ │ ├── NetworkStrategy.m
│ │ ├── makeSquare.m
│ │ ├── cropImage.m
│ │ ├── applyCorrection.m
│ │ ├── preluLayer.m
│ │ ├── calculateScales.m
│ │ ├── DagNetworkStrategy.m
│ │ ├── DlNetworkStrategy.m
│ │ └── convertToDagNet.m
│ ├── pnet.m
│ ├── rnet.m
│ ├── proposeRegions.m
│ ├── onet.m
│ ├── detectFaces.m
│ └── Detector.m
│ ├── mtcnnRoot.m
│ ├── Contents.m
│ └── info.xml
├── Mtcnnfacedetection.prj
├── generateDAGNetVersions.m
├── .circleci
└── config.yml
├── kpzhang93-MTCNN_face_detection_alignment.rights.txt
├── LICENSE
├── README.md
└── mtcnn.prj
/.gitignore:
--------------------------------------------------------------------------------
1 | *.mltbx
2 | code/mtcnn/weights/dag*.mat
--------------------------------------------------------------------------------
/doc/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matlab-deep-learning/mtcnn-face-detection/HEAD/doc/logo.png
--------------------------------------------------------------------------------
/resources/project/Root.type.Files/code.type.File.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/resources/project/Root.type.Files/doc.type.File.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/resources/project/Root.type.Files/test.type.File.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/doc/output1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matlab-deep-learning/mtcnn-face-detection/HEAD/doc/output1.jpg
--------------------------------------------------------------------------------
/doc/output2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matlab-deep-learning/mtcnn-face-detection/HEAD/doc/output2.jpg
--------------------------------------------------------------------------------
/resources/project/Project.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/resources/project/Root.type.Files/.circleci.type.File.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/resources/project/Root.type.Files/LICENSE.type.File.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/resources/project/Root.type.Files/README.md.type.File.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/resources/project/Root.type.Files/mtcnn.prj.type.File.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/resources/project/Root.type.Files/.gitignore.type.File.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/resources/project/uuid-888b3c04-163a-4681-b133-4e6d0607d560.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/resources/project/ProjectData.type.Info.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/resources/project/Root.type.Files/code.type.File/mtcnn.type.File.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/resources/project/Root.type.Files/doc.type.File/1.type.DIR_SIGNIFIER.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/resources/project/Root.type.Files/doc.type.File/logo.png.type.File.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/resources/project/Root.type.Files/doc.type.File/logo.svg.type.File.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/resources/project/Root.type.Files/test.type.File/+tests.type.File.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/resources/project/Root.type.Files/test.type.File/resources.type.File.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/test/resources/ref.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matlab-deep-learning/mtcnn-face-detection/HEAD/test/resources/ref.mat
--------------------------------------------------------------------------------
/resources/project/Root.type.Files/code.type.File/1.type.DIR_SIGNIFIER.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/resources/project/Root.type.Files/doc.type.File/output1.jpg.type.File.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/resources/project/Root.type.Files/doc.type.File/output2.jpg.type.File.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/resources/project/Root.type.Files/test.type.File/1.type.DIR_SIGNIFIER.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/code/mtcnn/weights/onet.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matlab-deep-learning/mtcnn-face-detection/HEAD/code/mtcnn/weights/onet.mat
--------------------------------------------------------------------------------
/code/mtcnn/weights/pnet.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matlab-deep-learning/mtcnn-face-detection/HEAD/code/mtcnn/weights/pnet.mat
--------------------------------------------------------------------------------
/code/mtcnn/weights/rnet.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matlab-deep-learning/mtcnn-face-detection/HEAD/code/mtcnn/weights/rnet.mat
--------------------------------------------------------------------------------
/doc/getting_started_01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matlab-deep-learning/mtcnn-face-detection/HEAD/doc/getting_started_01.png
--------------------------------------------------------------------------------
/doc/getting_started_02.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matlab-deep-learning/mtcnn-face-detection/HEAD/doc/getting_started_02.png
--------------------------------------------------------------------------------
/resources/project/Root.type.Files/.circleci.type.File/1.type.DIR_SIGNIFIER.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/resources/project/Root.type.Files/.circleci.type.File/config.yml.type.File.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/resources/project/Root.type.Files/code.type.File/mtcnn.type.File/doc.type.File.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/resources/project/Root.type.Files/doc.type.File/getting_started.md.type.File.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/resources/project/Root.type.Files/code.type.File/mtcnn.type.File/+mtcnn.type.File.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/resources/project/Root.type.Files/code.type.File/mtcnn.type.File/weights.type.File.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/resources/project/Root.type.Files/doc.type.File/getting_started_01.png.type.File.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/resources/project/Root.type.Files/doc.type.File/getting_started_02.png.type.File.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/code/mtcnn/doc/GettingStarted.mlx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matlab-deep-learning/mtcnn-face-detection/HEAD/code/mtcnn/doc/GettingStarted.mlx
--------------------------------------------------------------------------------
/resources/project/Root.type.Files/code.type.File/mtcnn.type.File/1.type.DIR_SIGNIFIER.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/resources/project/Root.type.Files/test.type.File/+tests.type.File/1.type.DIR_SIGNIFIER.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/resources/project/Root.type.Files/test.type.File/resources.type.File/1.type.DIR_SIGNIFIER.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/resources/project/Root.type.Files/code.type.File/mtcnn.type.File/+mtcnn.type.File/+util.type.File.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/resources/project/Root.type.Files/kpzhang93-MTCNN_face_detection_alignment.rights.txt.type.File.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/resources/project/Root.type.Files/code.type.File/mtcnn.type.File/+mtcnn.type.File/1.type.DIR_SIGNIFIER.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/resources/project/Root.type.Files/code.type.File/mtcnn.type.File/doc.type.File/1.type.DIR_SIGNIFIER.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/resources/project/Root.type.Files/code.type.File/mtcnn.type.File/weights.type.File/1.type.DIR_SIGNIFIER.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/test/mtcnnTestRoot.m:
--------------------------------------------------------------------------------
1 | function folder = mtcnnTestRoot()
2 | % Copyright 2019 The MathWorks, Inc.
3 | folder = fileparts(mfilename('fullpath'));
4 | end
--------------------------------------------------------------------------------
/resources/project/Root.type.Files/code.type.File/mtcnn.type.File/+mtcnn.type.File/+util.type.File/1.type.DIR_SIGNIFIER.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/resources/project/Root.type.Categories/FileClassCategory.type.Category/design.type.Label.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/resources/project/Root.type.Categories/FileClassCategory.type.Category/none.type.Label.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/resources/project/Root.type.Categories/FileClassCategory.type.Category/other.type.Label.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/resources/project/Root.type.Categories/FileClassCategory.type.Category/test.type.Label.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/resources/project/Root.type.Categories/FileClassCategory.type.Category/artifact.type.Label.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/resources/project/Root.type.Categories/FileClassCategory.type.Category/derived.type.Label.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/resources/project/Root.type.ProjectPath/cc5a25c3-9c36-4121-bf9f-975cb273e5c8.type.Reference.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/resources/project/Root.type.Categories/FileClassCategory.type.Category/convenience.type.Label.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/resources/project/Root.type.Categories/FileClassCategory.type.Category.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/Mtcnnfacedetection.prj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/code/mtcnn/+mtcnn/+util/prelu.m:
--------------------------------------------------------------------------------
1 | function x = prelu(x, params)
2 | % prelu Parameterized relu activation.
3 |
4 | % Copyright 2019 The MathWorks, Inc.
5 |
6 | x = max(0, x) + params.*min(0, x);
7 |
8 | end
--------------------------------------------------------------------------------
/code/mtcnn/mtcnnRoot.m:
--------------------------------------------------------------------------------
1 | function folder = mtcnnRoot()
2 | % mtcnnRoot Returns the root folder of MTCNN.
3 |
4 | % Copyright 2019 The MathWorks, Inc.
5 |
6 | folder = fileparts(mfilename('fullpath'));
7 | end
--------------------------------------------------------------------------------
/resources/project/Root.type.Files/generateDAGNetVersions.m.type.File.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/resources/project/Root.type.Files/test.type.File/mtcnnTestRoot.m.type.File.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/resources/project/Root.type.EntryPoints/6e86f0ef-faba-4a6f-a9aa-491caaa23a05.type.EntryPoint.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/resources/project/Root.type.Files/test.type.File/makeDetectionReference.m.type.File.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/resources/project/Root.type.Files/code.type.File/mtcnn.type.File/Contents.m.type.File.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/resources/project/Root.type.Files/code.type.File/mtcnn.type.File/info.xml.type.File.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/resources/project/Root.type.Files/code.type.File/mtcnn.type.File/mtcnnRoot.m.type.File.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/resources/project/Root.type.Files/test.type.File/+tests.type.File/DetectorTest.m.type.File.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/resources/project/Root.type.Files/test.type.File/+tests.type.File/UtilTest.m.type.File.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/resources/project/Root.type.Files/test.type.File/resources.type.File/ref.mat.type.File.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/resources/project/Root.type.Files/test.type.File/+tests.type.File/DetectFacesTest.m.type.File.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/resources/project/Root.type.Files/test.type.File/+tests.type.File/PerformanceTest.m.type.File.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/resources/project/Root.type.Files/code.type.File/mtcnn.type.File/+mtcnn.type.File/onet.m.type.File.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/resources/project/Root.type.Files/code.type.File/mtcnn.type.File/+mtcnn.type.File/pnet.m.type.File.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/resources/project/Root.type.Files/code.type.File/mtcnn.type.File/+mtcnn.type.File/rnet.m.type.File.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/resources/project/Root.type.Files/test.type.File/+tests.type.File/ProposeRegionsTest.m.type.File.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/resources/project/Root.type.Files/code.type.File/mtcnn.type.File/+mtcnn.type.File/Detector.m.type.File.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/resources/project/Root.type.Files/code.type.File/mtcnn.type.File/doc.type.File/helptoc.xml.type.File.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/resources/project/Root.type.Files/code.type.File/mtcnn.type.File/weights.type.File/onet.mat.type.File.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/resources/project/Root.type.Files/code.type.File/mtcnn.type.File/weights.type.File/pnet.mat.type.File.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/resources/project/Root.type.Files/code.type.File/mtcnn.type.File/weights.type.File/rnet.mat.type.File.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/resources/project/Root.type.Files/code.type.File/mtcnn.type.File/+mtcnn.type.File/detectFaces.m.type.File.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/resources/project/Root.type.Files/code.type.File/mtcnn.type.File/+mtcnn.type.File/proposeRegions.m.type.File.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/resources/project/Root.type.Files/code.type.File/mtcnn.type.File/doc.type.File/GettingStarted.mlx.type.File.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/resources/project/Root.type.Files/code.type.File/mtcnn.type.File/doc.type.File/GettingStarted.html.type.File.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/resources/project/Root.type.Files/code.type.File/mtcnn.type.File/+mtcnn.type.File/+util.type.File/prelu.m.type.File.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/resources/project/Root.type.Files/code.type.File/mtcnn.type.File/+mtcnn.type.File/+util.type.File/cropImage.m.type.File.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/resources/project/Root.type.Files/code.type.File/mtcnn.type.File/+mtcnn.type.File/+util.type.File/makeSquare.m.type.File.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/resources/project/Root.type.Files/code.type.File/mtcnn.type.File/+mtcnn.type.File/+util.type.File/preluLayer.m.type.File.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/code/mtcnn/+mtcnn/+util/NetworkStrategy.m:
--------------------------------------------------------------------------------
1 | classdef (Abstract) NetworkStrategy < handle
2 | methods
3 | load(obj)
4 | pnet = getPNet(obj)
5 | [probs, correction] = applyRNet(obj, im)
6 | [probs, correction, landmarks] = applyONet(obj, im)
7 | end
8 | end
--------------------------------------------------------------------------------
/resources/project/Root.type.Files/code.type.File/mtcnn.type.File/+mtcnn.type.File/+util.type.File/DagNetworkStrategy.m.type.File.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/resources/project/Root.type.Files/code.type.File/mtcnn.type.File/+mtcnn.type.File/+util.type.File/DlNetworkStrategy.m.type.File.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/resources/project/Root.type.Files/code.type.File/mtcnn.type.File/+mtcnn.type.File/+util.type.File/NetworkStrategy.m.type.File.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/resources/project/Root.type.Files/code.type.File/mtcnn.type.File/+mtcnn.type.File/+util.type.File/applyCorrection.m.type.File.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/resources/project/Root.type.Files/code.type.File/mtcnn.type.File/+mtcnn.type.File/+util.type.File/calculateScales.m.type.File.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/resources/project/Root.type.Files/code.type.File/mtcnn.type.File/+mtcnn.type.File/+util.type.File/convertToDagNet.m.type.File.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/code/mtcnn/Contents.m:
--------------------------------------------------------------------------------
1 | % MTCNN
2 | % Version 1.2.2 (R2020a) 14-September-2020
3 | %
4 | % Files
5 | % mtcnn.detectFaces - Use a pretrained model to detect faces in an image.
6 | % mtcnn.Detector - Create a detector object to detect faces in an image.
7 |
8 | % Copyright 2020 The MathWorks, Inc.
9 |
--------------------------------------------------------------------------------
/code/mtcnn/doc/helptoc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | MTCNN Face Detection
6 |
7 | GitHub repository
8 |
9 |
10 |
--------------------------------------------------------------------------------
/code/mtcnn/+mtcnn/+util/makeSquare.m:
--------------------------------------------------------------------------------
1 | function outBox = makeSquare(bboxes)
2 | % makeSquare Make the bounding box square.
3 |
4 | % Copyright 2019 The MathWorks, Inc.
5 |
6 | maxSide = max(bboxes(:, 3:4), [], 2);
7 | cx = bboxes(:, 1) + bboxes(:, 3)/2;
8 | cy = bboxes(:, 2) + bboxes(:, 4)/2;
9 | outBox = [cx - maxSide/2, cy - maxSide/2, maxSide, maxSide];
10 | end
--------------------------------------------------------------------------------
/test/makeDetectionReference.m:
--------------------------------------------------------------------------------
1 | function makeDetectionReference()
2 | % Run the detector in known good config to create reference boxes,
3 | % scores and landmarks for regression tests.
4 | im = imread("visionteam.jpg");
5 | [bboxes, scores, landmarks] = mtcnn.detectFaces(im);
6 |
7 | filename = fullfile(mtcnnTestRoot(), "resources", "ref.mat");
8 | save(filename, "bboxes", "scores", "landmarks");
9 |
10 | end
--------------------------------------------------------------------------------
/generateDAGNetVersions.m:
--------------------------------------------------------------------------------
1 | function generateDAGNetVersions
2 | % generate DAG net versions if not there already
3 | nets = ["p", "r", "o"];
4 | for iNet = 1:numel(nets)
5 | thisNet = nets(iNet);
6 | dagFile = fullfile(mtcnnRoot, 'weights', ...
7 | strcat('dag', char(upper(thisNet)), 'Net.mat'));
8 | if ~isfile(dagFile)
9 | net = mtcnn.util.convertToDagNet(thisNet);
10 | save(dagFile, "net");
11 | end
12 | end
--------------------------------------------------------------------------------
/code/mtcnn/+mtcnn/+util/cropImage.m:
--------------------------------------------------------------------------------
1 | function cropped = cropImage(im, bboxes, outSize)
2 | % cropImage Crop and resize image.
3 |
4 | % Copyright 2019 The MathWorks, Inc.
5 |
6 | nBoxes = size(bboxes, 1);
7 | cropped = zeros(outSize, outSize, 3, nBoxes, 'like', im);
8 | for iBox = 1:nBoxes
9 | thisBox = bboxes(iBox, :);
10 | cropped(:,:,:,iBox) = imresize(imcrop(im, thisBox), [outSize, outSize]);
11 | end
12 |
13 | end
--------------------------------------------------------------------------------
/code/mtcnn/+mtcnn/+util/applyCorrection.m:
--------------------------------------------------------------------------------
1 | function outBboxes = applyCorrection(bboxes, correction)
2 | % applyCorrection Apply bounding box regression correction.
3 |
4 | % Copyright 2019 The MathWorks, Inc.
5 |
6 | assert(all(bboxes(:, 3) == bboxes(:, 4)), ...
7 | "mtcnn:util:applyCorrection:badBox", ...
8 | "Correction assumes square bounding boxes.");
9 |
10 | scaledOffset = bboxes(:, 3).*correction;
11 | outBboxes = bboxes + scaledOffset;
12 |
13 | end
--------------------------------------------------------------------------------
/code/mtcnn/+mtcnn/pnet.m:
--------------------------------------------------------------------------------
1 | function [probability, correction] = pnet(x, weights)
2 | % pnet Apply the pnet network to a batch of images.
3 |
4 | % Copyright 2019 The MathWorks, Inc.
5 |
6 | for layer = 1:3
7 | weightName = sprintf("features_conv%d_weight", layer);
8 | biasName = sprintf("features_conv%d_bias", layer);
9 | x = dlconv(x, ...
10 | weights.(weightName), ...
11 | weights.(biasName));
12 |
13 | preluName = sprintf("features_prelu%d_weight", layer);
14 | x = mtcnn.util.prelu(x, weights.(preluName));
15 |
16 | if layer == 1
17 | x = maxpool(x, 2, "Stride", 2);
18 | end
19 | end
20 |
21 | probability = dlconv(x, weights.conv4_1_weight, weights.conv4_1_bias);
22 | correction = dlconv(x, weights.conv4_2_weight, weights.conv4_2_bias);
23 | probability = softmax(probability);
24 |
25 | end
--------------------------------------------------------------------------------
/.circleci/config.yml:
--------------------------------------------------------------------------------
1 | version: 2.1
2 | orbs:
3 | matlab: mathworks/matlab@0.3.0
4 | codecov: codecov/codecov@1.0.2
5 |
6 | jobs:
7 | test:
8 | parameters:
9 | version:
10 | description: "MATLAB version"
11 | default: "R2020b"
12 | type: string
13 | machine:
14 | image: ubuntu-1604:201903-01
15 | steps:
16 | - checkout
17 | - matlab/install:
18 | release: <>
19 | - matlab/run-tests:
20 | test-results-junit: artifacts/junit/testResults.xml
21 | code-coverage-cobertura: artifacts/coverage/codeCoverage.xml
22 | source-folder: code
23 | - store_test_results:
24 | path: artifacts/junit
25 | - store_artifacts:
26 | path: artifacts
27 | - codecov/upload:
28 | file: artifacts/coverage/codeCoverage.xml
29 |
30 | workflows:
31 | matrix-tests:
32 | jobs:
33 | - test:
34 | matrix:
35 | parameters:
36 | version:
37 | - R2020a
38 | - R2020b
39 | - R2021a
--------------------------------------------------------------------------------
/kpzhang93-MTCNN_face_detection_alignment.rights.txt:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2016 Kaipeng Zhang
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/test/+tests/RegressionTest.m:
--------------------------------------------------------------------------------
1 | classdef RegressionTest < matlab.unittest.TestCase
2 | % Test cases for known bugs that have been fixed
3 |
4 | % Copyright 2020 The MathWorks, Inc.
5 |
6 | methods (Test)
7 | function testSelectStrongestBug(test)
8 | % GitHub issue #17
9 | im = imread("visionteam1.jpg");
10 |
11 | [bboxes, scores, landmarks] = mtcnn.detectFaces(im, "ConfidenceThresholds", repmat(0.01, [3, 1]));
12 | for iBox = 1:size(bboxes, 1)
13 | test.assertInBox(landmarks(iBox, :, :), bboxes(iBox, :));
14 | end
15 | end
16 | end
17 |
18 | methods
19 | function assertInBox(test, landmarks, box)
20 | % check that all landmarks are within the bounding box
21 | tf = all(inpolygon(landmarks(1, :, 1), ...
22 | landmarks(1, :, 2), ...
23 | [box(1), box(1) + box(3), box(1) + box(3), box(1)], ...
24 | [box(2), box(2), box(2) + box(4), box(2) + box(4)]));
25 | test.assertTrue(tf, "Landmarks should all be inside bounding box");
26 | end
27 | end
28 |
29 | end
--------------------------------------------------------------------------------
/test/+tests/DocTest:
--------------------------------------------------------------------------------
1 | classdef DocTest < matlab.unittest.TestCase
2 |
3 | methods(TestClassSetup)
4 | function addDocToPath(testCase)
5 | testCase.applyFixture(PathFixture(fullfile(mtcnnRoot,'doc')));
6 | end
7 | end
8 |
9 | methods(TestMethodSetup)
10 | function captureAndCleanFigures(testCase)
11 | figs = findall(groot,'Type','figure');
12 | testCase.addTeardown(@testCase.logAndClose, figs);
13 | end
14 | end
15 | methods(Access=private)
16 | function logAndClose(testCase, figs)
17 | openedFigs = setdiff(findall(groot,'Type','figure'),figs);
18 | for fig=openedFigs'
19 | testCase.log(1,FigureDiagnostic(fig));
20 | end
21 | close(openedFigs);
22 | end
23 | end
24 |
25 | methods(Test)
26 | function executesWithoutError(~)
27 | GettingStarted;
28 | end
29 | end
30 | end
31 |
32 | function f = FigureDiagnostic(varargin)
33 | f = matlab.unittest.diagnostics.FigureDiagnostic(varargin{:});
34 | end
35 |
36 | function f = PathFixture(varargin)
37 | f = matlab.unittest.fixtures.PathFixture(varargin{:});
38 | end
39 |
--------------------------------------------------------------------------------
/code/mtcnn/info.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 | 2019b
13 |
14 | MTCNN Face Detection
15 |
16 |
17 | toolbox
18 |
19 |
20 |
21 |
22 | doc
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/code/mtcnn/+mtcnn/+util/preluLayer.m:
--------------------------------------------------------------------------------
1 | classdef preluLayer < nnet.layer.Layer
2 | % Example custom PReLU layer.
3 | % Taken from "Define Custom Deep Learning Layer with Learnable
4 | % Parameters"
5 |
6 | % Copyright 2020 The MathWorks, Inc.
7 |
8 | properties (Learnable)
9 | % Scaling coefficient
10 | Alpha
11 | end
12 |
13 | methods
14 | function layer = preluLayer(weights, name)
15 | % layer = preluLayer(numChannels, name) creates a PReLU layer
16 | % for 2-D image input with numChannels channels and specifies
17 | % the layer name.
18 |
19 | layer.Name = name;
20 | layer.Alpha = weights;
21 | end
22 |
23 | function Z = predict(layer, X)
24 | % Z = predict(layer, X) forwards the input data X through the
25 | % layer and outputs the result Z.
26 | Z = max(X,0) + layer.Alpha .* min(0,X);
27 | end
28 |
29 | function [dLdX, dLdAlpha] = backward(layer, X, ~, dLdZ, ~)
30 | dLdX = layer.Alpha .* dLdZ;
31 | dLdX(X>0) = dLdZ(X>0);
32 | dLdAlpha = min(0,X) .* dLdZ;
33 | dLdAlpha = sum(sum(dLdAlpha,1),2);
34 |
35 | % Sum over all observations in mini-batch.
36 | dLdAlpha = sum(dLdAlpha,4);
37 | end
38 | end
39 | end
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2019, The MathWorks, Inc.
2 | All rights reserved.
3 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
4 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
5 | 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
6 | 3. In all cases, the software is, and all modifications and derivatives of the software shall be, licensed to you solely for use in conjunction with MathWorks products and service offerings.
7 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
--------------------------------------------------------------------------------
/code/mtcnn/+mtcnn/rnet.m:
--------------------------------------------------------------------------------
1 | function [probability, correction] = rnet(x, weights)
2 | % rnet Apply the rnet network to a batch of images.
3 |
4 | % Copyright 2019 The MathWorks, Inc.
5 |
6 | for layer = 1:3
7 | weightName = sprintf("features_conv%d_weight", layer);
8 | biasName = sprintf("features_conv%d_bias", layer);
9 | x = dlconv(x, ...
10 | weights.(weightName), ...
11 | weights.(biasName));
12 |
13 | preluName = sprintf("features_prelu%d_weight", layer);
14 | x = mtcnn.util.prelu(x, weights.(preluName));
15 |
16 | if layer == 1 || layer == 2
17 | if layer == 1
18 | % This padding is required to replicate the default padding
19 | % from the original Caffe implementation
20 | padding = [0, 0; 2, 2];
21 | else
22 | padding = 0;
23 | end
24 | x = maxpool(x, 3, "Stride", 2, "Padding", padding);
25 | end
26 | end
27 |
28 | nBatch = size(x,4);
29 | % x = permute(stripdims(x), [4, 1, 2, 3]);
30 | % x = dlarray(reshape(x, nBatch, []), "BC");
31 |
32 | x = fullyconnect(x, weights.features_conv4_weight, weights.features_conv4_bias);
33 | x = mtcnn.util.prelu(x, weights.features_prelu4_weight);
34 | probability = fullyconnect(x, weights.conv5_1_weight, weights.conv5_1_bias);
35 | correction = fullyconnect(x, weights.conv5_2_weight, weights.conv5_2_bias);
36 | probability = softmax(probability);
37 | end
--------------------------------------------------------------------------------
/code/mtcnn/+mtcnn/+util/calculateScales.m:
--------------------------------------------------------------------------------
1 | function scales = calculateScales(im, minSize, maxSize, defaultScale, pyramidScale)
2 | % calculateScales Compute image scales for a given size range.
3 | %
4 | % Args:
5 | % im Input image
6 | % minSize Minimum pixel size for detection
7 | % maxSize Maximum pixel size for detection
8 | % defaultScale Pixel size of proposal network
9 | % pyramidScale Scale factor for image pyramid this must be
10 | % greater than 1 (optional, default = sqrt(2))
11 | %
12 | % Returns:
13 | % scales 1xn row vector of calculated pyramid scales
14 |
15 | % Copyright 2019 The MathWorks, Inc.
16 |
17 | if nargin < 5
18 | pyramidScale = sqrt(2);
19 | else
20 | assert(pyramidScale > 1, ...
21 | "mtcnn:util:calculateScales:badScale", ...
22 | "PyramidScale must be >1 but it was %f", pyramidScale);
23 | end
24 |
25 | imSize = size(im);
26 |
27 | % if maxSize is empty assume the smallest image dimension
28 | if isempty(maxSize)
29 | maxSize = min(imSize(1:2));
30 | end
31 |
32 | % Calculate min and max scaling factors required
33 | minScale = minSize/defaultScale;
34 | maxScale = maxSize/defaultScale;
35 |
36 | % Round to multiples or sqrt(2)
37 | alpha = floor(log(maxScale/minScale)/log(pyramidScale));
38 | scales = minScale.*pyramidScale.^(0:alpha);
39 | end
--------------------------------------------------------------------------------
/code/mtcnn/+mtcnn/proposeRegions.m:
--------------------------------------------------------------------------------
1 | function [bboxes, scores] = proposeRegions(im, scale, threshold, networkStrategy)
2 | % proposeRegions Generate region proposals at a given scale.
3 | %
4 | % Args:
5 | % im - Input image -1 to 1 range, type single
6 | % scale - Scale to run proposal at
7 | % threshold - Confidence threshold to accept proposal
8 | % weights - P-Net weights struct or trained network
9 | %
10 | % Returns:
11 | % bboxes - Nx4 array of bounding boxes
12 | % scores - Nx1 array of region scores
13 |
14 | % Copyright 2019 The MathWorks, Inc.
15 |
16 |
17 | % Stride of the proposal network
18 | stride = 2;
19 | % Field of view of the proposal network in pixels
20 | pnetSize = 12;
21 |
22 | im = imresize(im, 1/scale);
23 |
24 | [probability, correction] = networkStrategy.applyPNet(im);
25 |
26 | faces = probability(:,:,2) > threshold;
27 | if sum(faces, 'all') == 0
28 | bboxes = [];
29 | scores = [];
30 | return
31 | end
32 |
33 | linCoord = find(faces(:));
34 | [iY, iX] = ind2sub(size(faces), linCoord);
35 |
36 | % Generate bounding boxes from positive locations
37 | bboxes = [scale*stride*(iX - 1) + 1, scale*stride*(iY - 1) + 1];
38 | bboxes(:, 3:4) = scale*pnetSize;
39 |
40 | % Apply bounding box correction
41 | linCorrection = reshape(correction, [], 4);
42 | scaledOffset = scale*pnetSize*linCorrection(linCoord, :);
43 | bboxes = bboxes + scaledOffset;
44 |
45 | linProb = reshape(probability, [], 2);
46 | scores = linProb(linCoord, 2);
47 |
48 | end
49 |
--------------------------------------------------------------------------------
/code/mtcnn/+mtcnn/onet.m:
--------------------------------------------------------------------------------
1 | function [probability, correction, landmarks] = onet(x, weights)
2 | % onet Apply the onet network to a batch of images.
3 |
4 | % Copyright 2019 The MathWorks, Inc.
5 |
6 | for layer = 1:4
7 | weightName = sprintf("features_conv%d_weight", layer);
8 | biasName = sprintf("features_conv%d_bias", layer);
9 | x = dlconv(x, ...
10 | weights.(weightName), ...
11 | weights.(biasName));
12 |
13 | preluName = sprintf("features_prelu%d_weight", layer);
14 | x = mtcnn.util.prelu(x, weights.(preluName));
15 |
16 | if layer < 4
17 | if layer == 3
18 | kernel = 2;
19 | else
20 | kernel = 3;
21 | end
22 | if layer == 1
23 | % This padding is required to replicate the default padding
24 | % from the original Caffe implementation
25 | padding = [0, 0; 2, 2];
26 | else
27 | padding = 0;
28 | end
29 | x = maxpool(x, kernel, "Stride", 2, "Padding", padding);
30 | end
31 | end
32 |
33 | x = fullyconnect(x, weights.features_conv5_weight, weights.features_conv5_bias);
34 | % inference only so no dropout
35 | x = mtcnn.util.prelu(x, weights.features_prelu5_weight);
36 |
37 | probability = fullyconnect(x, weights.conv6_1_weight, weights.conv6_1_bias);
38 | correction = fullyconnect(x, weights.conv6_2_weight, weights.conv6_2_bias);
39 | landmarks = fullyconnect(x, weights.conv6_3_weight, weights.conv6_3_bias);
40 | probability = softmax(probability);
41 | end
42 |
--------------------------------------------------------------------------------
/code/mtcnn/+mtcnn/+util/DagNetworkStrategy.m:
--------------------------------------------------------------------------------
1 | classdef DagNetworkStrategy < handle
2 |
3 | properties (SetAccess=private)
4 | % Trained Dag networks
5 | Pnet
6 | Rnet
7 | Onet
8 | ExecutionEnvironment
9 | end
10 |
11 | methods
12 | function obj = DagNetworkStrategy(useGpu)
13 | if useGpu
14 | obj.ExecutionEnvironment = "gpu";
15 | else
16 | obj.ExecutionEnvironment = "cpu";
17 | end
18 | end
19 |
20 | function load(obj)
21 | % loadWeights Load the network weights from file.
22 | obj.Pnet = importdata(fullfile(mtcnnRoot(), "weights", "dagPNet.mat"));
23 | obj.Rnet = importdata(fullfile(mtcnnRoot(), "weights", "dagRNet.mat"));
24 | obj.Onet = importdata(fullfile(mtcnnRoot(), "weights", "dagONet.mat"));
25 | end
26 |
27 | function [probability, correction] = applyPNet(obj, im)
28 | % need to use activations as we don't know what size it will be
29 | result = obj.Pnet.activations(im, "concat", ...
30 | "ExecutionEnvironment", obj.ExecutionEnvironment);
31 |
32 | probability = result(:,:,1:2,:);
33 | correction = result(:,:,3:end,:);
34 | end
35 |
36 | function [probs, correction] = applyRNet(obj, im)
37 | output = obj.Rnet.predict(im, "ExecutionEnvironment", obj.ExecutionEnvironment);
38 |
39 | probs = output(:,1:2);
40 | correction = output(:,3:end);
41 | end
42 |
43 | function [probs, correction, landmarks] = applyONet(obj, im)
44 | output = obj.Onet.predict(im, "ExecutionEnvironment", obj.ExecutionEnvironment);
45 |
46 | probs = output(:,1:2);
47 | correction = output(:,3:6);
48 | landmarks = output(:,7:end);
49 | end
50 |
51 | end
52 | end
--------------------------------------------------------------------------------
/test/+tests/ProposeRegionsTest.m:
--------------------------------------------------------------------------------
1 | classdef ProposeRegionsTest < matlab.unittest.TestCase
2 | % Test propose regions function
3 |
4 | % Copyright 2020 The MathWorks, Inc.
5 |
6 | properties (Constant)
7 | Image = single(imread("visionteam.jpg"))/255*2 - 1
8 | end
9 |
10 | properties (TestParameter)
11 | getNet = struct("dl", @() mtcnn.util.DlNetworkStrategy(false) , ...
12 | "dag", @() mtcnn.util.DagNetworkStrategy(false));
13 | end
14 |
15 | methods (Test)
16 | function testOutputs(test, getNet)
17 | scale = 2;
18 | conf = 0.5;
19 | strategy = getNet();
20 | strategy.load();
21 |
22 | [box, score] = mtcnn.proposeRegions(test.Image, scale, conf, strategy);
23 |
24 | test.verifyOutputs(box, score);
25 | end
26 |
27 | function test1DActivations(test, getNet)
28 | % Test for bug #6 (1xn activations causes proposeRegions to
29 | % fail)
30 | cropped = imcrop(test.Image, [300, 42, 65, 38]);
31 | scale = 3;
32 | conf = 0.5;
33 | strategy = getNet();
34 | strategy.load();
35 |
36 | [box, score] = mtcnn.proposeRegions(cropped, scale, conf, strategy);
37 |
38 | test.verifyOutputs(box, score);
39 | end
40 | end
41 |
42 | methods
43 | function verifyOutputs(test, box, score)
44 | % helper to check expected outputs of proposeRegions
45 | test.verifyEqual(size(box, 2), 4, ...
46 | "first output should be nx4 bounding box list");
47 | test.verifyEqual(size(score, 2), 1, ...
48 | "second output should be nx1 face probabilities");
49 | test.verifyEqual(size(box, 1), size(score, 1), ...
50 | "should be 1 box for each probability");
51 | end
52 | end
53 |
54 | end
55 |
--------------------------------------------------------------------------------
/test/+tests/PerformanceTest.m:
--------------------------------------------------------------------------------
1 | classdef PerformanceTest < matlab.perftest.TestCase
2 | % Test the run-time performance of face detection.
3 |
4 | % Copyright 2019 The MathWorks, Inc.
5 |
6 | properties
7 | Image
8 | Reference
9 | end
10 |
11 | properties (TestParameter)
12 | imSize = struct('small', 0.5, 'med', 1, 'large', 2);
13 | imFaces = {'few', 'many'};
14 | end
15 |
16 | methods (TestClassSetup)
17 | function setupTestImage(test)
18 | test.Image = imread("visionteam.jpg");
19 | end
20 |
21 | function loadReference(test)
22 | test.Reference = load(fullfile(mtcnnTestRoot(), ...
23 | "resources", ...
24 | "ref.mat"));
25 | end
26 | end
27 |
28 | methods (Test)
29 | function testDefaultDetect(test, imSize, imFaces)
30 |
31 | switch imFaces
32 | case 'few'
33 | im = test.Image;
34 | case 'many'
35 | im = repmat(test.Image(25:125, :, :), [4, 1]);
36 | end
37 | im = imresize(im, imSize);
38 |
39 | test.startMeasuring();
40 | [bboxes, scores, landmarks] = mtcnn.detectFaces(im);
41 | test.stopMeasuring();
42 | end
43 |
44 | function testLowLevelDetect(test, imSize, imFaces)
45 |
46 | switch imFaces
47 | case 'few'
48 | im = test.Image;
49 | case 'many'
50 | im = repmat(test.Image(25:125, :, :), [4, 1]);
51 | end
52 | im = imresize(im, imSize);
53 |
54 | detector = mtcnn.Detector();
55 |
56 | test.startMeasuring();
57 | [bboxes, scores, landmarks] = detector.detect(im);
58 | test.stopMeasuring();
59 | end
60 | end
61 |
62 | end
--------------------------------------------------------------------------------
/code/mtcnn/+mtcnn/detectFaces.m:
--------------------------------------------------------------------------------
1 | function [bboxes, scores, landmarks] = detectFaces(im, varargin)
2 | % detectFaces Use a pretrained model to detect faces in an image.
3 | %
4 | % Args:
5 | % im - RGB input image for detection
6 | %
7 | % Returns:
8 | % bbox - nx4 array of face bounding boxes in the
9 | % format [x, y, w, h]
10 | % scores - nx1 array of face probabilities
11 | % landmarks - nx5x2 array of facial landmarks
12 | %
13 | % Name-Value pairs:
14 | % detectFaces also takes the following optional Name-Value pairs:
15 | % - MinSize - Approx. min size in pixels
16 | % (default=24)
17 | % - MaxSize - Approx. max size in pixels
18 | % (default=[])
19 | % - PyramidScale - Pyramid scales for region proposal
20 | % (default=sqrt(2))
21 | % - ConfidenceThresholds - Confidence threshold at each stage of detection
22 | % (default=[0.6, 0.7, 0.8])
23 | % - NmsThresholds - Non-max suppression overlap thresholds
24 | % (default=[0.5, 0.5, 0.5])
25 | % - UseGPU - Use GPU for processing or not
26 | % (default=false)
27 | % - UseDagNet - Use DAGNetwork for prediction (for
28 | % compatibility with R2019a)
29 | % (default=false R2019b+, =true R2019a)
30 | %
31 | % Note:
32 | % The 5 landmarks detector are in the order:
33 | % - Left eye, right eye, nose, left mouth corner, right mouth corner
34 | % The final 2 dimensions correspond to x and y co-ords.
35 | %
36 | % See also: mtcnn.Detector.detect
37 |
38 | % Copyright 2019 The MathWorks, Inc.
39 |
40 | detector = mtcnn.Detector(varargin{:});
41 | [bboxes, scores, landmarks] = detector.detect(im);
42 | end
--------------------------------------------------------------------------------
/test/+tests/DetectFacesTest.m:
--------------------------------------------------------------------------------
1 | classdef DetectFacesTest < matlab.unittest.TestCase
2 | % Test the high-level api for detecting faces.
3 |
4 | % Copyright 2019 The MathWorks, Inc.
5 |
6 | properties
7 | Image
8 | Reference
9 | end
10 |
11 | methods (TestClassSetup)
12 | function setupTestImage(test)
13 | test.Image = imread("visionteam.jpg");
14 | end
15 |
16 | function loadReference(test)
17 | test.Reference = load(fullfile(mtcnnTestRoot(), ...
18 | "resources", ...
19 | "ref.mat"));
20 | end
21 | end
22 |
23 | methods (Test)
24 | function testDefaultDetect(test)
25 | [bboxes, scores, landmarks] = mtcnn.detectFaces(test.Image);
26 |
27 | test.assertEqual(size(bboxes), [6, 4]);
28 | test.assertEqual(size(scores), [6, 1]);
29 | test.assertEqual(size(landmarks), [6, 5, 2]);
30 |
31 | test.assertEqual(bboxes, test.Reference.bboxes, "RelTol", 1e-6);
32 | test.assertEqual(scores, test.Reference.scores, "RelTol", 1e-6);
33 | test.assertEqual(landmarks, test.Reference.landmarks, "RelTol", 1e-6);
34 | end
35 |
36 | function testDetectWithOptions(test)
37 | % We should be able to pass name value paris to detect faces
38 | opts = {"MinSize", 20, ...
39 | "MaxSize", 100, ...
40 | "PyramidScale", 1.5, ...
41 | "ConfidenceThresholds", [0.6, 0.6, 0.6], ...
42 | "NmsThresholds", [0.6, 0.6, 0.6]};
43 |
44 | [bboxes, scores, landmarks] = mtcnn.detectFaces(test.Image, opts{:});
45 |
46 | test.assertEqual(size(bboxes), [6, 4]);
47 | test.assertEqual(size(scores), [6, 1]);
48 | test.assertEqual(size(landmarks), [6, 5, 2]);
49 | end
50 | end
51 |
52 | end
--------------------------------------------------------------------------------
/code/mtcnn/+mtcnn/+util/DlNetworkStrategy.m:
--------------------------------------------------------------------------------
1 | classdef DlNetworkStrategy < handle
2 |
3 | properties (SetAccess=private)
4 | UseGPU
5 | % Weights for the networks
6 | PnetWeights
7 | RnetWeights
8 | OnetWeights
9 | end
10 |
11 | methods
12 | function obj = DlNetworkStrategy(useGpu)
13 | obj.UseGPU = useGpu;
14 | end
15 |
16 | function load(obj)
17 | % loadWeights Load the network weights from file.
18 | obj.PnetWeights = load(fullfile(mtcnnRoot(), "weights", "pnet.mat"));
19 | obj.RnetWeights = load(fullfile(mtcnnRoot(), "weights", "rnet.mat"));
20 | obj.OnetWeights = load(fullfile(mtcnnRoot(), "weights", "onet.mat"));
21 |
22 | if obj.UseGPU
23 | obj.PnetWeights = dlupdate(@gpuArray, obj.PnetWeights);
24 | obj.RnetWeights = dlupdate(@gpuArray, obj.RnetWeights);
25 | obj.OnetWeights = dlupdate(@gpuArray, obj.OnetWeights);
26 | end
27 | end
28 |
29 | function [probability, correction] = applyPNet(obj, im)
30 | im = dlarray(im, "SSCB");
31 |
32 | [probability, correction] = mtcnn.pnet(im, obj.PnetWeights);
33 |
34 | probability = extractdata(gather(probability));
35 | correction = extractdata(gather(correction));
36 | end
37 |
38 | function [probs, correction] = applyRNet(obj, im)
39 | im = dlarray(im, "SSCB");
40 |
41 | [probs, correction] = mtcnn.rnet(im, obj.RnetWeights);
42 |
43 | probs = extractdata(probs)';
44 | correction = extractdata(correction)';
45 | end
46 |
47 | function [probs, correction, landmarks] = applyONet(obj, im)
48 | im = dlarray(im, "SSCB");
49 |
50 | [probs, correction, landmarks] = mtcnn.onet(im, obj.OnetWeights);
51 |
52 | probs = extractdata(probs)';
53 | correction = extractdata(correction)';
54 | landmarks = extractdata(landmarks)';
55 | end
56 |
57 | end
58 | end
--------------------------------------------------------------------------------
/doc/getting_started.md:
--------------------------------------------------------------------------------
1 | ### Getting started
2 |
3 | This example shows how to run face detection and alignment on an image.
4 |
5 | ### Face detection
6 |
7 | The simplest way to use the face detector is the function
8 | mtcnn.detectFaces this takes in an image and returns bounding boxes,
9 | probability scores, and facial landmarks for each face detected.
10 |
11 | ``` matlab
12 | im = imread("visionteam1.jpg");
13 | [bboxes, scores, landmarks] = mtcnn.detectFaces(im);
14 | fprintf("Found %d faces.\n", numel(scores));
15 | ```
16 |
17 | ``` output
18 | Found 6 faces.
19 | ```
20 |
21 | To visualise the results we can superimpose the bounding boxes and
22 | landmarks on the original
23 | image.
24 |
25 | ``` matlab
26 | displayIm = insertObjectAnnotation(im, "rectangle", bboxes, scores, "LineWidth", 2);
27 | imshow(displayIm)
28 | hold on
29 | for iFace = 1:numel(scores)
30 | scatter(landmarks(iFace, :, 1), landmarks(iFace, :, 2), 'filled');
31 | end
32 | ```
33 |
34 | 
35 |
36 | ### Facial landmarks
37 |
38 | Landmarks detected are returned in the following order:
39 |
40 | 1. Left eye
41 | 2. Right eye
42 | 3. Nose
43 | 4. Left mouth corner
44 | 5. Right mouth corner
45 |
46 | Where left and right are as observed by camera.
47 |
48 | ``` matlab
49 | figure();
50 | imshow(im);
51 | xlim([95, 150])
52 | ylim([115, 185])
53 | hold on
54 | scatter(landmarks(2, :, 1), landmarks(2, :, 2), 100, "r", "filled");
55 | text(landmarks(2, :, 1)+3, landmarks(2, :, 2)-1, string(1:5), "FontSize", 25);
56 | ```
57 |
58 | 
59 |
60 | ### Detection speed
61 |
62 | For best detection speed you should manually create a detector object
63 | using mtcnn.Detector, then call its detect method. This will ensure that
64 | network parameters are loaded before the actual detection occurs.
65 |
66 | ``` matlab
67 | detector = mtcnn.Detector();
68 | tic();
69 | [~, scores, ~] = detector.detect(im);
70 | timeTaken = toc();
71 | fprintf("Found %d faces in %.3f seconds.\n", numel(scores), timeTaken);
72 | ```
73 |
74 | ``` output
75 | Found 6 faces in 0.544 seconds.
76 | ```
77 |
78 | If you know the expected scale of your face there are also several
79 | Name-Value optional arguments which can be used to control the details
80 | of face
81 | detection
82 |
83 | ``` matlab
84 | detector = mtcnn.Detector("MinSize", 24, "MaxSize", 48, "PyramidScale", 2);
85 | tic();
86 | [~, scores, ~] = detector.detect(im);
87 | timeTaken = toc();
88 | fprintf("Found %d faces in %.3f seconds.\n", numel(scores), timeTaken);
89 | ```
90 |
91 | ``` output
92 | Found 6 faces in 0.209 seconds.
93 | ```
94 |
95 | If you have a GPU on your machine, you might see further perfromance
96 | improvments by setting "UseGPU" to true. For more details of these
97 | parameters type help mtcnn.detectFaces.
98 |
99 | _Copyright 2019 The MathWorks, Inc._
--------------------------------------------------------------------------------
/test/+tests/UtilTest.m:
--------------------------------------------------------------------------------
1 | classdef UtilTest < matlab.unittest.TestCase
2 | % Test helper functions in the util package.
3 |
4 | % Copyright 2019 The MathWorks, Inc.
5 |
6 | methods (Test)
7 | function testCalcScales(test)
8 | im = zeros(50, 50, 3);
9 | defaultScale = 12;
10 | minSize = 12;
11 | maxSize = [];
12 | expectedScales = [1, sqrt(2), 2, 2*sqrt(2), 4];
13 |
14 | scales = mtcnn.util.calculateScales(im, minSize, maxSize, defaultScale);
15 |
16 | test.verifyEqual(scales, expectedScales, "RelTol", 1e-10);
17 | end
18 |
19 | function testCalcScalesSetMax(test)
20 | im = zeros(50, 50, 3);
21 | defaultScale = 12;
22 | minSize = 12;
23 | maxSize = 34;
24 | expectedScales = [1, sqrt(2), 2, 2*sqrt(2)];
25 |
26 | scales = mtcnn.util.calculateScales(im, minSize, maxSize, defaultScale);
27 |
28 | test.verifyEqual(scales, expectedScales, "RelTol", 1e-10);
29 | end
30 |
31 | function testCalcScalesSetMin(test)
32 | im = zeros(50, 50, 3);
33 | defaultScale = 12;
34 | minSize = 24;
35 | maxSize = 34;
36 | expectedScales = [2, 2*sqrt(2)];
37 |
38 | scales = mtcnn.util.calculateScales(im, minSize, maxSize, defaultScale);
39 |
40 | test.verifyEqual(scales, expectedScales, "RelTol", 1e-10);
41 | end
42 |
43 | function testCalcScalesPyramidScale(test)
44 | im = zeros(50, 50, 3);
45 | defaultScale = 12;
46 | minSize = 12;
47 | maxSize = [];
48 | pyramidScale = 2;
49 | expectedScales = [1, 2, 4];
50 |
51 | scales = mtcnn.util.calculateScales(im, minSize, maxSize, ...
52 | defaultScale, pyramidScale);
53 |
54 | test.verifyEqual(scales, expectedScales, "RelTol", 1e-10);
55 | end
56 |
57 | function testCalcScalesPyramidScaleLessThanOne(test)
58 | im = zeros(50, 50, 3);
59 | defaultScale = 12;
60 | minSize = 12;
61 | maxSize = [];
62 | pyramidScale = 0.1;
63 |
64 | calcScales = @() mtcnn.util.calculateScales(im, minSize, maxSize, ...
65 | defaultScale, pyramidScale);
66 |
67 | test.verifyError(calcScales, "mtcnn:util:calculateScales:badScale")
68 | end
69 |
70 | function testMakeSquare(test)
71 | bbox = [1, 2, 3, 4];
72 | expectedBox = [0.5, 2, 4, 4];
73 |
74 | resizedBox = mtcnn.util.makeSquare(bbox);
75 |
76 | test.verifyEqual(resizedBox, expectedBox);
77 | end
78 |
79 | function testApplyCorrection(test)
80 | bbox = [1, 2, 3, 3];
81 | correction = [0, -0.5, 0.5, 1];
82 | expected = [1, 0.5, 4.5, 6];
83 |
84 | corrected = mtcnn.util.applyCorrection(bbox, correction);
85 |
86 | test.verifyEqual(corrected, expected);
87 | end
88 | end
89 | end
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Face Detection and Alignment MTCNN
2 |
3 | 
4 | [](https://codecov.io/gh/matlab-deep-learning/mtcnn-face-detection)
5 |
6 | ## [__Download the toolbox here__](https://github.com/matlab-deep-learning/mtcnn-face-detection/releases/latest/download/MTCNN-Face-Detection.mltbx)
7 |
8 | This repository implements a deep-learning based face detection and facial landmark localization model using [multi-task cascaded convolutional neural networks (MTCNNs)](https://kpzhang93.github.io/MTCNN_face_detection_alignment/).
9 |
10 | - [📦 Installation](#installation)
11 | - [🏁 Getting Started](#getting-started)
12 | - [🔎😄 Usage](#usage)
13 | - [❓ About](#about)
14 | - [💬 Contribute](#contribute)
15 |
16 | _Note: This code supports inference using a pretrained model. Training from scratch is not supported. Weights are imported from the [original MTCNN model](https://kpzhang93.github.io/MTCNN_face_detection_alignment/) trained in Caffe._
17 |
18 | ## Installation
19 |
20 | - Face Detection and Alignment MTCNN requires the following products:
21 | - MATLAB R2019a or later (_now works in R2019a and later!_)
22 | - Deep Learning Toolbox
23 | - Computer Vision Toolbox
24 | - Image Processing Toolbox
25 | - Download the [latest release](https://github.com/matlab-deep-learning/mtcnn-face-detection/releases/) of the Face Detection and Aligment MTCNN. To install, open the .mltbx file in MATLAB.
26 |
27 | ## Getting Started
28 |
29 | To get started using the pretrained face detector, import an image and use the `mtcnn.detectFaces` function:
30 |
31 | ```matlab
32 | im = imread("visionteam.jpg");
33 | [bboxes, scores, landmarks] = mtcnn.detectFaces(im);
34 | ```
35 |
36 | This returns the bounding boxes, probabilities, and five-point facial landmarks for each face detected in the image.
37 |
38 | 
39 |
40 | ## Usage
41 |
42 | The `detectFaces` function supports various optional arguments. For more details, refer to the help documentation for this function by typing `help mtcnn.detectFaces` at the command window.
43 |
44 | To get the best speed performance from the detector, first create a `mtcnn.Detector` object, then call its `detect` method on your image. Doing so ensures that the pretrained weights and options are loaded before calling detect:
45 |
46 | ```matlab
47 | detector = mtcnn.Detector();
48 | [bboxes, scores, landmarks] = detector.detect(im);
49 | ```
50 |
51 | The detector object accepts the same optional arguments as the `mtcnn.detectFaces` function.
52 |
53 | Refer to the MATLAB toolbox documentation or [click here](docs/getting_started.md) for a complete example.
54 |
55 | ## About
56 |
57 | The MTCNN face detector is fast and accurate. Evaluation on the [WIDER face benchmark](http://mmlab.ie.cuhk.edu.hk/projects/WIDERFace/WiderFace_Results.html) shows significant performance gains over non-deep learning face detection methods. Prediction speed depends on the image, dimensions, pyramid scales, and hardware (i.e. CPU or GPU). On a typical CPU, for VGA resolution images, a frame rates ~10 fps should be achievable.
58 |
59 | In comparisson to MATLAB's built in `vision.CascadeObjectDetector` the MTCNN detector is more robust to facial pose as demonstrated in the image below.
60 |
61 | 
62 |
63 | _Face detection from MTCNN in yellow, detections from the built in vision.CascadeObjectDetector in teal._
64 |
65 |
66 | ## Contribute
67 |
68 | Please file any bug reports or feature requests as [GitHub issues](https://github.com/matlab-deep-learning/mtcnn-face-detection/issues). In particular if you'd be interested in training your own MTCNN network comment on the following issue: [Support training MTCNN](https://github.com/matlab-deep-learning/mtcnn-face-detection/issues/1)
69 |
70 | _Copyright 2019 The MathWorks, Inc._
71 |
--------------------------------------------------------------------------------
/code/mtcnn/+mtcnn/+util/convertToDagNet.m:
--------------------------------------------------------------------------------
1 | function net = convertToDagNet(stage)
2 |
3 | warnId = "deep:functionToLayerGraph:Placeholder";
4 | warnState = warning('off', warnId);
5 | restoreWarn = onCleanup(@() warning(warnState));
6 |
7 | switch stage
8 | case "p"
9 | inputSize = 12;
10 | nBlocks = 3;
11 | finalConnections = [sprintf("conv_%d", nBlocks), sprintf("prelu_%d", nBlocks)];
12 | catConnections = ["sm_1", "conv_5"];
13 | case "r"
14 | inputSize = 24;
15 | nBlocks = 4;
16 | finalConnections = ["fc_1", sprintf("prelu_%d", nBlocks)];
17 | catConnections = ["sm_1", "fc_3"];
18 | case "o"
19 | inputSize = 48;
20 | nBlocks = 5;
21 | finalConnections = ["fc_1", sprintf("prelu_%d", nBlocks)];
22 | catConnections = ["sm_1", "fc_3", "fc_4"];
23 | otherwise
24 | error("mtcnn:convertToDagNet:unknownStage", ...
25 | "Stage '%s' is not recognised", stage)
26 | end
27 |
28 | matFilename = strcat(stage, "net.mat");
29 | weightsFile = load(fullfile(mtcnnRoot, "weights", matFilename));
30 | input = dlarray(zeros(inputSize, inputSize, 3, "single"), "SSCB");
31 |
32 | switch stage
33 | case "p"
34 | netFunc = @(x) mtcnn.pnet(x, weightsFile);
35 | [a, b] = netFunc(input);
36 | output = cat(3, a, b);
37 | case "r"
38 | netFunc = @(x) mtcnn.rnet(x, weightsFile);
39 | [a, b] = netFunc(input);
40 | output = cat(1, a, b);
41 | case "o"
42 | netFunc = @(x) mtcnn.onet(x, weightsFile);
43 | [a, b, c] = netFunc(input);
44 | output = cat(1, a, b, c);
45 | end
46 |
47 | if verLessThan('matlab', '9.9')
48 | lgraph = functionToLayerGraph(netFunc, input);
49 | else
50 | lgraph = functionToLayerGraph(netFunc, input, "GenerateLayer", "placeholder-layer");
51 | end
52 | placeholders = findPlaceholderLayers(lgraph);
53 | lgraph = removeLayers(lgraph, {placeholders.Name});
54 |
55 | for iPrelu = 1:nBlocks
56 | name = sprintf("prelu_%d", iPrelu);
57 | weightName = sprintf("features_prelu%d_weight", iPrelu);
58 | if iPrelu ~= nBlocks
59 | weights = weightsFile.(weightName);
60 | else
61 | weights = reshape(weightsFile.(weightName), 1, 1, []);
62 | end
63 | prelu = mtcnn.util.preluLayer(weights, name);
64 | lgraph = replaceLayer(lgraph, sprintf("plus_%d", iPrelu), prelu, "ReconnectBy", "order");
65 |
66 | if iPrelu ~= nBlocks
67 | lgraph = connectLayers(lgraph, sprintf("conv_%d", iPrelu), sprintf("prelu_%d", iPrelu));
68 | else
69 | % need to make different connections at the end of the
70 | % repeating blocks
71 | for iConnection = 1:size(finalConnections, 1)
72 | lgraph = connectLayers(lgraph, ...
73 | finalConnections(iConnection, 1), ...
74 | finalConnections(iConnection, 2));
75 | end
76 |
77 | end
78 | end
79 |
80 | lgraph = addLayers(lgraph, imageInputLayer([inputSize, inputSize, 3], ...
81 | "Name", "input", ...
82 | "Normalization", "none"));
83 | lgraph = connectLayers(lgraph, "input", "conv_1");
84 |
85 | lgraph = addLayers(lgraph, concatenationLayer(3, numel(catConnections), "Name", "concat"));
86 | for iConnection = 1:numel(catConnections)
87 | lgraph = connectLayers(lgraph, ...
88 | catConnections(iConnection), ...
89 | sprintf("concat/in%d", iConnection));
90 | end
91 | lgraph = addLayers(lgraph, regressionLayer("Name", "output"));
92 | lgraph = connectLayers(lgraph, "concat", "output");
93 |
94 | net = assembleNetwork(lgraph);
95 | result = net.predict(zeros(inputSize, inputSize, 3, "single"));
96 |
97 | difference = extractdata(sum(output - result', "all"));
98 |
99 | assert(difference < 1e-6, ...
100 | "mtcnn:convertToDagNet:outputMismatch", ...
101 | "Outputs of function and dag net do not match")
102 | end
--------------------------------------------------------------------------------
/test/+tests/DetectorTest.m:
--------------------------------------------------------------------------------
1 | classdef DetectorTest < matlab.unittest.TestCase
2 | % Test cases for Detector class.
3 |
4 | % Copyright 2019 The MathWorks, Inc.
5 |
6 | properties
7 | Image
8 | Reference
9 | end
10 |
11 | properties (TestParameter)
12 | imageTypeConversion = struct("uint8", @(x) x, ...
13 | "single", @(x) single(x)/255, ...
14 | "double", @(x) double(x)/255)
15 | useDagNet = {false, true}
16 | end
17 |
18 | methods (TestClassSetup)
19 | function setupTestImage(test)
20 | test.Image = imread("visionteam.jpg");
21 | end
22 |
23 | function loadReference(test)
24 | test.Reference = load(fullfile(mtcnnTestRoot(), ...
25 | "resources", ...
26 | "ref.mat"));
27 | end
28 | end
29 |
30 | methods (Test)
31 |
32 | function testCreate(test)
33 | detector = mtcnn.Detector();
34 | end
35 |
36 | function testDetectwithDefaults(test, imageTypeConversion, useDagNet)
37 | % Test expected inputs with images of type uint8, single,
38 | % double (float images are scaled 0-1);
39 | detector = mtcnn.Detector("UseDagNet", useDagNet);
40 |
41 | inputImage = imageTypeConversion(test.Image);
42 |
43 | [bboxes, scores, landmarks] = detector.detect(inputImage);
44 |
45 | test.verifyEqual(size(bboxes), [6, 4]);
46 | test.verifyEqual(size(scores), [6, 1]);
47 | test.verifyEqual(size(landmarks), [6, 5, 2]);
48 |
49 | test.verifyEqual(bboxes, test.Reference.bboxes, "RelTol", 1e-6);
50 | test.verifyEqual(scores, test.Reference.scores, "RelTol", 1e-6);
51 | test.verifyEqual(landmarks, test.Reference.landmarks, "RelTol", 1e-6);
52 | end
53 |
54 | %% Pyramid parameters
55 | function testMinSize(test)
56 | detector = mtcnn.Detector("MinSize", 240);
57 | [bboxes, scores, landmarks] = detector.detect(test.Image);
58 |
59 | test.verifyEmpty(bboxes);
60 | test.verifyEmpty(scores);
61 | test.verifyEmpty(landmarks);
62 | end
63 |
64 | function testMinMinSize(test)
65 | createDetector = @() mtcnn.Detector("MinSize", 1);
66 |
67 | test.verifyError(createDetector, "MATLAB:validators:mustBeGreaterThan")
68 | end
69 |
70 | function testMaxSize(test)
71 | detector = mtcnn.Detector("MaxSize", 12);
72 | [bboxes, scores, landmarks] = detector.detect(test.Image);
73 |
74 | test.verifyEmpty(bboxes);
75 | test.verifyEmpty(scores);
76 | test.verifyEmpty(landmarks);
77 | end
78 |
79 | function testDetectwithMoreScales(test)
80 | detector = mtcnn.Detector("PyramidScale", sqrt(1.5));
81 |
82 | [bboxes, scores, landmarks] = detector.detect(test.Image);
83 |
84 | test.verifyEqual(size(bboxes), [6, 4]);
85 | test.verifyEqual(size(scores), [6, 1]);
86 | test.verifyEqual(size(landmarks), [6, 5, 2]);
87 |
88 | boxOverlaps = bboxOverlapRatio(bboxes, test.Reference.bboxes);
89 | test.verifyEqual(max(boxOverlaps) > 0.8, true(1, 6));
90 | test.verifyEqual(scores, test.Reference.scores, "RelTol", 1e-3);
91 | end
92 |
93 | %% Thresholds
94 | function testConfThresholds(test)
95 | detector = mtcnn.Detector("ConfidenceThresholds", [0.8, 0.8, 0.9]);
96 |
97 | [bboxes, scores, landmarks] = detector.detect(test.Image);
98 |
99 | test.verifyNotEmpty(bboxes);
100 | test.verifyNotEmpty(scores);
101 | test.verifyNotEmpty(landmarks);
102 | end
103 |
104 | function testNmsThresholds(test)
105 | detector = mtcnn.Detector("NmsThresholds", [0.4, 0.4, 0.4]);
106 |
107 | [bboxes, scores, landmarks] = detector.detect(test.Image);
108 |
109 | test.verifyNotEmpty(bboxes);
110 | test.verifyNotEmpty(scores);
111 | test.verifyNotEmpty(landmarks);
112 | end
113 |
114 | %% GPU
115 | function testGpuDetect(test, imageTypeConversion, useDagNet)
116 |
117 | % filter if no GPU present
118 | test.assumeGreaterThan(gpuDeviceCount, 0, "This test is only valid on machines with at least one GPU");
119 |
120 | inputImage = imageTypeConversion(test.Image);
121 | detector = mtcnn.Detector("UseGPU", true, "UseDagNet", useDagNet);
122 | [bboxes, scores, landmarks] = detector.detect(inputImage);
123 |
124 | test.verifyEqual(size(bboxes), [6, 4]);
125 | test.verifyEqual(size(scores), [6, 1]);
126 | test.verifyEqual(size(landmarks), [6, 5, 2]);
127 |
128 | % Reference was taken on the CPU so increase relative tolerance
129 | test.verifyEqual(bboxes, test.Reference.bboxes, "RelTol", 1e-1);
130 | test.verifyEqual(scores, test.Reference.scores, "RelTol", 1e-1);
131 | test.verifyEqual(landmarks, test.Reference.landmarks, "RelTol", 1e-1);
132 | end
133 | end
134 | end
135 |
--------------------------------------------------------------------------------
/mtcnn.prj:
--------------------------------------------------------------------------------
1 |
2 |
3 | MTCNN Face Detection
4 | Justin Pinkney
5 | jpinkney@mathworks.com
6 | MathWorks
7 | Face detection and landmark localisation using deep learning.
8 | This repository implements deep learning based face detection and facial landmark localisation using Multi-Task Cascaded CNNs.
9 | For more details see the GitHub repository: https://github.com/matlab-deep-learning/mtcnn-face-detection
10 | ${PROJECT_ROOT}\doc\logo.png
11 | 1.2.2
12 | ${PROJECT_ROOT}\MTCNN Face Detection.mltbx
13 |
14 | - Computer Vision Toolbox
15 | - Deep Learning Toolbox
16 | - Image Processing Toolbox
17 |
18 |
19 | - 96
20 | - 12
21 | - 17
22 |
23 |
24 | - 9.2
25 | - 14.0
26 | - 11.1
27 |
28 |
29 | d2cc38da-9b3d-4307-8cfd-4a34d5a442bf
30 |
31 | true
32 |
33 |
34 |
35 |
36 | ${PROJECT_ROOT}\code\mtcnn\info.xml
37 | ${PROJECT_ROOT}\code\mtcnn\doc\GettingStarted.mlx
38 |
39 |
40 | false
41 |
42 |
43 |
44 | R2019a
45 | latest
46 | false
47 | true
48 | true
49 | true
50 | true
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 | ${PROJECT_ROOT}\code\mtcnn
86 |
87 |
88 | ${PROJECT_ROOT}\code\mtcnn\+mtcnn
89 | ${PROJECT_ROOT}\code\mtcnn\Contents.m
90 | ${PROJECT_ROOT}\code\mtcnn\doc
91 | ${PROJECT_ROOT}\code\mtcnn\info.xml
92 | ${PROJECT_ROOT}\code\mtcnn\mtcnnRoot.m
93 | ${PROJECT_ROOT}\code\mtcnn\weights
94 |
95 |
96 |
97 |
98 |
99 | C:\code\internal\mtcnn-face-detection\MTCNN Face Detection.mltbx
100 |
101 |
102 |
103 | C:\Program Files\MATLAB\R2020a
104 |
105 |
106 |
107 |
108 |
109 | true
110 |
111 |
112 |
113 |
114 | false
115 | false
116 | true
117 | false
118 | false
119 | false
120 | false
121 | false
122 | 10.0
123 | false
124 | true
125 | win64
126 | true
127 |
128 |
129 |
--------------------------------------------------------------------------------
/doc/logo.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
180 |
--------------------------------------------------------------------------------
/code/mtcnn/+mtcnn/Detector.m:
--------------------------------------------------------------------------------
1 | classdef Detector < matlab.mixin.SetGet
2 | % MTCNN Detector class
3 | %
4 | % When creating an mtcnn.Detector object
5 | % pass in any of the public properties as Name-Value pairs to
6 | % configure the detector. For more details of the available
7 | % options see the help for mtcnn.detectFaces.
8 | %
9 | % See also: mtcnn.detectFaces
10 |
11 | % Copyright 2019 The MathWorks, Inc.
12 |
13 | properties
14 | % Approx. min size in pixels
15 | MinSize {mustBeGreaterThan(MinSize, 12)} = 24
16 | % Approx. max size in pixels
17 | MaxSize = []
18 | % Pyramid scales for region proposal
19 | PyramidScale = sqrt(2)
20 | % Confidence threshold at each stage of detection
21 | ConfidenceThresholds = [0.6, 0.7, 0.8]
22 | % Non-max suppression overlap thresholds
23 | NmsThresholds = [0.5, 0.5, 0.5]
24 | % Use GPU for processing or not
25 | UseGPU = false
26 | % Use DAG Network for pre 19b compatibility
27 | UseDagNet = verLessThan('matlab', '9.7')
28 | end
29 |
30 | properties (Access=private)
31 | % An object providing an inteface to the networks
32 | Networks
33 | end
34 |
35 | properties (Constant)
36 | % Input sizes (pixels) of the networks
37 | PnetSize = 12
38 | RnetSize = 24
39 | OnetSize = 48
40 | end
41 |
42 |
43 | methods
44 | function obj = Detector(varargin)
45 | % Create an mtcnn.Detector object
46 |
47 | if nargin > 1
48 | obj.set(varargin{:});
49 | end
50 |
51 | if obj.UseDagNet
52 | obj.Networks = mtcnn.util.DagNetworkStrategy(obj.UseGPU);
53 | else
54 | obj.Networks = mtcnn.util.DlNetworkStrategy(obj.UseGPU);
55 | end
56 |
57 | obj.Networks.load();
58 |
59 | end
60 |
61 | function [bboxes, scores, landmarks] = detect(obj, im)
62 | % detect Run the detection algorithm on an image.
63 | %
64 | % Args:
65 | % im - RGB input image for detection
66 | %
67 | % Returns:
68 | % bbox - nx4 array of face bounding boxes in the
69 | % format [x, y, w, h]
70 | % scores - nx1 array of face probabilities
71 | % landmarks - nx5x2 array of facial landmarks
72 | %
73 | % See also: mtcnn.detectFaces
74 |
75 | im = obj.prepImage(im);
76 |
77 | bboxes = [];
78 | scores = [];
79 | landmarks = [];
80 |
81 | %% Stage 1 - Proposal
82 | scales = mtcnn.util.calculateScales(im, ...
83 | obj.MinSize, ...
84 | obj.MaxSize, ...
85 | obj.PnetSize, ...
86 | obj.PyramidScale);
87 |
88 | for scale = scales
89 | [thisBox, thisScore] = ...
90 | mtcnn.proposeRegions(im, scale, ...
91 | obj.ConfidenceThresholds(1), ...
92 | obj.Networks);
93 | bboxes = cat(1, bboxes, thisBox);
94 | scores = cat(1, scores, thisScore);
95 | end
96 |
97 | if ~isempty(scores)
98 | [bboxes, ~] = selectStrongestBbox(gather(bboxes), scores, ...
99 | "RatioType", "Min", ...
100 | "OverlapThreshold", obj.NmsThresholds(1));
101 | else
102 | return % No proposals found
103 | end
104 |
105 | %% Stage 2 - Refinement
106 | [cropped, bboxes] = obj.prepBbox(im, bboxes, obj.RnetSize);
107 | [probs, correction] = obj.Networks.applyRNet(cropped);
108 | [scores, bboxes] = obj.processOutputs(probs, correction, bboxes, 2);
109 |
110 | if isempty(scores)
111 | return
112 | end
113 |
114 | %% Stage 3 - Output
115 | [cropped, bboxes] = obj.prepBbox(im, bboxes, obj.OnetSize);
116 |
117 | % Adjust bboxes for the behaviour of imcrop
118 | bboxes(:, 1:2) = bboxes(:, 1:2) - 0.5;
119 | bboxes(:, 3:4) = bboxes(:, 3:4) + 1;
120 |
121 | [probs, correction, landmarks] = obj.Networks.applyONet(cropped);
122 |
123 | % landmarks are relative to uncorrected bbox
124 | x = bboxes(:, 1) + landmarks(:, 1:5).*(bboxes(:, 3));
125 | y = bboxes(:, 2) + landmarks(:, 6:10).*(bboxes(:, 4));
126 | landmarks = cat(3, x, y);
127 | landmarks(probs(:, 2) < obj.ConfidenceThresholds(3), :, :) = [];
128 |
129 | [scores, bboxes, landmarks] = obj.processOutputs(probs, correction, bboxes, 3, landmarks);
130 |
131 | % Gather and cast the outputs
132 | bboxes= gather(double(bboxes));
133 | scores = gather(double(scores));
134 | landmarks = gather(double(landmarks));
135 | end
136 |
137 | function set.UseDagNet(obj, val)
138 | if verLessThan('matlab', '9.7') && val
139 | warning("mtcnn:Detector:pre19b", ...
140 | "For use in R2019a UseDagNet must be set to true");
141 | end
142 | obj.UseDagNet = val;
143 | end
144 | end
145 |
146 | methods (Access=private)
147 | function [cropped, bboxes] = prepBbox(obj, im, bboxes, outputSize)
148 | % prepImages Pre-process the images and bounding boxes.
149 | bboxes = mtcnn.util.makeSquare(bboxes);
150 | bboxes = round(bboxes);
151 | cropped = mtcnn.util.cropImage(im, bboxes, outputSize);
152 | end
153 |
154 | function [scores, bboxes, landmarks] = ...
155 | processOutputs(obj, probs, correction, bboxes, netIdx, landmarks)
156 | % processOutputs Post-process the output values.
157 | faceProbs = probs(:, 2);
158 | bboxes = mtcnn.util.applyCorrection(bboxes, correction);
159 | bboxes(faceProbs < obj.ConfidenceThresholds(netIdx), :) = [];
160 | scores = faceProbs(faceProbs >= obj.ConfidenceThresholds(netIdx));
161 | if ~isempty(scores)
162 | if verLessThan("matlab", "9.9")
163 | % < R2020b no gpuArray support for selectStrongestBbox
164 | [bboxes, scores] = gather(bboxes, scores);
165 | end
166 | [bboxes, scores, index] = selectStrongestBbox(bboxes, scores, ...
167 | "RatioType", "Min", ...
168 | "OverlapThreshold", obj.NmsThresholds(netIdx));
169 | if netIdx == 3
170 | landmarks = landmarks(index, :, :);
171 | end
172 | end
173 | end
174 |
175 | function outIm = prepImage(obj, im)
176 | % convert the image to the correct scaling and type
177 | % All images should be scaled to -1 to 1 and of single type
178 | % also place on the GPU if required
179 |
180 | switch class(im)
181 | case "uint8"
182 | outIm = single(im)/255*2 - 1;
183 | case "single"
184 | % expect floats to be 0-1 scaled
185 | outIm = im*2 - 1;
186 | case "double"
187 | outIm = single(im)*2 - 1;
188 | otherwise
189 | error("mtcnn:Detector:UnsupportedType", ...
190 | "Input image is of unsupported type '%s'", class(im));
191 | end
192 |
193 | if obj.UseGPU && ~obj.UseDagNet
194 | outIm = gpuArray(outIm);
195 | end
196 |
197 | end
198 | end
199 | end
--------------------------------------------------------------------------------