Skip to content

Commit 81f35ab

Browse files
authored
[facemesh] Add model. (tensorflow#413)
1 parent 78d3f69 commit 81f35ab

27 files changed

+8899
-1
lines changed

.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,5 @@ clone/
1414
.rpt2_cache/
1515

1616
*.pyc
17+
18+
*.tgz

blazeface/scripts/publish-demo.sh

+2-1
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,5 @@
1717
cd demo
1818
rm -rf dist
1919
yarn build
20-
gsutil rsync -J -d -r dist/ gs://tfjs-models/demos/blazeface
20+
gsutil -m rm -r gs://tfjs-models/demos/blazeface/*
21+
gsutil -m cp -Z -r dist/ gs://tfjs-models/demos/blazeface

facemesh/.npmignore

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
.DS_Store
2+
.yalc/
3+
.vscode/
4+
.rpt2_cache/
5+
demo/
6+
scripts/
7+
src/
8+
coverage/
9+
node_modules/
10+
karma.conf.js
11+
*.tgz
12+
.travis.yml
13+
.npmignore
14+
tslint.json
15+
yarn.lock
16+
yalc.lock
17+
cloudbuild.yml
18+
dist/*_test.js
19+
dist/*_test.js.map
20+
dist/test_util*

facemesh/README.md

+131
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
# MediaPipe Facemesh
2+
3+
MediaPipe Facemesh is a lightweight machine learning pipeline predicting 486 3D facial landmarks to infer the approximate surface geometry of a human face ([paper](https://arxiv.org/pdf/1907.06724.pdf)).
4+
5+
<img src="demo.gif" alt="demo" style="width: 640px;"/>
6+
7+
More background information about the model, as well as its performance characteristics on different datasets, can be found here: [https://drive.google.com/file/d/1VFC_wIpw4O7xBOiTgUldl79d9LA-LsnA/view](https://drive.google.com/file/d/1VFC_wIpw4O7xBOiTgUldl79d9LA-LsnA/view)
8+
9+
The model is designed for front-facing cameras on mobile devices, where faces in view tend to occupy a relatively large fraction of the canvas. MediaPipe Facemesh may struggle to identify far-away faces.
10+
11+
Check out our [demo](https://storage.googleapis.com/tfjs-models/demos/facemesh/index.html), which uses the model to detect facial landmarks in a live video stream.
12+
13+
This model is also available as part of [MediaPipe](https://github.com/google/mediapipe/tree/master/mediapipe/models), a
14+
framework for building multimodal applied ML pipelines.
15+
16+
## Installation
17+
18+
Using `yarn`:
19+
20+
$ yarn add @tensorflow-models/facemesh
21+
22+
Using `npm`:
23+
24+
$ npm install @tensorflow-models/facemesh
25+
26+
Note that this package specifies `@tensorflow/tfjs-core` and `@tensorflow/tfjs-converter` as peer dependencies, so they will also need to be installed.
27+
28+
## Usage
29+
30+
To import in npm:
31+
32+
```js
33+
import * as facemesh from '@tensorflow-models/facemesh';
34+
```
35+
36+
or as a standalone script tag:
37+
38+
```html
39+
<script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs-core"></script>
40+
<script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs-converter"></script>
41+
<script src="https://cdn.jsdelivr.net/npm/@tensorflow-models/facemesh"></script>
42+
```
43+
44+
Then:
45+
46+
```js
47+
48+
async function main() {
49+
// Load the MediaPipe facemesh model.
50+
const model = await facemesh.load();
51+
52+
// Pass in a video stream (or an image, canvas, or 3D tensor) to obtain an
53+
// array of detected faces from the MediaPipe graph.
54+
const predictions = await model.estimateFaces(document.querySelector("video"));
55+
56+
if (predictions.length > 0) {
57+
/*
58+
`predictions` is an array of objects describing each detected face, for example:
59+
60+
[
61+
{
62+
faceInViewConfidence: 1, // The probability of a face being present.
63+
boundingBox: { // The bounding box surrounding the face.
64+
topLeft: [232.28, 145.26],
65+
bottomRight: [449.75, 308.36],
66+
},
67+
mesh: [ // The 3D coordinates of each facial landmark.
68+
[92.07, 119.49, -17.54],
69+
[91.97, 102.52, -30.54],
70+
...
71+
],
72+
scaledMesh: [ // The 3D coordinates of each facial landmark, normalized.
73+
[322.32, 297.58, -17.54],
74+
[322.18, 263.95, -30.54]
75+
],
76+
annotations: { // Semantic groupings of the `scaledMesh` coordinates.
77+
silhouette: [
78+
[326.19, 124.72, -3.82],
79+
[351.06, 126.30, -3.00],
80+
...
81+
],
82+
...
83+
}
84+
}
85+
]
86+
*/
87+
88+
for (let i = 0; i < predictions.length; i++) {
89+
const keypoints = predictions[i].scaledMesh;
90+
91+
// Log facial keypoints.
92+
for (let i = 0; i < keypoints.length; i++) {
93+
const [x, y, z] = keypoints[i];
94+
95+
console.log(`Keypoint ${i}: [${x}, ${y}, ${z}]`);
96+
}
97+
}
98+
}
99+
}
100+
101+
main();
102+
103+
```
104+
105+
#### Parameters for facemesh.load()
106+
107+
`facemesh.load()` takes a configuration object with the following properties:
108+
109+
* **maxContinuousChecks** - How many frames to go without running the bounding box detector. Only relevant if maxFaces > 1. Defaults to 5.
110+
111+
* **detectionConfidence** - Threshold for discarding a prediction. Defaults to 0.9.
112+
113+
* **maxFaces** - The maximum number of faces detected in the input. Should be set to the minimum number for performance. Defaults to 10.
114+
115+
* **iouThreshold** - A float representing the threshold for deciding whether boxes overlap too much in non-maximum suppression. Must be between [0, 1]. Defaults to 0.3.
116+
117+
* **scoreThreshold** - A threshold for deciding when to remove boxes based on score in non-maximum suppression. Defaults to 0.75.
118+
119+
#### Parameters for model.estimateFace()
120+
121+
* **input** - The image to classify. Can be a tensor, DOM element image, video, or canvas.
122+
123+
* **returnTensors** - (defaults to `false`) Whether to return tensors as opposed to values.
124+
125+
* **flipHorizontal** - Whether to flip/mirror the facial keypoints horizontally. Should be true for videos that are flipped by default (e.g. webcams).
126+
127+
#### Keypoints
128+
129+
Here is map of the keypoints:
130+
131+
<img src="mesh_map.jpg" alt="keypoints_map" style="width: 500px; height: 500px">

facemesh/demo.gif

8.44 MB
Loading

facemesh/demo/.babelrc

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
{
2+
"presets": [
3+
[
4+
"env",
5+
{
6+
"esmodules": false,
7+
"targets": {
8+
"browsers": [
9+
"> 3%"
10+
]
11+
}
12+
}
13+
]
14+
],
15+
"plugins": [
16+
[
17+
"transform-runtime",
18+
{
19+
"polyfill": false
20+
}
21+
]
22+
]
23+
}

facemesh/demo/README.md

+66
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
# MediaPipe Facemesh demo
2+
3+
## Contents
4+
5+
The MediaPipe Facemesh demo shows how to use the MediaPipe Facemesh model to estimate keypoints on a face.
6+
7+
## Setup
8+
9+
cd into the demos folder:
10+
11+
```sh
12+
cd facemesh/demos
13+
```
14+
15+
Install dependencies and prepare the build directory:
16+
17+
```sh
18+
yarn
19+
```
20+
21+
To watch files for changes, and launch a dev server:
22+
23+
```sh
24+
yarn watch
25+
```
26+
27+
## If you are developing facemesh locally, and want to test the changes in the demos
28+
29+
Cd into the facemesh folder:
30+
```sh
31+
cd facemesh
32+
```
33+
34+
Install dependencies:
35+
```sh
36+
yarn
37+
```
38+
39+
Publish facemesh locally:
40+
```sh
41+
yarn build && yarn yalc publish
42+
```
43+
44+
Cd into the demos and install dependencies:
45+
46+
```sh
47+
cd demos
48+
yarn
49+
```
50+
51+
Link the local facemesh to the demos:
52+
```sh
53+
yarn yalc link @tensorflow-models/facemesh
54+
```
55+
56+
Start the dev demo server:
57+
```sh
58+
yarn watch
59+
```
60+
61+
To get future updates from the facemesh source code:
62+
```
63+
# cd up into the facemesh directory
64+
cd ../
65+
yarn build && yarn yalc push
66+
```

facemesh/demo/index.html

+60
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
<!-- Copyright 2020 Google LLC. All Rights Reserved.
2+
3+
Licensed under the Apache License, Version 2.0 (the "License");
4+
you may not use this file except in compliance with the License.
5+
You may obtain a copy of the License at
6+
7+
http://www.apache.org/licenses/LICENSE-2.0
8+
9+
Unless required by applicable law or agreed to in writing, software
10+
distributed under the License is distributed on an "AS IS" BASIS,
11+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
See the License for the specific language governing permissions and
13+
limitations under the License.
14+
==============================================================================-->
15+
16+
<head>
17+
<!-- Load three.js -->
18+
<script src="https://cdn.jsdelivr.net/npm/[email protected]/build/three.min.js"></script>
19+
<!-- Load scatter-gl.js -->
20+
<script src="https://cdn.jsdelivr.net/npm/[email protected]/lib/scatter-gl.min.js"></script>
21+
<style>
22+
.canvas-wrapper, #scatter-gl-container {
23+
display: inline-block;
24+
vertical-align: top;
25+
}
26+
27+
#scatter-gl-container {
28+
border: solid 1px black;
29+
position: relative;
30+
}
31+
32+
/* center the canvas within its wrapper */
33+
#scatter-gl-container canvas {
34+
transform: translate3d(-50%, -50%, 0);
35+
left: 50%;
36+
top: 50%;
37+
position: absolute;
38+
}
39+
</style>
40+
</head>
41+
<body>
42+
<div id="main">
43+
<div class="container">
44+
<div class="canvas-wrapper">
45+
<canvas id="output"></canvas>
46+
<video id="video" playsinline style="
47+
-webkit-transform: scaleX(-1);
48+
transform: scaleX(-1);
49+
visibility: hidden;
50+
width: auto;
51+
height: auto;
52+
">
53+
</video>
54+
</div>
55+
<div id="scatter-gl-container"></div>
56+
</div>
57+
</div>
58+
</body>
59+
<script src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.7.6/dat.gui.min.js"></script>
60+
<script src="index.js"></script>

0 commit comments

Comments
 (0)