Skip to content

Commit 20f129e

Browse files
face detection example
1 parent 331e323 commit 20f129e

File tree

5 files changed

+173
-43
lines changed

5 files changed

+173
-43
lines changed

examples/public/commons.js

Lines changed: 107 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -8,47 +8,134 @@ function getFaceImageUri(className, idx) {
88
return `images/${className}/${className}${idx}.png`
99
}
1010

11-
async function initNet() {
11+
async function fetchImage(uri) {
12+
return (await axios.get(uri, { responseType: 'blob' })).data
13+
}
14+
15+
function round(num) {
16+
return Math.floor(num * 100) / 100
17+
}
18+
19+
function getElement(arg) {
20+
if (typeof arg === 'string') {
21+
return document.getElementById(arg)
22+
}
23+
return arg
24+
}
25+
26+
async function initFaceDetectionNet() {
27+
const res = await axios.get('face_detection_model.weights', { responseType: 'arraybuffer' })
28+
const weights = new Float32Array(res.data)
29+
return facerecognition.faceDetectionNet(weights)
30+
}
31+
32+
async function initFaceRecognitionNet() {
1233
const res = await axios.get('face_recognition_model.weights', { responseType: 'arraybuffer' })
1334
const weights = new Float32Array(res.data)
1435
return facerecognition.faceRecognitionNet(weights)
1536
}
1637

17-
function bufferToImgSrc(buf) {
18-
return new Promise((resolve, reject) => {
19-
const reader = new window.FileReader()
20-
reader.onload = () => resolve(reader.result)
21-
reader.onerror = reject
22-
reader.readAsDataURL(buf)
23-
})
38+
function drawImgToCanvas(canvasArg, imgArg) {
39+
const canvas = getElement(canvasArg)
40+
const img = getElement(imgArg)
41+
canvas.width = img.width
42+
canvas.height = img.height
43+
const ctx = canvas.getContext('2d')
44+
ctx.drawImage(img, 0, 0, img.width, img.height)
45+
return ctx
2446
}
2547

26-
function imgSrcToData(src) {
48+
function imgSrcToImageData(src) {
2749
return new Promise((resolve, reject) => {
28-
const canvas = document.createElement('canvas')
29-
canvas.width = 150
30-
canvas.height = 150
31-
const ctx = canvas.getContext('2d')
3250
const img = new Image()
3351
img.onload = function() {
34-
ctx.drawImage(img, 0, 0)
35-
resolve(ctx.getImageData(0, 0, 150, 150))
52+
const ctx = drawImgToCanvas(document.createElement('canvas'), img)
53+
resolve(ctx.getImageData(0, 0, img.width, img.height))
3654
}
3755
img.onerror = reject
3856
img.src = src
3957
})
4058
}
4159

60+
function bufferToImgSrc(buf) {
61+
return new Promise((resolve, reject) => {
62+
const reader = new window.FileReader()
63+
reader.onload = () => resolve(reader.result)
64+
reader.onerror = reject
65+
reader.readAsDataURL(buf)
66+
})
67+
}
68+
4269
async function bufferToImageData(buf) {
43-
return imgSrcToData(await bufferToImgSrc(buf))
70+
return imgSrcToImageData(await bufferToImgSrc(buf))
4471
}
4572

46-
async function fetchImage(uri) {
47-
return (await axios.get(uri, { responseType: 'blob' })).data
73+
function drawBox(canvasArg, x, y, w, h, lineWidth = 2, color = 'blue') {
74+
const canvas = getElement(canvasArg)
75+
const ctx = canvas.getContext('2d')
76+
ctx.strokeStyle = color
77+
ctx.lineWidth = lineWidth
78+
ctx.strokeRect(x, y, w, h)
4879
}
4980

50-
function round(num) {
51-
return Math.floor(num * 100) / 100
81+
function drawText(canvasArg, x, y, text, fontSize = 20, fontStyle = 'Georgia', color = 'blue') {
82+
const canvas = getElement(canvasArg)
83+
const ctx = canvas.getContext('2d')
84+
ctx.fillStyle = color
85+
ctx.font = fontSize + 'px ' + fontStyle
86+
ctx.fillText(text, x, y)
87+
}
88+
89+
function drawDetection(canvasArg, detection, options = {}) {
90+
const canvas = getElement(canvasArg)
91+
const detectionArray = Array.isArray(detection)
92+
? detection
93+
: [detection]
94+
95+
detectionArray.forEach((det) => {
96+
const {
97+
score,
98+
box
99+
} = det
100+
101+
const {
102+
left,
103+
right,
104+
top,
105+
bottom
106+
} = box
107+
108+
const {
109+
color,
110+
lineWidth = 2,
111+
fontSize = 20,
112+
fontStyle,
113+
withScore = true
114+
} = options
115+
116+
const padText = 2 + lineWidth
117+
118+
drawBox(
119+
canvas,
120+
left,
121+
top,
122+
right - left,
123+
bottom - top,
124+
lineWidth,
125+
color
126+
)
127+
if (withScore) {
128+
drawText(
129+
canvas,
130+
left + padText,
131+
top + (fontSize * 0.6) + padText,
132+
round(score),
133+
fontSize,
134+
fontStyle,
135+
color
136+
)
137+
}
138+
})
52139
}
53140

54141
function renderNavBar(navbarId, exampleUri) {

examples/public/styles.css

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
.page-container {
2-
position: fixed;
32
left: 0;
43
right: 0;
54
margin: auto;
@@ -29,9 +28,4 @@
2928

3029
.margin {
3130
margin: 20px;
32-
}
33-
34-
img {
35-
width: 150px;
36-
height: 150px;
3731
}

examples/views/faceDetection.html

Lines changed: 56 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,29 +12,78 @@
1212
<body>
1313
<div class="center-content page-container">
1414
<div id="navbar"></div>
15-
<div class="center-content">
16-
<img id="img" src="" class="margin"/>
17-
<div id="selectList" class="input-field"></div>
15+
<div class="progress" id="loader">
16+
<div class="indeterminate"></div>
17+
</div>
18+
<div style="position: relative" class="margin">
19+
<img id="img" src="" />
20+
<canvas id="overlay" style="position: absolute; top: 0; left: 0;" />
21+
</div>
22+
<div class="row side-by-side">
23+
<div id="selectList"></div>
24+
<div class="row">
25+
<label for="minConfidence">Min Confidence:</label>
26+
<input disabled value="0.7" id="minConfidence" type="text" class="bold">
27+
</div>
28+
<button
29+
class="waves-effect waves-light btn"
30+
onclick="onDecreaseThreshold()"
31+
>
32+
<i class="material-icons left">-</i>
33+
</button>
34+
<button
35+
class="waves-effect waves-light btn"
36+
onclick="onIncreaseThreshold()"
37+
>
38+
<i class="material-icons left">+</i>
39+
</button>
1840
</div>
1941
</div>
2042

2143
<script>
44+
let minConfidence = 0.7
45+
let net, result
46+
47+
function onIncreaseThreshold() {
48+
minConfidence = Math.min(round(minConfidence + 0.1), 1.0)
49+
$('#minConfidence').val(minConfidence)
50+
updateResults()
51+
}
52+
53+
function onDecreaseThreshold() {
54+
minConfidence = Math.max(round(minConfidence - 0.1), 0.1)
55+
$('#minConfidence').val(minConfidence)
56+
updateResults()
57+
}
58+
59+
async function updateResults() {
60+
result = await net.locateFaces(await imgSrcToImageData($(`#img`).get(0).src), minConfidence)
61+
drawImgToCanvas('overlay', 'img')
62+
drawDetection('overlay', result)
63+
}
64+
2265
async function onSelectionChanged(uri) {
2366
const imgBuf = await fetchImage(uri)
24-
const imgEl = $(`#img`).get(0)
25-
imgEl.src = await bufferToImgSrc(imgBuf)
67+
$(`#img`).get(0).src = await bufferToImgSrc(imgBuf)
68+
updateResults()
69+
}
70+
71+
async function run() {
72+
net = await initFaceDetectionNet()
73+
$('#loader').hide()
74+
onSelectionChanged($('#selectList select').val())
2675
}
2776

2877
$(document).ready(function() {
29-
renderNavBar('#navbar')
78+
renderNavBar('#navbar', 'face_detection')
3079
renderImageSelectList(
3180
'#selectList',
3281
async (uri) => {
3382
await onSelectionChanged(uri)
3483
},
3584
1
3685
)
37-
onSelectionChanged($('#selectList select').val())
86+
run()
3887
})
3988
</script>
4089
</body>

examples/views/faceRecognition.html

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@
4747
class="waves-effect waves-light btn"
4848
onclick="onSlower()"
4949
>
50-
<i class="material-icons left">-</i> Slower
50+
<i class="material-icons left">-</i> Slower
5151
</button>
5252
<button
5353
class="waves-effect waves-light btn"
@@ -71,17 +71,17 @@
7171

7272
let isStop = false
7373
let trainDescriptorsByClass = []
74-
let net = {}
74+
let net
7575
let currImageIdx = 2, currClassIdx = 0
7676
let to = null
7777

7878
function onSlower() {
79-
interval = Math.max(interval + 100, 0)
79+
interval = Math.min(interval + 100, 2000)
8080
$('#interval').val(interval)
8181
}
8282

8383
function onFaster() {
84-
interval = Math.min(interval - 100, 2000)
84+
interval = Math.max(interval - 100, 0)
8585
$('#interval').val(interval)
8686
}
8787

@@ -136,7 +136,7 @@
136136
const imgEl = $('#face').get(0)
137137
imgEl.src = await bufferToImgSrc(imgBuf)
138138

139-
const imageData = await imgSrcToData(imgEl.src)
139+
const imageData = await imgSrcToImageData(imgEl.src)
140140

141141
const ts = Date.now()
142142
const result = await net.forward(imageData)
@@ -161,7 +161,7 @@
161161
try {
162162
setStatusText('loading model file...')
163163

164-
net = await initNet()
164+
net = await initFaceRecognitionNet()
165165
setStatusText('computing initial descriptors...')
166166

167167
const trainImgDatas = await loadTrainingData()

examples/views/faceSimilarity.html

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,11 @@
2020
<div class="row side-by-side">
2121
<div class="center-content">
2222
<img id="face1" src="" class="margin"/>
23-
<div id="selectList1" class="input-field"></div>
23+
<div id="selectList1"></div>
2424
</div>
2525
<div class="center-content">
2626
<img id="face2" src="" class="margin"/>
27-
<div id="selectList2" class="input-field"></div>
27+
<div id="selectList2"></div>
2828
</div>
2929
</div>
3030
<div class="row">
@@ -52,7 +52,7 @@
5252
}
5353

5454
async function computeDescriptorFromSrc(imgEl) {
55-
return net.computeFaceDescriptor(await imgSrcToData(imgEl.src))
55+
return net.computeFaceDescriptor(await imgSrcToImageData(imgEl.src))
5656
}
5757

5858
async function onSelectionChanged(which, uri) {
@@ -63,7 +63,7 @@
6363
}
6464

6565
async function run() {
66-
net = await initNet()
66+
net = await initFaceRecognitionNet()
6767
$('#loader').hide()
6868
await onSelectionChanged(1, $('#selectList1 select').val())
6969
await onSelectionChanged(2, $('#selectList2 select').val())

0 commit comments

Comments
 (0)