Skip to content

Commit 4eed7a3

Browse files
added examples for mtcnn face detection and mtcnn video face detection
1 parent b65c74c commit 4eed7a3

File tree

4 files changed

+256
-0
lines changed

4 files changed

+256
-0
lines changed

examples/public/commons.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,14 @@ function renderNavBar(navbarId, exampleUri) {
114114
uri: 'detect_and_recognize_faces',
115115
name: 'Detect and Recognize Faces'
116116
},
117+
{
118+
uri: 'mtcnn_face_detection',
119+
name: 'MTCNN Face Detection'
120+
},
121+
{
122+
uri: 'mtcnn_face_detection_video',
123+
name: 'MTCNN Face Detection Video'
124+
},
117125
{
118126
uri: 'batch_face_landmarks',
119127
name: 'Batch Face Landmarks'

examples/server.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ app.get('/detect_and_draw_faces', (req, res) => res.sendFile(path.join(viewsDir,
2424
app.get('/detect_and_draw_landmarks', (req, res) => res.sendFile(path.join(viewsDir, 'detectAndDrawLandmarks.html')))
2525
app.get('/face_alignment', (req, res) => res.sendFile(path.join(viewsDir, 'faceAlignment.html')))
2626
app.get('/detect_and_recognize_faces', (req, res) => res.sendFile(path.join(viewsDir, 'detectAndRecognizeFaces.html')))
27+
app.get('/mtcnn_face_detection', (req, res) => res.sendFile(path.join(viewsDir, 'mtcnnFaceDetection.html')))
28+
app.get('/mtcnn_face_detection_video', (req, res) => res.sendFile(path.join(viewsDir, 'mtcnnFaceDetectionVideo.html')))
2729
app.get('/batch_face_landmarks', (req, res) => res.sendFile(path.join(viewsDir, 'batchFaceLandmarks.html')))
2830
app.get('/batch_face_recognition', (req, res) => res.sendFile(path.join(viewsDir, 'batchFaceRecognition.html')))
2931

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<script src="face-api.js"></script>
5+
<script src="commons.js"></script>
6+
<link rel="stylesheet" href="styles.css">
7+
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.100.2/css/materialize.css">
8+
<script type="text/javascript" src="https://code.jquery.com/jquery-2.1.1.min.js"></script>
9+
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.100.2/js/materialize.min.js"></script>
10+
</head>
11+
<body>
12+
<div id="navbar"></div>
13+
<div class="center-content page-container">
14+
<div class="progress" id="loader">
15+
<div class="indeterminate"></div>
16+
</div>
17+
<div style="position: relative" class="margin">
18+
<img id="inputImg" src="" style="max-width: 800px;" />
19+
<canvas id="overlay" />
20+
</div>
21+
<div class="row side-by-side">
22+
<div id="selectList"></div>
23+
<div class="row">
24+
<label for="imgUrlInput">Get image from URL:</label>
25+
<input id="imgUrlInput" type="text" class="bold">
26+
</div>
27+
<button
28+
class="waves-effect waves-light btn"
29+
onclick="loadImageFromUrl()"
30+
>
31+
Ok
32+
</button>
33+
</div>
34+
<div class="row side-by-side">
35+
<div class="row">
36+
<label for="minConfidence">Min Confidence:</label>
37+
<input disabled value="0.7" id="minConfidence" type="text" class="bold">
38+
</div>
39+
<button
40+
class="waves-effect waves-light btn"
41+
onclick="onDecreaseThreshold()"
42+
>
43+
<i class="material-icons left">-</i>
44+
</button>
45+
<button
46+
class="waves-effect waves-light btn"
47+
onclick="onIncreaseThreshold()"
48+
>
49+
<i class="material-icons left">+</i>
50+
</button>
51+
</div>
52+
</div>
53+
54+
<script>
55+
let minFaceSize = 50 //20 //
56+
let scaleFactor = 0.709 // 0.2
57+
let maxNumScales = 10 // 0.2
58+
let stage1Threshold = 0.6
59+
let stage2Threshold = 0.7
60+
let stage3Threshold = 0.7
61+
let mtcnn
62+
63+
function onIncreaseThreshold() {
64+
minConfidence = Math.min(faceapi.round(minConfidence + 0.1), 1.0)
65+
$('#minConfidence').val(minConfidence)
66+
updateResults()
67+
}
68+
69+
function onDecreaseThreshold() {
70+
minConfidence = Math.max(faceapi.round(minConfidence - 0.1), 0.1)
71+
$('#minConfidence').val(minConfidence)
72+
updateResults()
73+
}
74+
75+
async function loadImageFromUrl(url) {
76+
const img = await requestExternalImage($('#imgUrlInput').val())
77+
$('#inputImg').get(0).src = img.src
78+
updateResults()
79+
}
80+
81+
async function updateResults() {
82+
const inputImgEl = $('#inputImg').get(0)
83+
const { width, height } = inputImgEl
84+
const canvas = $('#overlay').get(0)
85+
canvas.width = width
86+
canvas.height = height
87+
88+
const scoreThresholds = [stage1Threshold, stage2Threshold, stage3Threshold]
89+
const { results, stats } = await mtcnn.forwardWithStats(inputImgEl, minFaceSize, scaleFactor, maxNumScales, scoreThresholds)
90+
91+
console.log(stats)
92+
93+
if (results) {
94+
const { faceDetection, faceLandmarks } = results
95+
results.forEach(({ faceDetection, faceLandmarks }) => {
96+
faceapi.drawDetection('overlay', faceDetection.forSize(width, height))
97+
faceapi.drawLandmarks('overlay', faceLandmarks.forSize(width, height), { lineWidth: 4, color: 'red' })
98+
})
99+
}
100+
}
101+
102+
async function onSelectionChanged(uri) {
103+
const imgBuf = await fetchImage(uri)
104+
$(`#inputImg`).get(0).src = (await faceapi.bufferToImage(imgBuf)).src
105+
updateResults()
106+
}
107+
108+
async function run() {
109+
const weightsBuffer = await (await fetch('/uncompressed/mtcnn_model.weights')).arrayBuffer()
110+
mtcnn = faceapi.mtcnn(new Float32Array(weightsBuffer))
111+
$('#loader').hide()
112+
onSelectionChanged($('#selectList select').val())
113+
}
114+
115+
$(document).ready(function() {
116+
renderNavBar('#navbar', 'mtcnn_face_detection')
117+
renderImageSelectList(
118+
'#selectList',
119+
async (uri) => {
120+
await onSelectionChanged(uri)
121+
},
122+
'bbt1.jpg'
123+
)
124+
run()
125+
})
126+
</script>
127+
</body>
128+
</html>
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<script src="face-api.js"></script>
5+
<script src="commons.js"></script>
6+
<link rel="stylesheet" href="styles.css">
7+
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.100.2/css/materialize.css">
8+
<script type="text/javascript" src="https://code.jquery.com/jquery-2.1.1.min.js"></script>
9+
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.100.2/js/materialize.min.js"></script>
10+
</head>
11+
<body>
12+
<div id="navbar"></div>
13+
<div class="center-content page-container">
14+
<div class="progress" id="loader">
15+
<div class="indeterminate"></div>
16+
</div>
17+
<div style="position: relative" class="margin">
18+
<video src="media/bbt.mp4" onplay="onPlay(this)" id="inputVideo" autoplay muted></video>
19+
<canvas id="overlay" />
20+
</div>
21+
<div class="row side-by-side">
22+
<div class="row">
23+
<label for="minConfidence">Min Confidence:</label>
24+
<input disabled value="0.7" id="minConfidence" type="text" class="bold">
25+
</div>
26+
<button
27+
class="waves-effect waves-light btn"
28+
onclick="onDecreaseThreshold()"
29+
>
30+
<i class="material-icons left">-</i>
31+
</button>
32+
<button
33+
class="waves-effect waves-light btn"
34+
onclick="onIncreaseThreshold()"
35+
>
36+
<i class="material-icons left">+</i>
37+
</button>
38+
</div>
39+
<div class="row side-by-side">
40+
<div class="row">
41+
<label for="time">Time:</label>
42+
<input disabled value="-" id="time" type="text" class="bold">
43+
</div>
44+
<div class="row">
45+
<label for="fps">Estimated Fps:</label>
46+
<input disabled value="-" id="fps" type="text" class="bold">
47+
</div>
48+
</div>
49+
</div>
50+
51+
<script>
52+
let minFaceSize = 80
53+
let scaleFactor = 0.709
54+
let maxNumScales = 10
55+
let minConfidence = 0.9
56+
let stage1Threshold = 0.7
57+
let stage2Threshold = 0.7
58+
let stage3Threshold = 0.7
59+
let modelLoaded = false
60+
let result
61+
62+
function onIncreaseThreshold() {
63+
minConfidence = Math.min(faceapi.round(minConfidence + 0.1), 1.0)
64+
$('#minConfidence').val(minConfidence)
65+
}
66+
67+
function onDecreaseThreshold() {
68+
minConfidence = Math.max(faceapi.round(minConfidence - 0.1), 0.1)
69+
$('#minConfidence').val(minConfidence)
70+
}
71+
72+
function displayTimeStats(timeInMs) {
73+
$('#time').val(`${timeInMs} ms`)
74+
$('#fps').val(`${faceapi.round(1000 / timeInMs)}`)
75+
}
76+
77+
async function onPlay(videoEl) {
78+
if(videoEl.paused || videoEl.ended || !modelLoaded)
79+
return false
80+
81+
const { width, height } = faceapi.getMediaDimensions(videoEl)
82+
const canvas = $('#overlay').get(0)
83+
canvas.width = width
84+
canvas.height = height
85+
86+
const scoreThresholds = [stage1Threshold, stage2Threshold, stage3Threshold]
87+
const ts = Date.now()
88+
const { results, stats } = await mtcnn.forwardWithStats(videoEl, minFaceSize, scaleFactor, maxNumScales, scoreThresholds)
89+
displayTimeStats(Date.now() - ts)
90+
91+
if (results) {
92+
const { faceDetection, faceLandmarks } = results
93+
results.forEach(({ faceDetection, faceLandmarks }) => {
94+
if (faceDetection.score < minConfidence) {
95+
return
96+
}
97+
faceapi.drawDetection('overlay', faceDetection.forSize(width, height))
98+
faceapi.drawLandmarks('overlay', faceLandmarks.forSize(width, height), { lineWidth: 4, color: 'red' })
99+
})
100+
}
101+
setTimeout(() => onPlay(videoEl))
102+
}
103+
104+
async function run() {
105+
const weightsBuffer = await (await fetch('/uncompressed/mtcnn_model.weights')).arrayBuffer()
106+
mtcnn = faceapi.mtcnn(new Float32Array(weightsBuffer))
107+
modelLoaded = true
108+
onPlay($('#inputVideo').get(0))
109+
$('#loader').hide()
110+
}
111+
112+
$(document).ready(function() {
113+
renderNavBar('#navbar', 'mtcnn_face_detection_video')
114+
run()
115+
})
116+
</script>
117+
</body>
118+
</html>

0 commit comments

Comments
 (0)