https://github.com/adelpro/face-api-detection
Face detection using Face-api.js and vanilla JavaScript
https://github.com/adelpro/face-api-detection
Last synced: 6 months ago
JSON representation
Face detection using Face-api.js and vanilla JavaScript
- Host: GitHub
- URL: https://github.com/adelpro/face-api-detection
- Owner: adelpro
- License: gpl-3.0
- Created: 2023-04-03T09:25:59.000Z (over 3 years ago)
- Default Branch: main
- Last Pushed: 2024-12-17T13:56:27.000Z (over 1 year ago)
- Last Synced: 2025-04-14T07:30:20.555Z (over 1 year ago)
- Language: JavaScript
- Size: 5.28 MB
- Stars: 3
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
In this step by step tutorial, we will learn how to use Face-api.js and vanilla JavaScript to detect faces and expressions in real-time, all that from the browser, no back-end needed.
### **What is Face-api.js?**
[Face-api.js](https://justadudewhohacks.github.io/face-api.js/) is a JavaScript API for face detection and face recognition directly in the browser implemented build on top of the tensorflow.js
### **What are we building?**
In this tutorial we will build a simple application that streams a video from the webcam of the PC or the camera of the phone, search for any faces present in it, and show a blue rectangle containing: the age, the gender and the expression for each face.
### **List of models that we will use in our Tutorial**
#### **Tiny Face Detector**
Very performant, real time face detector, This model is extremely mobile and web friendly, thus it should be your GO-TO face detector on mobile devices and resource limited clients. The size of the quantized model is only 190 KB (**tiny\_face\_detector\_model**).
#### **68 Point Face Landmark Detection Models**
This package implements a very lightweight and fast, yet accurate 68 point face landmark detector. The default model has a size of only 350kb (**face\_landmark\_68\_model**) and the tiny model is only 80kb (**face\_landmark\_68\_tiny\_model**). Both models employ the ideas of depth wise separable convolutions as well as densely connected blocks. The models have been trained on a dataset of ~35k face images labelled with 68 face landmark points.
#### **Age Gender model**
Age estimation and gender recognition model from detected faces ( for each face detected in the image or the video).
#### **Face expression model**
Face expression recognition model, can detect expressions in an image or a video of each face.
### **Let’s code**
Our application structure will look like this:
```plaintext
/Root
├─ /models
├─ app.js
├─ face-api.min.js
├─ styles.css
└─ index.html
```
#### **./models**
Contain the files of all the trained models to use with our Face-api.js API.
%[https://github.com/adelpro/face-api-detection/tree/0796c1df82306cd8b6e7e837036399559572b23c/models]
#### **face-api.min.js**
Contain the code of our face-api API (minified), you can download this file from here:
%[https://github.com/adelpro/face-api-detection/blob/0796c1df82306cd8b6e7e837036399559572b23c/face-api.min.js]
#### **styles.css**
A simple CSS files to style our application:
```css
.container {
display: flex;
justify-content: centre;
flex-direction: column;
align-items: centre;
height: 100vh;
text-align: centre;
flex: 1;
}
.video-container {
position: relative;
}
canvas {
position: absolute;
top: 0;
left: 0;
}
```
As you can see we have a canvas element that will be positioned over our video, and we will use it to draw our face detection.
#### **index.html**
This file contain all the necessary HTML code for your application, we will do all the logic in our app.js
```xml
Face-API AI Real-Time Facial Detection
Real-Time facial detection
We will use Javascript and Face-API to create a real time facial detection system
```
#### **app.js**
```javascript
const video = document.getElementById("video");
const videoContainer = document.getElementById("video-container");
const MODEL_URI = "/models";
Promise.all([
faceapi.nets.tinyFaceDetector.loadFromUri(MODEL_URI),
faceapi.nets.faceLandmark68Net.loadFromUri(MODEL_URI),
faceapi.nets.faceRecognitionNet.loadFromUri(MODEL_URI),
faceapi.nets.faceExpressionNet.loadFromUri(MODEL_URI),
faceapi.nets.ageGenderNet.loadFromUri(MODEL_URI),
])
.then(playVideo)
.catch((err) => {
console.log(err);
});
function playVideo() {
if (!navigator.mediaDevices) {
console.error("mediaDevices not supported");
return;
}
navigator.mediaDevices
.getUserMedia({
video: {
width: { min: 640, ideal: 1280, max: 1920 },
height: { min: 360, ideal: 720, max: 1080 },
},
audio: false,
})
.then(function (stream) {
video.srcObject = stream;
})
.catch(function (err) {
console.log(err);
});
}
video.addEventListener("play", () => {
// Creating the canvas
const canvas = faceapi.createCanvasFromMedia(video);
// This will force the use of a software (instead of hardware accelerated)
// Enable only for low configurations
canvas.willReadFrequently = true;
videoContainer.appendChild(canvas);
// Resizing the canvas to cover the video element
const canvasSize = { width: video.width, height: video.height };
faceapi.matchDimensions(canvas, canvasSize);
setInterval(async () => {
const detections = await faceapi
.detectAllFaces(video, new faceapi.TinyFaceDetectorOptions())
.withFaceLandmarks()
.withFaceExpressions()
.withAgeAndGender();
// Set detections size to the canvas size
const DetectionsArray = faceapi.resizeResults(detections, canvasSize);
canvas.getContext("2d").clearRect(0, 0, canvas.width, canvas.height);
detectionsDraw(canvas, DetectionsArray);
}, 10);
});
// Drawing our detections above the video
function detectionsDraw(canvas, DetectionsArray) {
// Adjust the size of the detection canvas
faceapi.draw.drawDetections(canvas, DetectionsArray);
faceapi.draw.drawFaceLandmarks(canvas, DetectionsArray);
faceapi.draw.drawFaceExpressions(canvas, DetectionsArray);
// Drawing AGE and GENDER
DetectionsArray.forEach((detection) => {
const box = detection.detection.box;
const drawBox = new faceapi.draw.DrawBox(box, {
label: ${Math.round(detection.age)}y, ${detection.gender},
});
drawBox.draw(canvas);
});
}
Now we will go throw app.js, and explain different code blocks.
const MODEL_URI = "/models";
Promise.all([
faceapi.nets.tinyFaceDetector.loadFromUri(MODEL_URI),
faceapi.nets.faceLandmark68Net.loadFromUri(MODEL_URI),
faceapi.nets.faceRecognitionNet.loadFromUri(MODEL_URI),
faceapi.nets.faceExpressionNet.loadFromUri(MODEL_URI),
faceapi.nets.ageGenderNet.loadFromUri(MODEL_URI),
])
.then(playVideo)
.catch((err) => {
console.log(err);
});
```
In this code block, we are loading our models files from the ‘/models’ folder using **Promise.all\[\]**, which allows us to wait for all models to load (it will take some time, depending on your hardware).
Then, we call the function **playVideo** and of course catch any errors and show them in the console.
Our **playVideo()** function
First we check if the browser support [mediaDevices API](https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices) , if not we stop and execution of the function and show an error in the console: “mediaDevices not supported”
Then we call the mediaDevice.getUserMedia: this will show a notification to the user, asking permission to access the camera ( no sound in our case),if the user refuses, we throw an error.
If all goes well, we assign the stream to our video element:
video.srcObject = stream;
Now our video element starts showing a live stream from the camera.
video.addEventListener("play", () => {
// Creating the canvas
const canvas = faceapi.createCanvasFromMedia(video);
```javascript
function playVideo() {
if (!navigator.mediaDevices) {
console.error("mediaDevices not supported");
return;
}
navigator.mediaDevices
.getUserMedia({
video: {
width: { min: 640, ideal: 1280, max: 1920 },
height: { min: 360, ideal: 720, max: 1080 },
},
audio: false,
})
.then(function (stream) {
video.srcObject = stream;
})
.catch(function (err) {
console.log(err);
});
}
// This will force the use of a software (instead of hardware accelerated)
// Enable only for low configurations
canvas.willReadFrequently = true;
videoContainer.appendChild(canvas);
// Resizing the canvas to cover the video element
const canvasSize = { width: video.width, height: video.height };
faceapi.matchDimensions(canvas, canvasSize);
setInterval(async () => {
const detections = await faceapi
.detectAllFaces(video, new faceapi.TinyFaceDetectorOptions())
.withFaceLandmarks()
.withFaceExpressions()
.withAgeAndGender();
// Set detections size to the canvas size
const DetectionsArray = faceapi.resizeResults(detections, canvasSize);
canvas.getContext("2d").clearRect(0, 0, canvas.width, canvas.height);
detectionsDraw(canvas, DetectionsArray);
}, 10);
});
```
Now come's this block of code, this will be executed when the video starts playing.
In this block of code we will start drawing our different detection: face, landmarks, expressions, age, gender. All that using the canvas element.
First: creating the canvas and assign it to the video element
```javascript
const canvas = faceapi.createCanvasFromMedia(video);
// This will force the use of a software (instead of hardware accelerated)
// Enable only for low configurations
canvas.willReadFrequently = true;
videoContainer.appendChild(canvas);
```
Then resize the canvas to muth the video element
```javascript
// Resizing the canvas to cover the video element
const canvasSize = { width: video.width, height: video.height };
faceapi.matchDimensions(canvas, canvasSize);
Start a timer that will search for face detection in the video stream, and draw the results over our canvas
setInterval(async () => {
const detections = await faceapi
.detectAllFaces(video, new faceapi.TinyFaceDetectorOptions())
.withFaceLandmarks()
.withFaceExpressions()
.withAgeAndGender();
// Set detections size to the canvas size
const DetectionsArray = faceapi.resizeResults(detections, canvasSize);
canvas.getContext("2d").clearRect(0, 0, canvas.width, canvas.height);
detectionsDraw(canvas, DetectionsArray);
}, 10);
```