Commit 20f129e2 by vincent

face detection example

parent 331e323a
......@@ -8,47 +8,134 @@ function getFaceImageUri(className, idx) {
return `images/${className}/${className}${idx}.png`
}
async function initNet() {
async function fetchImage(uri) {
return (await axios.get(uri, { responseType: 'blob' })).data
}
function round(num) {
return Math.floor(num * 100) / 100
}
function getElement(arg) {
if (typeof arg === 'string') {
return document.getElementById(arg)
}
return arg
}
async function initFaceDetectionNet() {
const res = await axios.get('face_detection_model.weights', { responseType: 'arraybuffer' })
const weights = new Float32Array(res.data)
return facerecognition.faceDetectionNet(weights)
}
async function initFaceRecognitionNet() {
const res = await axios.get('face_recognition_model.weights', { responseType: 'arraybuffer' })
const weights = new Float32Array(res.data)
return facerecognition.faceRecognitionNet(weights)
}
function bufferToImgSrc(buf) {
return new Promise((resolve, reject) => {
const reader = new window.FileReader()
reader.onload = () => resolve(reader.result)
reader.onerror = reject
reader.readAsDataURL(buf)
})
function drawImgToCanvas(canvasArg, imgArg) {
const canvas = getElement(canvasArg)
const img = getElement(imgArg)
canvas.width = img.width
canvas.height = img.height
const ctx = canvas.getContext('2d')
ctx.drawImage(img, 0, 0, img.width, img.height)
return ctx
}
function imgSrcToData(src) {
function imgSrcToImageData(src) {
return new Promise((resolve, reject) => {
const canvas = document.createElement('canvas')
canvas.width = 150
canvas.height = 150
const ctx = canvas.getContext('2d')
const img = new Image()
img.onload = function() {
ctx.drawImage(img, 0, 0)
resolve(ctx.getImageData(0, 0, 150, 150))
const ctx = drawImgToCanvas(document.createElement('canvas'), img)
resolve(ctx.getImageData(0, 0, img.width, img.height))
}
img.onerror = reject
img.src = src
})
}
function bufferToImgSrc(buf) {
return new Promise((resolve, reject) => {
const reader = new window.FileReader()
reader.onload = () => resolve(reader.result)
reader.onerror = reject
reader.readAsDataURL(buf)
})
}
async function bufferToImageData(buf) {
return imgSrcToData(await bufferToImgSrc(buf))
return imgSrcToImageData(await bufferToImgSrc(buf))
}
async function fetchImage(uri) {
return (await axios.get(uri, { responseType: 'blob' })).data
function drawBox(canvasArg, x, y, w, h, lineWidth = 2, color = 'blue') {
const canvas = getElement(canvasArg)
const ctx = canvas.getContext('2d')
ctx.strokeStyle = color
ctx.lineWidth = lineWidth
ctx.strokeRect(x, y, w, h)
}
function round(num) {
return Math.floor(num * 100) / 100
function drawText(canvasArg, x, y, text, fontSize = 20, fontStyle = 'Georgia', color = 'blue') {
const canvas = getElement(canvasArg)
const ctx = canvas.getContext('2d')
ctx.fillStyle = color
ctx.font = fontSize + 'px ' + fontStyle
ctx.fillText(text, x, y)
}
function drawDetection(canvasArg, detection, options = {}) {
const canvas = getElement(canvasArg)
const detectionArray = Array.isArray(detection)
? detection
: [detection]
detectionArray.forEach((det) => {
const {
score,
box
} = det
const {
left,
right,
top,
bottom
} = box
const {
color,
lineWidth = 2,
fontSize = 20,
fontStyle,
withScore = true
} = options
const padText = 2 + lineWidth
drawBox(
canvas,
left,
top,
right - left,
bottom - top,
lineWidth,
color
)
if (withScore) {
drawText(
canvas,
left + padText,
top + (fontSize * 0.6) + padText,
round(score),
fontSize,
fontStyle,
color
)
}
})
}
function renderNavBar(navbarId, exampleUri) {
......
.page-container {
position: fixed;
left: 0;
right: 0;
margin: auto;
......@@ -30,8 +29,3 @@
.margin {
margin: 20px;
}
\ No newline at end of file
img {
width: 150px;
height: 150px;
}
\ No newline at end of file
......@@ -12,21 +12,70 @@
<body>
<div class="center-content page-container">
<div id="navbar"></div>
<div class="center-content">
<img id="img" src="" class="margin"/>
<div id="selectList" class="input-field"></div>
<div class="progress" id="loader">
<div class="indeterminate"></div>
</div>
<div style="position: relative" class="margin">
<img id="img" src="" />
<canvas id="overlay" style="position: absolute; top: 0; left: 0;" />
</div>
<div class="row side-by-side">
<div id="selectList"></div>
<div class="row">
<label for="minConfidence">Min Confidence:</label>
<input disabled value="0.7" id="minConfidence" type="text" class="bold">
</div>
<button
class="waves-effect waves-light btn"
onclick="onDecreaseThreshold()"
>
<i class="material-icons left">-</i>
</button>
<button
class="waves-effect waves-light btn"
onclick="onIncreaseThreshold()"
>
<i class="material-icons left">+</i>
</button>
</div>
</div>
<script>
let minConfidence = 0.7
let net, result
function onIncreaseThreshold() {
minConfidence = Math.min(round(minConfidence + 0.1), 1.0)
$('#minConfidence').val(minConfidence)
updateResults()
}
function onDecreaseThreshold() {
minConfidence = Math.max(round(minConfidence - 0.1), 0.1)
$('#minConfidence').val(minConfidence)
updateResults()
}
async function updateResults() {
result = await net.locateFaces(await imgSrcToImageData($(`#img`).get(0).src), minConfidence)
drawImgToCanvas('overlay', 'img')
drawDetection('overlay', result)
}
async function onSelectionChanged(uri) {
const imgBuf = await fetchImage(uri)
const imgEl = $(`#img`).get(0)
imgEl.src = await bufferToImgSrc(imgBuf)
$(`#img`).get(0).src = await bufferToImgSrc(imgBuf)
updateResults()
}
async function run() {
net = await initFaceDetectionNet()
$('#loader').hide()
onSelectionChanged($('#selectList select').val())
}
$(document).ready(function() {
renderNavBar('#navbar')
renderNavBar('#navbar', 'face_detection')
renderImageSelectList(
'#selectList',
async (uri) => {
......@@ -34,7 +83,7 @@
},
1
)
onSelectionChanged($('#selectList select').val())
run()
})
</script>
</body>
......
......@@ -71,17 +71,17 @@
let isStop = false
let trainDescriptorsByClass = []
let net = {}
let net
let currImageIdx = 2, currClassIdx = 0
let to = null
function onSlower() {
interval = Math.max(interval + 100, 0)
interval = Math.min(interval + 100, 2000)
$('#interval').val(interval)
}
function onFaster() {
interval = Math.min(interval - 100, 2000)
interval = Math.max(interval - 100, 0)
$('#interval').val(interval)
}
......@@ -136,7 +136,7 @@
const imgEl = $('#face').get(0)
imgEl.src = await bufferToImgSrc(imgBuf)
const imageData = await imgSrcToData(imgEl.src)
const imageData = await imgSrcToImageData(imgEl.src)
const ts = Date.now()
const result = await net.forward(imageData)
......@@ -161,7 +161,7 @@
try {
setStatusText('loading model file...')
net = await initNet()
net = await initFaceRecognitionNet()
setStatusText('computing initial descriptors...')
const trainImgDatas = await loadTrainingData()
......
......@@ -20,11 +20,11 @@
<div class="row side-by-side">
<div class="center-content">
<img id="face1" src="" class="margin"/>
<div id="selectList1" class="input-field"></div>
<div id="selectList1"></div>
</div>
<div class="center-content">
<img id="face2" src="" class="margin"/>
<div id="selectList2" class="input-field"></div>
<div id="selectList2"></div>
</div>
</div>
<div class="row">
......@@ -52,7 +52,7 @@
}
async function computeDescriptorFromSrc(imgEl) {
return net.computeFaceDescriptor(await imgSrcToData(imgEl.src))
return net.computeFaceDescriptor(await imgSrcToImageData(imgEl.src))
}
async function onSelectionChanged(which, uri) {
......@@ -63,7 +63,7 @@
}
async function run() {
net = await initNet()
net = await initFaceRecognitionNet()
$('#loader').hide()
await onSelectionChanged(1, $('#selectList1 select').val())
await onSelectionChanged(2, $('#selectList2 select').val())
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment