- By: Dory Azar
- Video Demo: Recorded Examples
- Live Demo: FaceDetect Examples
- What is it?
- Credits & Resources
- Let's get started
- Let's get through the basics
- Let's have some fun
- Final Thoughts
- Known Issues
Detecting human faces and recognizing faces and facial expressions have always been an area of interest for different applications such as games, utilities and even security. With the advancement of machine learning, the techniques of detection and recognition have become more accurate and precise than ever before.
However, machine learning remains a relatively complex field that could feel intimidating or inaccessible to many of us. Luckily, in the last couple of years, several organizations and open source communities have been developing tools and libraries that help abstract the complex mathematical algorithms in order to encourage developers to easily create learning models and train them using any programming languages.
As part of this study, I created a Javascript framework built on top of the work of several open source projects and models with the hope to reduce the entry barrier for developers and to encourage them to focus more on developing innovative applications that make use of face detection and recognition.
Artificial Intelligence (AI) and Machine Learning in particular don't have to be difficult and we hope that the FaceDetect framework gives developers the means to include face detection and recognition in a seamless way in their applications.
-
face-api library: this project uses the face api javascript library developed by Vincent Muhler
-
detect.js: Proprietary open source class that I created to make the use of the face-api library easier to use and to integrate in third party applications and frameworks.
detect.js
is included in the package -
TensorFlow: Tensor flow is an end-to-end open source platform with comprehensive tools and libraries that lets developers easily build machine learning powered applications
-
ml5.js: ML5 is an open source library, with exhaustive documentation and tutorials for understanding machine learning algorithms and how to use TensorFlow Models
-
Internet connection: FaceDetect references a CDN distribution of Vue that requires a connection to the internet
-
Webcam: The FaceDetect framework does not require a webcam. However, the examples in this study are designed to detect faces live from a webcam stream
The FaceDetect package can be downloaded from the FaceDetect Github repository by either downloading the ZIP folder or by running the following command from the terminal:
git clone git@github.com:DoryAzar/facedetect.git
Once the FaceDetect package is downloaded, you can test it by running the out-of-the-box application that comes with it.
In order to run that application, navigate to the folder where FaceDetect was downloaded then run facedetect > app > basic > index.html
by double clicking on the index.html
.
If you downloaded the package in your server root then you should be able to run it directly through this url: http://localhost/facedetect/app/basic
Just like any framework, FaceDetect comes with a structure of its own. Understanding that structure is key to understanding the different components of the framework and how they interact with each other.
All the applications that you will create reside in this folder. For example, basic
- the application that we used to test the installation - is also in this folder. Each application is a folder of its own and it consists of the following:
-
main.js
: The VueJS script file -
index.html
: The markup HTML file that will reference the VueJS instance
In the app
folder, an app_template
folder with a template HTML markup and Vue script is provided for your convenience. You can simply copy this folder and rename it as a starting point for every application that you want to create.
In this folder lies the core definition of the detection and recognition framework. There are 4 key components to this framework:
-
FaceDetector
class: This is the core class for usingFaceDetect
in your application. The core code is indetect.js
that can be found in thescripts
folder -
models
: Every machine learning application relies on trained models to be able to do things such as object detection or recognition. FaceDetect is no exception to that rule and it needs these models to operate properly. These pre-trained models are included in the package and can be found in themodels
folder -
recognition
models: In order to recognize specific faces,FaceDetect
needs models to compare the detections to. These models are nothing more but a series of pictures of people organized in folders. These need to be created under the folder calledrecognition
. As an example, you can find a subfolder calledFlash
that has 6 (PNG) pictures named by number of the superhero Flash. The same mechanism should be used to create more models (pictures of you for example). We will elaborate more on face recognition when we create our first face recognition application -
faceapi.js
: The FaceAPI developed by Vincent Muhler is included in the package
Detection and Recognition are two different concepts. While both use machine learning and neural networks in particular, they achieve different things. Understanding the distinction is key to better understanding how the FaceDetect framework operates.
-
Face detection: Face detection is about identifying a human face among all other "things" perceived through either an image or a video. So for example, a picture or a video can have people, objects, scenery etc... Face detection is when the system is capable of pointing out the presence of a human face among all those other things.
-
Face recognition: Recognition is about identifying who the human face is among all other faces and things perceived. So for example, Face recognition is when the system is capable of pointing out "Flash" among all other superheroes in a picture or a video.
FaceDetect relies on an important principle: "First you detect then you do something with the detections". With that principle in mind, the framework focuses on providing an easy-to-code sandbox for you to do something with the detections. Each sandbox is an app
of its own. So if you intend to detect the age of a face or detect the facial expressions or count the number of people or recognize a face etc.. Each one of those is referred to as an app
.
The FaceDetect app
is a Vue application that - similarly to all Vue applications - relies on both an HTML markup file and a Javascript file.
Every application that you create resides in the app
folder. The basic
app that comes with the package illustrates the usage of the FaceDetect methods and properties. The app_template
is a barebone folder structure that can be duplicated within the app
folder and renamed as a starting point for your application.
The HTML markup file (index.html for example) is the user interface that will define the source of the face detections (image or video) and any other controls needed to make something useful with the detections. It should also include the FaceDetect needed libraries and the Vue JS framework reference.
The HTML markup has 4 key elements that are designed to work with and without Vue:
-
detector section
:FaceDetect
is identified in the markup by the iddetector
.FaceDetect
will be encapsulated within that block. If you are using Vue, thedetector
block lives within the Vue app id.<!-- Vue app --> <div id="app"> <section id="detector"> .... </section> </div>
-
Media source: No matter what you want to do with FaceDetect, detection is the first step to it. It is therefore important to identify what the detection source is. Is it an image, a video or a live webcam?
The markup of your application needs to provide that source:
<!-- Beginning of the app --> <div id="app"> <section id="detector"> <!-- media can be an image <img id="detection" class="show" src=""> --> <!-- media can be a video <video id="detection" src="<video local url>" type="video/mp4" width="720" height="560" class="show" autoplay="autoplay" muted playsinline controls></video> --> <!-- media can be live webcam --> <video id="detection" width="720" height="560" class="show" autoplay="autoplay" muted playsinline></video> </section> </div>
-
Controls: So far, only the source has been specified. In order to do something with it, it needs one or more UI triggers to activate it.
FaceDetector
provides you with a way to create these controls if you desire. In order to do that, you will need to add thecontrols
placeholder to your markup.<section class="controls"> <div id="apps"></div> </section>
-
Infobar:
FaceDetect
provides you with a UI component to display welcome messages, status or instruction messages calledInfobar
. In order to use it, you will need to add theinfobar
placeholder to your markup.<section id="infobar"></section>
FaceDetect is a framework that was designed to work as a third-party library with any Javascript code. In this study, we focus primarily on running FaceDetect with Vue. Since FaceDetect was not written as a Vue component per se, it will need to be instantiated as part of the Vue script that is serving the markup.
FaceDetector
is the main object of the FaceDetect framework. It can be instantiated in the Vue script by providing it with the HTML ID of the media source. It is therefore important to make sure that the markup for either an image or a video has an id attribute.
The main structure of the Vue script should look like this:
// make sure to use the HTML id of the media source
var detector = new FaceDetector('detection');
var app = new Vue({
el: '#app',
data () {
return {
detector: detector, /* important */
env: env
}
},
/* Method Definition */
methods: {
},
/* upon object load, the following will be executed */
mounted () {
}
});
The
basic
app included in the package shows you examples of the HTML markup as well as the Vue script that serves it.
The best way to explore the powerful features of the FaceDetect framework is to use them in actual examples. As part of this study, we will show you how you could make use of the framework to quickly create face detection and recognition applications.
In every
app
that we will create, we recommend that you duplicate theapp_template
folder provided, renaming it and adjusting the HTML markup as well as the Vue script when needed.
In all of the app examples, we will be detecting and/or recognizing faces from a webcam stream. Therefore, the HTML Markup will always be the same:
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="content-type", content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width initial-scale=1 maximum-scale=1">
<meta name='apple-mobile-web-app-capable' content='yes'>
<meta name='apple-mobile-web-app-status-bar-style' content='black'>
<title>Face Detect</title>
<!-- Stylesheet and head scripts go here -->
<link rel="stylesheet" href="../../facedetect/css/styles.css">
<!-- Initialization scripts -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js" defer></script>
<script src="../../facedetect/scripts/face-api.min.js" defer></script>
<script src="../../facedetect/scripts/detect.js" defer></script>
<script src="scripts/main.js" defer></script>
</head>
<body>
<!-- Beginning of the app -->
<div id="app">
<header>
<h1>Face Detect</h1>
</header>
<section id="infobar"></section>
<section id="detector">
<!-- media can be a webcam -->
<video id="detection" width="720" height="560" class="show" autoplay="autoplay" muted playsinline></video>
</section>
<section class="controls">
<div id="apps"></div>
</section>
</div>
</body>
</html>
The first app
we are going to create is a simple face detection application that detects all faces from a webcam stream. As much as this sounds complex, with the FaceDetect framework it can actually be done in one line of code in the Vue main.js
script.
var detector = new FaceDetector('detection');
var app = new Vue({
el: '#app',
data () {
return {
detector: detector
}
},
/* upon object load, the following will be executed */
mounted () {
// Load general detection
this.detector.loadApp();
}
});
The code for this app is in the
app
>example1
folder of this package
In the first application, all we did is load the default sandbox of the FaceDetect framework. All the default sandbox does is detect the faces. For this second application, we would like to detect more features of the detected faces (such as gender for example). The trained models that FaceDetect uses can detect: age, gender and 5 emotions (sad, happy, surprised, angry and neutral).
In order to do that, FaceDetect provides a way to activate/deactivate certain properties of the engine and pass them in a JSON format to the framework. Some of these properties are mandatory.
{
name: 'Full Detection', // MANDATORY: UI button label that triggers the detection
method: this.detector.draw, // MANDATORY: FaceDetect method that will draw the different detections on top of the detected faces
options: {
welcome: "Detect faces, genders, ages and expressions", // OPTIONAL: Message that will be displayed in the infobar of the UI
detection: true, // OPTIONAL: Draws the rectangle around the detected faces
landmarks: true, // OPTIONAL: Draws the contour of the detected faces
gender: true, // OPTIONAL: Displays the gender of the detected faces
expression: true, // OPTIONAL: Displays the detected emotion of the detected faces
age: true // OPTIONAL: Displays the age of the detected faces
}
}
The Vue script would then consist of calling the FaceDetect loadApp
method just like we did in the first example and passing the JSON as an argument to it.
var detector = new FaceDetector('detection');
var app = new Vue({
el: '#app',
data () {
return {
detector: detector
}
},
/* upon object load, the following will be executed */
mounted () {
// Passing the settings to the loadApp method
this.detector.loadApp({
name: 'Full Detection',
method: this.detector.draw,
options: {
welcome: "Detect faces, genders, ages and expressions",
detection: true,
landmarks: true,
gender: true,
expression: true,
age: true
}
});
}
});
The code for this app is in the
app
>example2
folder of this package
In all the applications that we created thus far, we have only been detecting faces. In this third example, we are going to create an example that not just detects faces in the webcam, but also recognizes specific faces among the ones detected.
If you need to understand better the distinction between Detection and Recognition, make sure you read this section
In order to do this, we need to create models of the people that we would want to recognize. Models are nothing more but face pictures of those people in different angles and perspectives. The more samples we have, the more accurate the recognition. We then need to tell FaceDetect to compare the detections to these models and identify the faces that it recognizes directly on top of the video.
Step 1: Define the recognition models
The easiest way to define a recognition model is to create a folder for each person containing many pictures of that person. Each person to be recognized will have a folder in their name and the pictures inside must be PNGs and must be named with a number.
That folder needs to be placed in facedetect
> recognition
> <name of person>
.
As an example, there is a model already defined in the package to recognize the superhero Flash. If you navigate to the
facedetect
>recognition
folder, you will find aFlash
folder containing 6 different PNGs of the Flash numbered 1 to 6.
-
Go ahead and create a folder in
facedetect
>recognition
that has your firstname. Keep theFlash
folder, we will use it for testing -
In this new folder, add 6 PNG images of you from different angles
-
Make sure that the PNGs are named 1.PNG, 2.PNG etc...
Step 2: Run recognition
Running the recognition is as easy as loading a detection app with 3 specific parameters: the method
, models
and recognition
parameters.
<!-- Vue example -->
this.detector.loadApp({
name: "Find me", // MANDATORY: UI button label that triggers the recognition
method: this.detector.recognize, // MANDATORY: FaceDetect method that will call the recognition engine
models: {
labels: ['Flash', 'Your Name'], // MANDATORY: Make sure to respect the case. Array of all the names of the people which are also the names of the folders in the structure.
sampleSize: 6 // number of pictures per person (this number must be the same for all)
},
options: {
welcome: "Can you find me?", // OPTIONAL: This is the message that will be displayed in the infobar
recognition: true // the recognition engine needs to be activated
},
algorithm: faceapi.SsdMobilenetv1Options // OPTIONAL: The detection algorithm that will be used
});
Go ahead and test out the application. If you took pictures of yourself, once you stand in front of the webcam, the system will be able to identify you and to show your name (which also is the folder name) around your face. For more fun, you can also have the Flash image on your phone and place it in front of your computer webcam (where the application is running). The system will be able to identify and distinguish both you and the Flash.
For any other face that it detects and that does not have a model, it will display an "unknown" label around them.
The code for this app is in the
app
>example3
folder of this package
In the examples thus far, we used the FaceDetect sandboxed features and we were able to do face detection and face recognition by simply manipulating some control settings. In this part, we are going to shed light on how we could leverage the FaceDetect framework to do whatever we want with the detections and the recognitions that its engine provides.
In order to do that, we need to create either a detection or a recognition app
that tells FaceDetect to just provide us with the data and our application handles all the rest. Let's imagine that we want to create an application that counts the number of men and women that it sees in the webcam and displays them in the UI.
Step 1: Load FaceDetect detection
Similarly to what we have seen in the other examples, this example also needs to initiate the detections. However, unlike the other examples, we are not looking to draw rectangles or display specific face information around the detected faces. What we need is for FaceDetect to allow us to hook into every detection cycle and execute our own logic.
In order to do that, we need to pass our own callback method to the app settings. Let's assume that our method will be called countGender
.
// In the Vue script
mounted () {
this.detector.loadApp({
name: "Count Gender", // name of the trigger button in the UI
method: this.countGender, // assuming our method is called countGender
options: {
detection: true
}
});
}
Step 2: Prepare the custom method
The second step is to create a custom Vue method countGender
that goes through the detections and increments the count of men or women based on the faces information that it detects. This example is mainly meant to illustrate how we can have access to the detections and in what format FaceDetect provides them to us.
FaceDetect enables us to have access to the entire set of properties of the FaceDetect instance through the custom method by making us define a name for that instance that will be passed as an argument to the custom method. Therefore, the countGender
method needs to take at least one argument and that argument should be the reference to the FaceDetect object which could easily give us access to the detections as shown in the code below.
methods: {
countGender: function(facedetector) {
// facedetector will reference the FaceDetect object
// facedetector.app.detections will provide an array of all the detected faces every cycle of detection (100ms by default)
console.log(facedetector.app.detections);
}
}
It would be instructive to log the facedetector.app.detections as suggested in the code above to see the complete list of properties that FaceDetect returns for each detection. Here are some: gender, expressions, age etc...
Step 3: Iterate through the detections
With the method defined, we can now create the logic that allows us to iterate through the detections. For each detection, we need to check the gender
property in each detection object model and increment either men or women counts.
var detector = new FaceDetector('detection');
var app = new Vue({
el: '#app',
data () {
return {
detector: detector,
femaleCount: 0,
maleCount: 0
}
},
methods: {
countGender: function(facedetector) {
// reset the counts every time the method is called
this.femaleCount = 0;
this.maleCount = 0;
// iterate through the detections and count the number of men and women
facedetector.app.detections.forEach((detection) => {
if (detection.gender == 'male') {
this.maleCount++;
} else {
this.femaleCount++;
}
});
}
},
/* upon object load, the following will be executed */
mounted () {
this.detector.loadApp({
name: "Count Gender",
method: this.countGender,
options: {
detection: true
}
});
}
});
Step 4: Display the counts in the HTML markup
The last step is really to display the counts in the HTML markup. This is nothing more but using Vue interpolation to display the 2 variables maleCount
and femaleCount
. In this case, we chose to adhere to the default styles provided by the FaceDetect CSS but any HTML structure and styling could be applied.
<body>
<!-- Beginning of the app -->
<div id="app">
<header>
<h1>Face Detect</h1>
</header>
<section id="infobar"><ul><li>men: {{ maleCount }}</li><li>women: {{ femaleCount }}</li></ul></section>
<section id="detector">
<!-- media can be a webcam -->
<video id="detection" width="720" height="560" class="show" autoplay="autoplay" muted playsinline></video>
</section>
<section class="controls">
<div id="apps"></div>
</section>
</div>
</body>
The code for this app is in the
app
>example4
folder of this package
FaceDetect is designed with the intent to abstract the underlying machine learning concepts that drive face detection and recognition. In this study, we gave you a glimpse on how a few lines of code can allow you to introduce face detection and recognition in your applications.
The framework is flexible to accommodate the needs of developers of all levels. There are more advanced features and properties that have not been illustrated in this study that are worth highlighting in conclusion.
In example 4, we have seen one type of hook that allows us to inject a piece of logic (through a custom method) that gets executed at every detection or recognition cycle.
There is another type of hook that instructs FaceDetect to execute a piece of code before detections or recognitions start. Basically, it forces the FaceDetect features to be called and controlled by developers. This is a way to give the ability for the developer to take control over the framework methods and properties.
In order to get into this mode, a FaceDetect app needs to be loaded with a custom
set to true. Doing so, will transfer execution to the callbackMethod
and any other FaceDetect feature needs to be called explicitly from within it.
this.loadApp({
name: "Custom callback",
method: this.callbackMethod,
custom: true, // set to true if you want the method to do something else before calling in FaceDetect features
options: {
detection: true
}
});
In order to create custom applications, FaceDetect provides 2 different types of hooks. One that we have seen in example 4 and another one that we just explained in the previous section. In both these modes, the program execution is passed on to a callback method. In that callback method, all the FaceDetect features can be leveraged to create powerful applications.
Here is the list of all the methods and properties that FaceDetect provides:
// PROPERTIES
facedetector.app // Everything about the app: name, options, detections, recognitions, canvas
facedetector.app.options // All the options defined in the app
facedetector.app.canvas // All the properties of the canvas that is created on top of the media source
facedetector.app.detections // Detections when the detection engine is running
facedetector.app.recognitions // Recognitions when the recognition engine is running
// METHODS
facedetector.loadApp(app); // load another app
(facedetector.detectFaces(app, facedetector))() // self invoking function to start face detection
facedetector.detect(callback, recognize = false, fetchRate = 100) // starts a parallel stream that captures any detections or recognitions when available
facedetector.prepareCanva(options = null) // returns a new canvas on top of the media source
facedetector.draw(facedetector) // draws the detections on the canvas
facedetector.loadRecognition({ labels: [], images: [], sampleSize: 6}) // load models to recognize by the recognition engine
facedetector.recognize(facedetector) // runs the recognition engine and draws on canvas. Must make sure that detections is started before
facedetector.fetchImage(canvas, media) // takes a canvas capture of the media and returns a blob data image (data url)
facedetector.display(message, output) // displays a message in the infobar and gives it an ID as specified by the 'output' input
facedetector.clearDisplay() // clears the infobar display
-
FaceDetect works on Chrome, Safari and FireFox from the local machine
-
In production, some browsers (Safari) require a secure SSL connection (https) for webcam streaming
-
"Puppeteer" (the line drawing feature) is not compatible with Safari
With your sponsorship, we can continue to bring more features and to share the knowledge with the open source community. Github Sponsorship