face-api.js学习笔记
参考
(youtube get started)
(有提到相似度)
注意事项:
由于 face-api.js 作者从 2020 Apr 之后就没有维护了, 以⾄于在 node.js 的时候⽆法使⽤最新的 @tensorflow/tfjs-node (issue 在)后来有个好⼼⼈ folk 出来改. 所以推荐⼤家使⽤新的版本
Get started
(youtube get started)
这篇主要是叫⼀些 basic ⼊门.
流程:
加载需要的 models
开启 webcam
把 webcam 源放⼊ video 做显⽰
通过 faceapi 扫描 video
做⼀个定位 canvas 画布
通过 faceapi draw ⼈脸位置, 轮廓, 表情.
代码:
import * as faceapi from 'face-api.js';
const video = document.querySelector<HTMLVideoElement>('#js-video')!;
video.addEventListener('play', () => {
// 制作定位 canvas
const canvas = ateElement('canvas');
canvas.style.position = 'absolute';
document.body.append(canvas);
// 配置显⽰尺⼨
const displaySize = { width: video.width, height: video.height };
faceapi.matchDimensions(canvas, displaySize);
// 每 100ms 去绘制
setInterval(async () => {
// 识别位置, 路阔, 表情
const detections = await faceapi
.detectAllFaces(video, new faceapi.TinyFaceDetectorOptions())
.withFaceLandmarks()
.
withFaceExpressions();
// 调整尺⼨
const resizedDetections = sizeResults(detections, displaySize);
faceapi.draw.drawDetections(canvas, resizedDetections); // 位置
faceapi.draw.drawFaceLandmarks(canvas, resizedDetections); // 路阔
faceapi.draw.drawFaceExpressions(canvas, resizedDetections); // 表情
}, 100);
});
setTimeout(async () => {
// 加载 models
await Promise.all([
faceapis.tinyFaceDetector.loadFromUri('/face-api-models'),
faceapis.faceLandmark68Net.loadFromUri('/face-api-models'),
faceapis.faceRecognitionNet.loadFromUri('/face-api-models'),
faceapis.faceExpressionNet.loadFromUri('/face-api-models'),
]);
// 开启 webcam, 把 webcam 的流引⼊ video 显⽰
{ video: {} },
stream => {
video.srcObject = stream;
},
error => console.log('error', error)
);
}, 1000);
提醒: Webpack + face-api.js warning
如果使⽤ Webpack 可能会看见⼀个 warning 显⽰ Can't resolve 'fs'
这是因为 face-api.js 的代码时 node.js 和游览器公⽤的, 在 node.js 的环境下 fs 是必要的. 但是游览器是不需要的. 忽略掉这个 warning 就可以了.
github issue 看.
⼈脸识别 + 相似度
通过获取 2 张图⽚的⼈脸信息就可以做⼀个相似度对⽐. 如果 < 0.6 就表⽰很可能是同⼀个⼈ (这个度, 只是⼀个参考值)
这⾥顺便补上了⼀个 detect age 的功能.
// import * as faceapi from 'face-api.js';
import * as faceapi from '@vladmandic/face-api';
(async () => {
await Promise.all([
faceapis.tinyFaceDetector.loadFromUri('/face-api-models'),
faceapis.faceLandmark68Net.loadFromUri('/face-api-models'),
faceapis.faceRecognitionNet.loadFromUri('/face-api-models'),
faceapis.faceExpressionNet.loadFromUri('/face-api-models'),
faceapis.ageGenderNet.loadFromUri('/face-api-models'),
]);
const processAsync = async (image: HTMLImageElement) => {
const imageContainer = image.parentElement!;
const canvas = ateElement('canvas');
canvas.style.position = 'absolute';
canvas.style.left = '0';
p = '0';
imageContainer.append(canvas);
const displaySize = { width: image.width, height: image.height };
faceapi.matchDimensions(canvas, displaySize);
const faceDetection = (
await faceapi
.
detectAllFaces(image, new faceapi.TinyFaceDetectorOptions())
.withFaceLandmarks()
.withFaceDescriptors()
.withFaceExpressions()
.withAgeAndGender()
)[0]; // 假设图⽚只会有⼀张脸
// 或者⽤ detectSingleFace 拿最像脸的脸, 提醒: withFaceDescriptor <- 没有 s 了
// const faceDetection = await faceapi
// .detectSingleFace(image, new faceapi.TinyFaceDetectorOptions())
// .withFaceLandmarks()
// .withFaceDescriptor()
/
/ .withFaceExpressions()
// .withAgeAndGender();
if (faceDetection === undefined) {
throw new Error(`no faces detected`);
}
const resizedDetection = sizeResults(faceDetection, displaySize);
faceapi.draw.drawDetections(canvas, resizedDetection);
faceapi.draw.drawFaceLandmarks(canvas, resizedDetection);
faceapi.draw.drawFaceExpressions(canvas, resizedDetection);
const box = resizedDetection.detection.box;
const drawBox = new faceapi.draw.DrawBox(box, {
label: und(resizedDetection.age) + ' year old ' + der,
});
drawBox.draw(canvas);
return faceDetection;
};
const [fd1, fd2] = await Promise.all([
processAsync(document.querySelector<HTMLImageElement>('#js-image1')!),
processAsync(document.querySelector<HTMLImageElement>('#js-image2')!),
]);
const distance = faceapi.euclideanDistance(fd1.descriptor, fd2.descriptor);
if (distance < 0.6) {
console.log('same person');
} else {
console.log('different person');
}
})();
关键就在最后⼏句.
Node.js 运⾏
安装
要在 Node.js 上运⾏ (Windows 机) 有些事情要留意, 我也不确定是不是要装到完
npm install -g --production windows-build-tools (Local machine PowerShell administrator 安装, 在 windows server 我是⽤ cmd without admin 安装的, 它⼤概装了 10 分钟, 虽然看上去没有什么跑,但其实 CPU 是有跑的, 要留意哦)
(我是通过 visual studio installer 安装的 3.x 版本, windows server 的话通过 installer 安装 2.x 版本 (可能 3.x 也是 ok), 在配置的时候记得选要setup path)
代码
nodeselector参考:
yarn add @tensorflow/tfjs-node @vladmandic/face-api canvas
这⾥⽤的是 CommonJS, 因为我⽬前还没有 migration 到 es module
require('@tensorflow/tfjs-node');
const canvas = require('canvas');
const faceapi = require('@vladmandic/face-api');
// 这个是官⽅推荐做法 monkeyPatch
const { Canvas, Image, ImageData } = canvas;
(async () => {
await Promise.all([
// 换成了 from disk
faceapis.tinyFaceDetector.loadFromDisk('face-api-models'),
faceapis.faceLandmark68Net.loadFromDisk('face-api-models'),
faceapis.faceRecognitionNet.loadFromDisk('face-api-models'),
faceapis.faceExpressionNet.loadFromDisk('face-api-models'),
]);
// 通过 canvas.loadImage 读取图⽚
const image1 = await canvas.loadImage('klc-face/1.jpg');
const image2 = await canvas.loadImage('klc-face/2.jpg');
const fd1 = await faceapi
.detectSingleFace(image1, new faceapi.TinyFaceDetectorOptions())
.withFaceLandmarks()
.withFaceDescriptor();
const fd2 = await faceapi
.detectSingleFace(image2, new faceapi.TinyFaceDetectorOptions())
.withFaceLandmarks()
.withFaceDescriptor();
const distance = faceapi.euclideanDistance(fd1.descriptor, fd2.descriptor);
console.log('distance', distance);
})();
如果要⽤ es module 的话, 到 package.json 加 { "type": "module" }, 下⾯这个是 es module 版本
import '@tensorflow/tfjs-node';
import canvas from 'canvas';
import faceapi from '@vladmandic/face-api';
// 这个是官⽅推荐做法 monkeyPatch
const { Canvas, Image, ImageData } = canvas;
(async () => {
await Promise.all([
// 换成了 from disk
faceapis.tinyFaceDetector.loadFromDisk('face-api-models'),
faceapis.faceLandmark68Net.loadFromDisk('face-api-models'),
faceapis.faceRecognitionNet.loadFromDisk('face-api-models'),
faceapis.faceExpressionNet.loadFromDisk('face-api-models'),
]);
// 通过 canvas.loadImage 读取图⽚
const image1 = await canvas.loadImage('klc-face/1.jpg');
const image2 = await canvas.loadImage('klc-face/2.jpg');
const fd1 = await faceapi
.detectSingleFace(image1, new faceapi.TinyFaceDetectorOptions())
.withFaceLandmarks()
.withFaceDescriptor();
const fd2 = await faceapi
.detectSingleFace(image2, new faceapi.TinyFaceDetectorOptions())
.withFaceLandmarks()
.withFaceDescriptor();
const distance = faceapi.euclideanDistance(fd1.descriptor, fd2.descriptor); console.log('distance', distance);
})();
View Code
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论