Skip to content

Commit b09fbe4

Browse files
tinyYolov2 face detection examples
1 parent e8c494d commit b09fbe4

File tree

7 files changed

+438
-4
lines changed

7 files changed

+438
-4
lines changed

examples/public/commons.js

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,18 @@ function renderNavBar(navbarId, exampleUri) {
134134
uri: 'mtcnn_face_recognition_webcam',
135135
name: 'MTCNN Face Recognition Webcam'
136136
},
137+
{
138+
uri: 'tiny_yolov2_face_detection',
139+
name: 'Tiny Yolov2 Face Detection'
140+
},
141+
{
142+
uri: 'tiny_yolov2_face_detection_video',
143+
name: 'Tiny Yolov2 Face Detection Video'
144+
},
145+
{
146+
uri: 'tiny_yolov2_face_detection_webcam',
147+
name: 'Tiny Yolov2 Face Detection Webcam'
148+
},
137149
{
138150
uri: 'batch_face_landmarks',
139151
name: 'Batch Face Landmarks'
@@ -197,7 +209,7 @@ function renderNavBar(navbarId, exampleUri) {
197209
})
198210

199211
$('.button-collapse').sideNav({
200-
menuWidth: 250
212+
menuWidth: 280
201213
})
202214
}
203215

examples/server.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@ app.get('/mtcnn_face_detection_video', (req, res) => res.sendFile(path.join(view
2929
app.get('/mtcnn_face_detection_webcam', (req, res) => res.sendFile(path.join(viewsDir, 'mtcnnFaceDetectionWebcam.html')))
3030
app.get('/mtcnn_face_recognition', (req, res) => res.sendFile(path.join(viewsDir, 'mtcnnFaceRecognition.html')))
3131
app.get('/mtcnn_face_recognition_webcam', (req, res) => res.sendFile(path.join(viewsDir, 'mtcnnFaceRecognitionWebcam.html')))
32+
app.get('/tiny_yolov2_face_detection', (req, res) => res.sendFile(path.join(viewsDir, 'tinyYolov2FaceDetection.html')))
33+
app.get('/tiny_yolov2_face_detection_video', (req, res) => res.sendFile(path.join(viewsDir, 'tinyYolov2FaceDetectionVideo.html')))
34+
app.get('/tiny_yolov2_face_detection_webcam', (req, res) => res.sendFile(path.join(viewsDir, 'tinyYolov2FaceDetectionWebcam.html')))
3235
app.get('/batch_face_landmarks', (req, res) => res.sendFile(path.join(viewsDir, 'batchFaceLandmarks.html')))
3336
app.get('/batch_face_recognition', (req, res) => res.sendFile(path.join(viewsDir, 'batchFaceRecognition.html')))
3437

examples/views/mtcnnFaceDetection.html

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,6 @@
5858
let stage1Threshold = 0.7
5959
let stage2Threshold = 0.7
6060
let stage3Threshold = 0.7
61-
let mtcnn
6261

6362
function onIncreaseThreshold() {
6463
minConfidence = Math.min(faceapi.round(minConfidence + 0.1), 1.0)
Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
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 input-field" style="margin-right: 20px;">
36+
<select id="sizeType">
37+
<option value="" disabled selected>Input Size:</option>
38+
<option value="xs">XS: 224 x 224</option>
39+
<option value="sm">SM: 320 x 320</option>
40+
<option value="md">MD: 416 x 416</option>
41+
<option value="lg">LG: 608 x 608</option>
42+
</select>
43+
<label>Input Size</label>
44+
</div>
45+
<div class="row">
46+
<label for="scoreThreshold">Score Threshold:</label>
47+
<input disabled value="0.5" id="scoreThreshold" type="text" class="bold">
48+
</div>
49+
<button
50+
class="waves-effect waves-light btn"
51+
onclick="onDecreaseThreshold()"
52+
>
53+
<i class="material-icons left">-</i>
54+
</button>
55+
<button
56+
class="waves-effect waves-light btn"
57+
onclick="onIncreaseThreshold()"
58+
>
59+
<i class="material-icons left">+</i>
60+
</button>
61+
</div>
62+
</div>
63+
64+
<script>
65+
let scoreThreshold = 0.5
66+
let sizeType = 'lg'
67+
68+
function onIncreaseThreshold() {
69+
scoreThreshold = Math.min(faceapi.round(scoreThreshold + 0.1), 1.0)
70+
$('#scoreThreshold').val(scoreThreshold)
71+
updateResults()
72+
}
73+
74+
function onDecreaseThreshold() {
75+
scoreThreshold = Math.max(faceapi.round(scoreThreshold - 0.1), 0.1)
76+
$('#scoreThreshold').val(scoreThreshold)
77+
updateResults()
78+
}
79+
80+
function onSizeTypeChanged(e, c) {
81+
sizeType = e.target.value
82+
$('#sizeType').val(sizeType)
83+
updateResults()
84+
}
85+
86+
async function loadImageFromUrl(url) {
87+
const img = await requestExternalImage($('#imgUrlInput').val())
88+
$('#inputImg').get(0).src = img.src
89+
updateResults()
90+
}
91+
92+
async function updateResults() {
93+
const inputImgEl = $('#inputImg').get(0)
94+
const { width, height } = inputImgEl
95+
const canvas = $('#overlay').get(0)
96+
canvas.width = width
97+
canvas.height = height
98+
99+
const forwardParams = {
100+
inputSize: sizeType,
101+
scoreThreshold
102+
}
103+
104+
const detections = await faceapi.tinyYolov2(inputImgEl, forwardParams)
105+
106+
faceapi.drawDetection('overlay', detections.map(det => det.forSize(width, height)))
107+
}
108+
109+
async function onSelectionChanged(uri) {
110+
const imgBuf = await fetchImage(uri)
111+
$(`#inputImg`).get(0).src = (await faceapi.bufferToImage(imgBuf)).src
112+
updateResults()
113+
}
114+
115+
async function run() {
116+
await faceapi.loadTinyYolov2Model('/')
117+
118+
$('#loader').hide()
119+
onSelectionChanged($('#selectList select').val())
120+
}
121+
122+
$(document).ready(function() {
123+
renderNavBar('#navbar', 'tiny_yolov2_face_detection')
124+
renderImageSelectList(
125+
'#selectList',
126+
async (uri) => {
127+
await onSelectionChanged(uri)
128+
},
129+
'bbt1.jpg'
130+
)
131+
132+
const sizeTypeSelect = $('#sizeType')
133+
sizeTypeSelect.val(sizeType)
134+
sizeTypeSelect.on('change', onSizeTypeChanged)
135+
sizeTypeSelect.material_select()
136+
run()
137+
})
138+
</script>
139+
</body>
140+
</html>
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+
<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 input-field" style="margin-right: 20px;">
23+
<select id="sizeType">
24+
<option value="" disabled selected>Input Size:</option>
25+
<option value="xs">XS: 224 x 224</option>
26+
<option value="sm">SM: 320 x 320</option>
27+
<option value="md">MD: 416 x 416</option>
28+
<option value="lg">LG: 608 x 608</option>
29+
</select>
30+
<label>Input Size</label>
31+
</div>
32+
<div class="row">
33+
<label for="scoreThreshold">Score Threshold:</label>
34+
<input disabled value="0.5" id="scoreThreshold" type="text" class="bold">
35+
</div>
36+
<button
37+
class="waves-effect waves-light btn"
38+
onclick="onDecreaseThreshold()"
39+
>
40+
<i class="material-icons left">-</i>
41+
</button>
42+
<button
43+
class="waves-effect waves-light btn"
44+
onclick="onIncreaseThreshold()"
45+
>
46+
<i class="material-icons left">+</i>
47+
</button>
48+
</div>
49+
<div class="row side-by-side">
50+
<div class="row">
51+
<label for="time">Time:</label>
52+
<input disabled value="-" id="time" type="text" class="bold">
53+
</div>
54+
<div class="row">
55+
<label for="fps">Estimated Fps:</label>
56+
<input disabled value="-" id="fps" type="text" class="bold">
57+
</div>
58+
</div>
59+
</div>
60+
61+
<script>
62+
let scoreThreshold = 0.5
63+
let sizeType = 'md'
64+
let modelLoaded = false
65+
66+
function onIncreaseThreshold() {
67+
scoreThreshold = Math.min(faceapi.round(scoreThreshold + 0.1), 1.0)
68+
$('#scoreThreshold').val(scoreThreshold)
69+
}
70+
71+
function onDecreaseThreshold() {
72+
scoreThreshold = Math.max(faceapi.round(scoreThreshold - 0.1), 0.1)
73+
$('#scoreThreshold').val(scoreThreshold)
74+
}
75+
76+
function onSizeTypeChanged(e, c) {
77+
sizeType = e.target.value
78+
$('#sizeType').val(sizeType)
79+
}
80+
81+
function displayTimeStats(timeInMs) {
82+
$('#time').val(`${timeInMs} ms`)
83+
$('#fps').val(`${faceapi.round(1000 / timeInMs)}`)
84+
}
85+
86+
async function onPlay(videoEl) {
87+
if(videoEl.paused || videoEl.ended || !modelLoaded)
88+
return false
89+
90+
const { width, height } = faceapi.getMediaDimensions(videoEl)
91+
const canvas = $('#overlay').get(0)
92+
canvas.width = width
93+
canvas.height = height
94+
95+
const forwardParams = {
96+
inputSize: sizeType,
97+
scoreThreshold
98+
}
99+
100+
const ts = Date.now()
101+
result = await faceapi.tinyYolov2(videoEl, forwardParams)
102+
displayTimeStats(Date.now() - ts)
103+
104+
faceapi.drawDetection('overlay', result.map(det => det.forSize(width, height)))
105+
setTimeout(() => onPlay(videoEl))
106+
}
107+
async function loadNetWeights(uri) {
108+
return new Float32Array(await (await fetch(uri)).arrayBuffer())
109+
}
110+
async function run() {
111+
await faceapi.loadTinyYolov2Model('/')
112+
modelLoaded = true
113+
onPlay($('#inputVideo').get(0))
114+
$('#loader').hide()
115+
}
116+
117+
$(document).ready(function() {
118+
renderNavBar('#navbar', 'tiny_yolov2_face_detection_video')
119+
120+
const sizeTypeSelect = $('#sizeType')
121+
sizeTypeSelect.val(sizeType)
122+
sizeTypeSelect.on('change', onSizeTypeChanged)
123+
sizeTypeSelect.material_select()
124+
run()
125+
})
126+
</script>
127+
</body>
128+
</html>

0 commit comments

Comments
 (0)