Commit 1416877d by vincent

new face recognition example

parent 174e0c28
...@@ -57,14 +57,18 @@ function renderNavBar(navbarId, exampleUri) { ...@@ -57,14 +57,18 @@ function renderNavBar(navbarId, exampleUri) {
name: 'BBT Face Landmark Detection' name: 'BBT Face Landmark Detection'
}, },
{ {
uri: 'bbt_face_recognition',
name: 'BBT Face Recognition'
},
{
uri: 'bbt_face_similarity', uri: 'bbt_face_similarity',
name: 'BBT Face Similarity' name: 'BBT Face Similarity'
}, },
{ {
uri: 'bbt_face_matching',
name: 'BBT Face Matching'
},
{
uri: 'bbt_face_recognition',
name: 'BBT Face Recognition'
},
{
uri: 'batch_face_landmarks', uri: 'batch_face_landmarks',
name: 'Batch Face Landmark Detection' name: 'Batch Face Landmark Detection'
}, },
......
...@@ -61,13 +61,7 @@ ...@@ -61,13 +61,7 @@
margin-bottom: 10px; margin-bottom: 10px;
} }
#overlay { #overlay, .overlay {
position: absolute;
top: 0;
left: 0;
}
.overlay {
position: absolute; position: absolute;
top: 0; top: 0;
left: 0; left: 0;
......
...@@ -19,8 +19,9 @@ app.get('/', (req, res) => res.redirect('/face_detection')) ...@@ -19,8 +19,9 @@ app.get('/', (req, res) => res.redirect('/face_detection'))
app.get('/batch_face_landmarks', (req, res) => res.sendFile(path.join(viewsDir, 'batchFaceLandmarks.html'))) app.get('/batch_face_landmarks', (req, res) => res.sendFile(path.join(viewsDir, 'batchFaceLandmarks.html')))
app.get('/batch_face_recognition', (req, res) => res.sendFile(path.join(viewsDir, 'batchFaceRecognition.html'))) app.get('/batch_face_recognition', (req, res) => res.sendFile(path.join(viewsDir, 'batchFaceRecognition.html')))
app.get('/bbt_face_landmark_detection', (req, res) => res.sendFile(path.join(viewsDir, 'bbtFaceLandmarkDetection.html'))) app.get('/bbt_face_landmark_detection', (req, res) => res.sendFile(path.join(viewsDir, 'bbtFaceLandmarkDetection.html')))
app.get('/bbt_face_recognition', (req, res) => res.sendFile(path.join(viewsDir, 'bbtFaceRecognition.html')))
app.get('/bbt_face_similarity', (req, res) => res.sendFile(path.join(viewsDir, 'bbtFaceSimilarity.html'))) app.get('/bbt_face_similarity', (req, res) => res.sendFile(path.join(viewsDir, 'bbtFaceSimilarity.html')))
app.get('/bbt_face_matching', (req, res) => res.sendFile(path.join(viewsDir, 'bbtFaceMatching.html')))
app.get('/bbt_face_recognition', (req, res) => res.sendFile(path.join(viewsDir, 'bbtFaceRecognition.html')))
app.get('/face_detection', (req, res) => res.sendFile(path.join(viewsDir, 'faceDetection.html'))) app.get('/face_detection', (req, res) => res.sendFile(path.join(viewsDir, 'faceDetection.html')))
app.get('/face_extraction', (req, res) => res.sendFile(path.join(viewsDir, 'faceExtraction.html'))) app.get('/face_extraction', (req, res) => res.sendFile(path.join(viewsDir, 'faceExtraction.html')))
app.get('/face_landmark_detection', (req, res) => res.sendFile(path.join(viewsDir, 'faceLandmarkDetection.html'))) app.get('/face_landmark_detection', (req, res) => res.sendFile(path.join(viewsDir, 'faceLandmarkDetection.html')))
......
<!DOCTYPE html>
<html>
<head>
<script src="face-api.js"></script>
<script src="js/commons.js"></script>
<script src="js/bbt.js"></script>
<link rel="stylesheet" href="styles.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.100.2/css/materialize.css">
<script type="text/javascript" src="https://code.jquery.com/jquery-2.1.1.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.100.2/js/materialize.min.js"></script>
</head>
<body>
<div id="navbar"></div>
<div class="center-content page-container">
<div>
<div class="row center-content" id="loader">
<input disabled value="" id="status" type="text" class="bold">
<div class="progress">
<div class="indeterminate"></div>
</div>
</div>
<div class="row center-content">
<img id="face" src=""/>
</div>
<div class="row">
<label for="prediction">Prediction:</label>
<input disabled value="-" id="prediction" type="text" class="bold">
</div>
<div class="row">
<label for="time">Time:</label>
<input disabled value="-" id="time" type="text" class="bold">
</div>
<div class="row">
<label for="fps">Estimated Fps:</label>
<input disabled value="-" id="fps" type="text" class="bold">
</div>
<div class="row">
<button
class="waves-effect waves-light btn"
id="stop"
onclick="onToggleStop()"
>
Stop
</button>
<button
class="waves-effect waves-light btn"
onclick="onSlower()"
>
<i class="material-icons left">-</i> Slower
</button>
<button
class="waves-effect waves-light btn"
onclick="onFaster()"
>
<i class="material-icons left">+</i> Faster
</button>
</div>
<div class="row">
<label for="interval">Interval:</label>
<input disabled value="2000" id="interval" type="text" class="bold">
</div>
</div>
</div>
<script>
let interval = 2000
let isStop = false
let faceMatcher = null
let currImageIdx = 2, currClassIdx = 0
let to = null
function onSlower() {
interval = Math.min(interval + 100, 2000)
$('#interval').val(interval)
}
function onFaster() {
interval = Math.max(interval - 100, 0)
$('#interval').val(interval)
}
function onToggleStop() {
clearTimeout(to)
isStop = !isStop
document.getElementById('stop').innerHTML = isStop ? 'Continue' : 'Stop'
setStatusText(isStop ? 'stopped' : 'running face recognition:')
if (!isStop) {
runFaceRecognition()
}
}
function setStatusText(text) {
$('#status').val(text)
}
function displayTimeStats(timeInMs) {
$('#time').val(`${timeInMs} ms`)
$('#fps').val(`${faceapi.round(1000 / timeInMs)}`)
}
function displayImage(src) {
getImg().src = src
}
async function runFaceRecognition() {
async function next() {
const input = await faceapi.fetchImage(getFaceImageUri(classes[currClassIdx], currImageIdx))
const imgEl = $('#face').get(0)
imgEl.src = input.src
const ts = Date.now()
const descriptor = await faceapi.computeFaceDescriptor(input)
displayTimeStats(Date.now() - ts)
const bestMatch = faceMatcher.findBestMatch(descriptor)
$('#prediction').val(bestMatch.toString())
currImageIdx = currClassIdx === (classes.length - 1)
? currImageIdx + 1
: currImageIdx
currClassIdx = (currClassIdx + 1) % classes.length
currImageIdx = (currImageIdx % 6) || 2
to = setTimeout(next, interval)
}
await next(0, 0)
}
async function run() {
try {
setStatusText('loading model file...')
await faceapi.loadFaceRecognitionModel('/')
setStatusText('computing initial descriptors...')
faceMatcher = await createBbtFaceMatcher(1)
$('#loader').hide()
runFaceRecognition()
} catch (err) {
console.error(err)
}
}
$(document).ready(function() {
renderNavBar('#navbar', 'bbt_face_matching')
run()
})
</script>
</body>
</html>
\ No newline at end of file
...@@ -3,6 +3,9 @@ ...@@ -3,6 +3,9 @@
<head> <head>
<script src="face-api.js"></script> <script src="face-api.js"></script>
<script src="js/commons.js"></script> <script src="js/commons.js"></script>
<script src="js/drawing.js"></script>
<script src="js/faceDetectionControls.js"></script>
<script src="js/imageSelectionControls.js"></script>
<script src="js/bbt.js"></script> <script src="js/bbt.js"></script>
<link rel="stylesheet" href="styles.css"> <link rel="stylesheet" href="styles.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.100.2/css/materialize.css"> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.100.2/css/materialize.css">
...@@ -12,144 +15,182 @@ ...@@ -12,144 +15,182 @@
<body> <body>
<div id="navbar"></div> <div id="navbar"></div>
<div class="center-content page-container"> <div class="center-content page-container">
<div>
<div class="row center-content" id="loader"> <div class="progress" id="loader">
<input disabled value="" id="status" type="text" class="bold">
<div class="progress">
<div class="indeterminate"></div> <div class="indeterminate"></div>
</div> </div>
<div style="position: relative" class="margin">
<img id="inputImg" src="" style="max-width: 800px;" />
<canvas id="overlay" />
</div> </div>
<div class="row center-content">
<img id="face" src=""/> <div class="row side-by-side">
<!-- face_detector_selection_control -->
<div id="face_detector_selection_control" class="row input-field" style="margin-right: 20px;">
<select id="selectFaceDetector">
<option value="ssd_mobilenetv1">SSD Mobilenet V1</option>
<option value="tiny_face_detector">Tiny Face Detector</option>
<option value="mtcnn">MTCNN</option>
</select>
<label>Select Face Detector</label>
</div> </div>
<!-- face_detector_selection_control -->
<!-- image_selection_control -->
<div id="image_selection_control"></div>
<div id="selectList"></div>
<div class="row"> <div class="row">
<label for="prediction">Prediction:</label> <label for="imgUrlInput">Get image from URL:</label>
<input disabled value="-" id="prediction" type="text" class="bold"> <input id="imgUrlInput" type="text" class="bold">
</div> </div>
<div class="row"> <button
<label for="time">Time:</label> class="waves-effect waves-light btn"
<input disabled value="-" id="time" type="text" class="bold"> onclick="loadImageFromUrl()"
>
Ok
</button>
<div id="image_selection_control"></div>
<!-- image_selection_control -->
</div> </div>
<!-- ssd_mobilenetv1_controls -->
<span id="ssd_mobilenetv1_controls">
<div class="row side-by-side">
<div class="row"> <div class="row">
<label for="fps">Estimated Fps:</label> <label for="minConfidence">Min Confidence:</label>
<input disabled value="-" id="fps" type="text" class="bold"> <input disabled value="0.7" id="minConfidence" type="text" class="bold">
</div> </div>
<div class="row">
<button <button
class="waves-effect waves-light btn" class="waves-effect waves-light btn"
id="stop" onclick="onDecreaseMinConfidence()"
onclick="onToggleStop()"
> >
Stop <i class="material-icons left">-</i>
</button> </button>
<button <button
class="waves-effect waves-light btn" class="waves-effect waves-light btn"
onclick="onSlower()" onclick="onIncreaseMinConfidence()"
> >
<i class="material-icons left">-</i> Slower <i class="material-icons left">+</i>
</button>
</div>
</span>
<!-- ssd_mobilenetv1_controls -->
<!-- tiny_face_detector_controls -->
<span id="tiny_face_detector_controls">
<div class="row side-by-side">
<div class="row input-field" style="margin-right: 20px;">
<select id="inputSize">
<option value="" disabled selected>Input Size:</option>
<option value="160">160 x 160</option>
<option value="224">224 x 224</option>
<option value="320">320 x 320</option>
<option value="416">416 x 416</option>
<option value="512">512 x 512</option>
<option value="608">608 x 608</option>
</select>
<label>Input Size</label>
</div>
<div class="row">
<label for="scoreThreshold">Score Threshold:</label>
<input disabled value="0.5" id="scoreThreshold" type="text" class="bold">
</div>
<button
class="waves-effect waves-light btn"
onclick="onDecreaseScoreThreshold()"
>
<i class="material-icons left">-</i>
</button> </button>
<button <button
class="waves-effect waves-light btn" class="waves-effect waves-light btn"
onclick="onFaster()" onclick="onIncreaseScoreThreshold()"
> >
<i class="material-icons left">+</i> Faster <i class="material-icons left">+</i>
</button> </button>
</div> </div>
</span>
<!-- tiny_face_detector_controls -->
<!-- mtcnn_controls -->
<span id="mtcnn_controls">
<div class="row side-by-side">
<div class="row"> <div class="row">
<label for="interval">Interval:</label> <label for="minFaceSize">Minimum Face Size:</label>
<input disabled value="2000" id="interval" type="text" class="bold"> <input disabled value="20" id="minFaceSize" type="text" class="bold">
</div>
</div> </div>
<button
class="waves-effect waves-light btn"
onclick="onDecreaseMinFaceSize()"
>
<i class="material-icons left">-</i>
</button>
<button
class="waves-effect waves-light btn"
onclick="onIncreaseMinFaceSize()"
>
<i class="material-icons left">+</i>
</button>
</div> </div>
</span>
<!-- mtcnn_controls -->
<script> </body>
let interval = 2000
let isStop = false <script>
let faceMatcher = null let faceMatcher = null
let currImageIdx = 2, currClassIdx = 0
let to = null
function onSlower() {
interval = Math.min(interval + 100, 2000)
$('#interval').val(interval)
}
function onFaster() { async function updateResults() {
interval = Math.max(interval - 100, 0) if (!isFaceDetectionModelLoaded()) {
$('#interval').val(interval) return
}
function onToggleStop() {
clearTimeout(to)
isStop = !isStop
document.getElementById('stop').innerHTML = isStop ? 'Continue' : 'Stop'
setStatusText(isStop ? 'stopped' : 'running face recognition:')
if (!isStop) {
runFaceRecognition()
}
} }
function setStatusText(text) { const inputImgEl = $('#inputImg').get(0)
$('#status').val(text)
}
function displayTimeStats(timeInMs) { const options = getFaceDetectorOptions()
$('#time').val(`${timeInMs} ms`) const results = await faceapi
$('#fps').val(`${faceapi.round(1000 / timeInMs)}`) .detectAllFaces(inputImgEl, options)
} .withFaceLandmarks()
.withFaceDescriptors()
function displayImage(src) { drawFaceRecognitionResults(results)
getImg().src = src
} }
async function runFaceRecognition() { function drawFaceRecognitionResults(results) {
async function next() { const canvas = $('#overlay').get(0)
const input = await faceapi.fetchImage(getFaceImageUri(classes[currClassIdx], currImageIdx)) // resize detection and landmarks in case displayed image is smaller than
const imgEl = $('#face').get(0) // original size
imgEl.src = input.src resizedResults = resizeCanvasAndResults($('#inputImg').get(0), canvas, results)
const ts = Date.now() const boxesWithText = resizedResults.map(({ detection, descriptor }) =>
const descriptor = await faceapi.computeFaceDescriptor(input) new faceapi.BoxWithText(
displayTimeStats(Date.now() - ts) detection.box,
faceMatcher.findBestMatch(descriptor).toString()
const bestMatch = faceMatcher.findBestMatch(descriptor) )
$('#prediction').val(bestMatch.toString()) )
faceapi.drawDetection(canvas, boxesWithText)
currImageIdx = currClassIdx === (classes.length - 1)
? currImageIdx + 1
: currImageIdx
currClassIdx = (currClassIdx + 1) % classes.length
currImageIdx = (currImageIdx % 6) || 2
to = setTimeout(next, interval)
}
await next(0, 0)
} }
async function run() { async function run() {
try { // load face detection, face landmark model and face recognition models
setStatusText('loading model file...') await changeFaceDetector(selectedFaceDetector)
await faceapi.loadFaceLandmarkModel('/')
await faceapi.loadFaceRecognitionModel('/') await faceapi.loadFaceRecognitionModel('/')
setStatusText('computing initial descriptors...') // initialize face matcher with 1 reference descriptor per bbt character
faceMatcher = await createBbtFaceMatcher(1) faceMatcher = await createBbtFaceMatcher(1)
$('#loader').hide()
runFaceRecognition() // start processing image
} catch (err) { updateResults()
console.error(err)
}
} }
$(document).ready(function() { $(document).ready(function() {
renderNavBar('#navbar', 'bbt_face_recognition') renderNavBar('#navbar', 'bbt_face_recognition')
initImageSelectionControls()
initFaceDetectionControls()
run() run()
}) })
</script> </script>
</body> </body>
</html> </html>
\ No newline at end of file
...@@ -37,7 +37,6 @@ ...@@ -37,7 +37,6 @@
<!-- face_detector_selection_control --> <!-- face_detector_selection_control -->
<!-- image_selection_control --> <!-- image_selection_control -->
<div id="image_selection_control"></div>
<div id="selectList"></div> <div id="selectList"></div>
<div class="row"> <div class="row">
<label for="imgUrlInput">Get image from URL:</label> <label for="imgUrlInput">Get image from URL:</label>
...@@ -49,7 +48,6 @@ ...@@ -49,7 +48,6 @@
> >
Ok Ok
</button> </button>
<div id="image_selection_control"></div>
<!-- image_selection_control --> <!-- image_selection_control -->
</div> </div>
......
...@@ -35,7 +35,6 @@ ...@@ -35,7 +35,6 @@
<!-- face_detector_selection_control --> <!-- face_detector_selection_control -->
<!-- image_selection_control --> <!-- image_selection_control -->
<div id="image_selection_control"></div>
<div id="selectList"></div> <div id="selectList"></div>
<div class="row"> <div class="row">
<label for="imgUrlInput">Get image from URL:</label> <label for="imgUrlInput">Get image from URL:</label>
...@@ -47,7 +46,6 @@ ...@@ -47,7 +46,6 @@
> >
Ok Ok
</button> </button>
<div id="image_selection_control"></div>
<!-- image_selection_control --> <!-- image_selection_control -->
</div> </div>
......
...@@ -37,7 +37,6 @@ ...@@ -37,7 +37,6 @@
<!-- face_detector_selection_control --> <!-- face_detector_selection_control -->
<!-- image_selection_control --> <!-- image_selection_control -->
<div id="image_selection_control"></div>
<div id="selectList"></div> <div id="selectList"></div>
<div class="row"> <div class="row">
<label for="imgUrlInput">Get image from URL:</label> <label for="imgUrlInput">Get image from URL:</label>
...@@ -49,7 +48,6 @@ ...@@ -49,7 +48,6 @@
> >
Ok Ok
</button> </button>
<div id="image_selection_control"></div>
<!-- image_selection_control --> <!-- image_selection_control -->
</div> </div>
......
...@@ -5,8 +5,6 @@ ...@@ -5,8 +5,6 @@
<script src="js/commons.js"></script> <script src="js/commons.js"></script>
<script src="js/drawing.js"></script> <script src="js/drawing.js"></script>
<script src="js/faceDetectionControls.js"></script> <script src="js/faceDetectionControls.js"></script>
<script src="js/imageSelectionControls.js"></script>
<script src="js/bbt.js"></script>
<link rel="stylesheet" href="styles.css"> <link rel="stylesheet" href="styles.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.100.2/css/materialize.css"> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.100.2/css/materialize.css">
<script type="text/javascript" src="https://code.jquery.com/jquery-2.1.1.min.js"></script> <script type="text/javascript" src="https://code.jquery.com/jquery-2.1.1.min.js"></script>
...@@ -16,45 +14,82 @@ ...@@ -16,45 +14,82 @@
<div id="navbar"></div> <div id="navbar"></div>
<div class="center-content page-container"> <div class="center-content page-container">
<p> Reference Image: </p>
<div class="progress" id="loader"> <div class="progress" id="loader">
<div class="indeterminate"></div> <div class="indeterminate"></div>
</div> </div>
<div style="position: relative" class="margin"> <div style="position: relative" class="margin">
<img id="inputImg" src="" style="max-width: 800px;" /> <img id="refImg" src="" style="max-width: 800px;" />
<canvas id="overlay" /> <canvas id="refImgOverlay" class="overlay"/>
</div> </div>
<div class="row side-by-side"> <div class="row side-by-side">
<!-- face_detector_selection_control --> <!-- image_selection_control -->
<div id="face_detector_selection_control" class="row input-field" style="margin-right: 20px;"> <div class="row">
<select id="selectFaceDetector"> <label>Upload Image:</label>
<option value="ssd_mobilenetv1">SSD Mobilenet V1</option> <div>
<option value="tiny_face_detector">Tiny Face Detector</option> <input id="refImgUploadInput" type="file" class="bold" onchange="uploadRefImage()" accept=".jpg, .jpeg, .png">
<option value="mtcnn">MTCNN</option>
</select>
<label>Select Face Detector</label>
</div> </div>
<!-- face_detector_selection_control --> </div>
<div class="row">
<label for="refImgUrlInput">Get image from URL:</label>
<input id="refImgUrlInput" type="text" class="bold">
</div>
<button
class="waves-effect waves-light btn"
onclick="loadRefImageFromUrl()"
>
Ok
</button>
<!-- image_selection_control -->
</div>
<p> Query Image: </p>
<div style="position: relative" class="margin">
<img id="queryImg" src="" style="max-width: 800px;" />
<canvas id="queryImgOverlay" class="overlay"/>
</div>
<div class="row side-by-side">
<!-- image_selection_control --> <!-- image_selection_control -->
<div id="image_selection_control"></div>
<div id="selectList"></div>
<div class="row"> <div class="row">
<label for="imgUrlInput">Get image from URL:</label> <label>Upload Image:</label>
<input id="imgUrlInput" type="text" class="bold"> <div>
<input id="queryImgUploadInput" type="file" class="bold" onchange="uploadQueryImage()" accept=".jpg, .jpeg, .png">
</div>
</div>
<div class="row">
<label for="queryImgUrlInput">Get image from URL:</label>
<input id="queryImgUrlInput" type="text" class="bold">
</div> </div>
<button <button
class="waves-effect waves-light btn" class="waves-effect waves-light btn"
onclick="loadImageFromUrl()" onclick="loadQueryImageFromUrl()"
> >
Ok Ok
</button> </button>
<div id="image_selection_control"></div>
<!-- image_selection_control --> <!-- image_selection_control -->
</div> </div>
<div class="center-content">
<!-- face_detector_selection_control -->
<div id="face_detector_selection_control" class="row input-field">
<select id="selectFaceDetector">
<option value="ssd_mobilenetv1">SSD Mobilenet V1</option>
<option value="tiny_face_detector">Tiny Face Detector</option>
<option value="mtcnn">MTCNN</option>
</select>
<label>Select Face Detector</label>
</div>
<!-- face_detector_selection_control -->
<!-- ssd_mobilenetv1_controls --> <!-- ssd_mobilenetv1_controls -->
<span id="ssd_mobilenetv1_controls"> <span id="ssd_mobilenetv1_controls">
<div class="row side-by-side"> <div class="row side-by-side">
...@@ -136,58 +171,110 @@ ...@@ -136,58 +171,110 @@
</span> </span>
<!-- mtcnn_controls --> <!-- mtcnn_controls -->
</div>
</body> </body>
<script> <script>
let faceMatcher = null let faceMatcher = null
async function updateResults() { async function uploadRefImage(e) {
if (!isFaceDetectionModelLoaded()) { const imgFile = $('#refImgUploadInput').get(0).files[0]
return const img = await faceapi.bufferToImage(imgFile)
$('#refImg').get(0).src = img.src
updateReferenceImageResults()
} }
const inputImgEl = $('#inputImg').get(0) async function loadRefImageFromUrl(url) {
const img = await requestExternalImage($('#refImgUrlInput').val())
$('#refImg').get(0).src = img.src
updateReferenceImageResults()
}
const options = getFaceDetectorOptions() async function uploadQueryImage(e) {
const results = await faceapi const imgFile = $('#queryImgUploadInput').get(0).files[0]
.detectAllFaces(inputImgEl, options) const img = await faceapi.bufferToImage(imgFile)
$('#queryImg').get(0).src = img.src
updateQueryImageResults()
}
async function loadQueryImageFromUrl(url) {
const img = await requestExternalImage($('#queryImgUrlInput').val())
$('#queryImg').get(0).src = img.src
updateQueryImageResults()
}
async function updateReferenceImageResults() {
const imgEl = $('#refImg').get(0)
const canvas = $('#refImgOverlay').get(0)
const fullFaceDescriptions = await faceapi
.detectAllFaces(imgEl, getFaceDetectorOptions())
.withFaceLandmarks() .withFaceLandmarks()
.withFaceDescriptors() .withFaceDescriptors()
drawFaceRecognitionResults(results) if (!fullFaceDescriptions.length) {
return
} }
function drawFaceRecognitionResults(results) { // create FaceMatcher with automatically assigned labels
const canvas = $('#overlay').get(0) // from the detection results for the reference image
faceMatcher = new faceapi.FaceMatcher(fullFaceDescriptions)
// resize detection and landmarks in case displayed image is smaller than // resize detection and landmarks in case displayed image is smaller than
// original size // original size
resizedResults = resizeCanvasAndResults($('#inputImg').get(0), canvas, results) resizedResults = resizeCanvasAndResults(imgEl, canvas, fullFaceDescriptions)
// draw boxes with the corresponding label as text
const labels = faceMatcher.labeledDescriptors
.map(ld => ld.label)
const boxesWithText = resizedResults
.map(res => res.detection.box)
.map((box, i) => new faceapi.BoxWithText(box, labels[i]))
faceapi.drawDetection(canvas, boxesWithText)
}
async function updateQueryImageResults() {
if (!faceMatcher) {
return
}
const imgEl = $('#queryImg').get(0)
const canvas = $('#queryImgOverlay').get(0)
const results = await faceapi
.detectAllFaces(imgEl, getFaceDetectorOptions())
.withFaceLandmarks()
.withFaceDescriptors()
// resize detection and landmarks in case displayed image is smaller than
// original size
resizedResults = resizeCanvasAndResults(imgEl, canvas, results)
// draw boxes with the corresponding label as text
const boxesWithText = resizedResults.map(({ detection, descriptor }) => const boxesWithText = resizedResults.map(({ detection, descriptor }) =>
new faceapi.BoxWithText( new faceapi.BoxWithText(
detection.box, detection.box,
// match each face descriptor to the reference descriptor
// with lowest euclidean distance and display the result as text
faceMatcher.findBestMatch(descriptor).toString() faceMatcher.findBestMatch(descriptor).toString()
) )
) )
faceapi.drawDetection(canvas, boxesWithText) faceapi.drawDetection(canvas, boxesWithText)
} }
async function updateResults() {
await updateReferenceImageResults()
await updateQueryImageResults()
}
async function run() { async function run() {
// load face detection, face landmark model and face recognition models // load face detection, face landmark model and face recognition models
await changeFaceDetector(selectedFaceDetector) await changeFaceDetector(selectedFaceDetector)
await faceapi.loadFaceLandmarkModel('/') await faceapi.loadFaceLandmarkModel('/')
await faceapi.loadFaceRecognitionModel('/') await faceapi.loadFaceRecognitionModel('/')
// initialize face matcher with 1 reference descriptor per bbt character
faceMatcher = await createBbtFaceMatcher(1)
// start processing image
updateResults()
} }
$(document).ready(function() { $(document).ready(function() {
renderNavBar('#navbar', 'face_recognition') renderNavBar('#navbar', 'face_recognition')
initImageSelectionControls()
initFaceDetectionControls() initFaceDetectionControls()
run() run()
}) })
......
import { ISsdMobilenetv1Options } from './types'; import { ISsdMobilenetv1Options } from './types';
export class SsdMobilenetv1Options { export class SsdMobilenetv1Options {
protected _name: string = 'MtcnnOptions' protected _name: string = 'SsdMobilenetv1Options'
private _minConfidence: number private _minConfidence: number
private _maxResults: number private _maxResults: number
......
...@@ -9,8 +9,8 @@ ...@@ -9,8 +9,8 @@
<script> <script>
tf = faceapi.tf tf = faceapi.tf
const uncompressedWeightsUri = `face_landmark_68_model.weights` const uncompressedWeightsUri = `tiny_face_detector_model.weights`
const net = new faceapi.FaceLandmark68LargeNet() const net = new faceapi.TinyFaceDetector()
async function load() { async function load() {
await net.load(new Float32Array(await (await fetch(uncompressedWeightsUri)).arrayBuffer())) await net.load(new Float32Array(await (await fetch(uncompressedWeightsUri)).arrayBuffer()))
...@@ -21,7 +21,7 @@ ...@@ -21,7 +21,7 @@
return net.getParamList().map(({ path, tensor }) => ({ name: path, tensor })) return net.getParamList().map(({ path, tensor }) => ({ name: path, tensor }))
} }
const modelName = 'face_landmark_68' const modelName = 'tiny_face_detector'
function makeShards(weightArray) { function makeShards(weightArray) {
const maxLength = 4096 * 1024 const maxLength = 4096 * 1024
......
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