大家好。这是杉野子。
在上一篇文章中,我写了一篇题为【远程工作】的文章,我尝试在网络会议中使用mediaPipe+p5js将我的脸变成图像【人脸显示NG】。
结果mediaPipe(Face Mesh)在性能方面还是不错的,所以我想,“我可以在开会的时候把脸藏起来!” . .
“我想尝试更准确的(?)面部表情分析! ] 所以我尝试了 face-api.js。
调查背景
我最后一次使用 mediaPipe 的 Face Mesh 是“比其他面部识别库更好的分析我使用它是因为我得到了以下信息
从某种意义上说,分析精度是
顔認証
mediaPipeのFace Mesh >>>> face-api.js
表情分析
face-api.js >>>>> mediaPipeのFace Mesh(というかできるの?)
我想过这个问题。
然而,随着我的实现,我开始对它的准确性感到奇怪,当我使用 face-api.js 演示时,我想,“也许 Face Mesh 的人脸识别很微妙? (怎么会因为没有面部表情分析?)
另外,个人“如果你可以用图像替换你的脸并在隐藏你的脸的同时切换面部表情,那将会很有趣。] 为什么(嗯,有第二次或第三次酝酿的感觉)我想调查并实施它。
作为最终目标,和上一篇文章一样,我们公司这是为了在推荐的露脸日隐藏你的脸。
这次重点是还可以做表情是。
*微软的 Azure Face API不同于face-api.js这是一个使用的故事
另外,我想与 Face Mesh 进行比较。
开发环境
- 节点 v18 系列
- Next.js(只是想用
地标比较
使用 face-api 实现(仅主要部分
// faceapiの情報をload
const loadModels = () => {
Promise.all([
faceapi.nets.tinyFaceDetector.loadFromUri(MODEL_PATH), // 顔認識
faceapi.nets.faceLandmark68Net.loadFromUri(MODEL_PATH), // 顔のlandmarks
faceapi.nets.faceRecognitionNet.loadFromUri(MODEL_PATH),
faceapi.nets.faceExpressionNet.loadFromUri(MODEL_PATH) // 顔の表情
]).then(res => {
setIsLoadedModels(true)
getVideo()
}).catch((err) => {
console.log('loadModels error', err)
})
}
// video情報を取得し、ビデオを映す
const getVideo = () => {
navigator.mediaDevices.getUserMedia({ video: true })
.then(stream => {
videoRef.current.srcObject = stream
setIsCaptureVideo(true)
videoRef.current.onloadedmetadata = async (e) => {
videoRef.current.play()
await playFaceTracking()
}
})
.catch(err => {
console.log('getvideo err', err)
setIsCaptureVideo(false)
})
}
const playFaceTracking = () => {
if (videoRef && videoRef.current) {
const video = videoRef.current as HTMLVideoElement
const createMedia = canvasRef.current as HTMLCanvasElement
faceapi.matchDimensions(createMedia, { width: video.clientWidth, height: video.clientHeight })
setInterval(async () => {
// 一人分の顔取得
const result = await faceapi.detectSingleFace(video, new faceapi.TinyFaceDetectorOptions()).withFaceLandmarks().withFaceExpressions();
//
if (result) {
const resizedDetections = faceapi.resizeResults(result, { width: video.clientWidth, height: video.clientHeight })
const ctx = createMedia.getContext('2d')
createMedia && ctx.clearRect(0, 0, video.clientWidth, video.clientHeight)
faceapi.draw.drawDetections(createMedia, resizedDetections) // 顔を認識
faceapi.draw.drawFaceExpressions(createMedia, resizedDetections) // 顔の表情を表示
faceapi.draw.drawFaceLandmarks(createMedia, resizedDetections, { drawLines: true }) // 顔のlandmarkを表示
}
}, 100)
}
}
useEffect(() => {
loadModels()
}, [])
当我拿出地标
在上一篇文章中,我可以将视频图像+地标输出到画布,但是使用face-api.js,感觉就像只有地标输出到画布一样。
所以说到使用它,就是用视频标签(你自己的相机图像)+画布(显示图像或将其放置在地标面上)覆盖它来使用它。
另外,Face Mesh 有 468 个路标,而 face-api.js 有 68 个路标,所以完全不同。
Face Mesh 获得更精细的细节。
人脸识别准确率对比
对于这里的准确率,我们将看即使面部侧向或向下也能识别人脸,或者即使面部快速移动也能识别。
目前,我将尝试用图像隐藏面部,就像我使用 Face Mesh 实现的那样。
* 我只会在处理发生变化的地方写
使用 face-api 实现(仅主要部分
// faceapiの情報をload
const loadModels = () => {
// ...
}
// video情報を取得し、ビデオを映す
const getVideo = () => {
// ...
}
// 顔を画像に変える
const changeFace = (result: any, canvas: HTMLCanvasElement, video: HTMLVideoElement, img) => {
const ctx = canvas.getContext('2d')
ctx.clearRect(0, 0, video.clientWidth, video.clientHeight)
canvas.width = video.clientWidth // レスポンシブ対応
canvas.height = video.clientHeight // レスポンシブ対応
const box = result.detection.box
const box_x = box.x
const box_y = box.y * 0.9 // landmark的におでこが見えるので少し上に
const box_width = box.width * 1.2 // landmark的に画像が小さいので気持ち大きめで表示
const box_height = box.height * 1.2
// let img: HTMLImageElement = new Image()
// img.src = FACE[0].path
ctx.drawImage(img, box_x, box_y, box_width, box_height)
}
const playFaceTracking = () => {
if (videoRef && videoRef.current) {
const video = videoRef.current as HTMLVideoElement
const createMedia = canvasRef.current as HTMLCanvasElement
faceapi.matchDimensions(createMedia, { width: video.clientWidth, height: video.clientHeight })
let img: HTMLImageElement = new Image()
img.src = FACE[0].path
setInterval(async () => {
// 一人分の顔取得
const result = await faceapi.detectSingleFace(video, new faceapi.TinyFaceDetectorOptions()).withFaceLandmarks().withFaceExpressions();
//
if (result) {
const resizedDetections = faceapi.resizeResults(result, { width: video.clientWidth, height: video.clientHeight })
changeFace(resizedDetections, createMedia, video, img)
}
}, 100)
}
}
useEffect(() => {
loadModels()
}, [])
我可以隐藏我的脸,但我担心我的额头会伸出来。 . .
人脸识别似乎不包括额头。 . . (即使这样,图像放置位置也略高。)
比较
在 Face Mesh 和 face-api.js 中,我都觉得人脸被侧翻了,即使在一个很好的角度,图像也隐藏了人脸。
面网
face-api.js
可能是因为 Face Mesh 有更多的地标,所以侧脸也会根据人脸的面积而变化。
此外,Face Mesh 让我觉得即使我摇晃我的脸,图像也会隐藏我的脸。 (灿烂)
然而,使用 face-api.js,当我像上面的 Gif 那样侧身摇脸时,我的真脸出现了足够的空间。 (因此,图像会受到限制......)
在运动物体检测和意义方面,Face Mesh 更准确?我感到。
面部表情分析
Face Mesh 无法进行面部表情分析,因此只能使用 face-api.js 实现。
让我们编写一个分析面部表情并为每个面部表情替换面部图像的过程。
* 我只会在处理发生变化的地方写
// faceapiの情報をload
const loadModels = () => {
// ...
}
// meetからvideo情報を取得し、ビデオを映す
const getVideo = () => {
// ...
}
// 顔の表情を分析する
// 固定小数点形式で出さないと小数点が正しくわからないので変換する
// 1に近い値を表情として表示する
const expression = async (result: any) => {
const data = result
// 配列にして固定小数点形式で文字列に変換
const expressionsArr = Object.entries(data.expressions)
const dataArr = expressionsArr.map((item: any, index: number) => {
item[1].toFixed(3)
// 小数点で比較すると面倒だったので100倍しておく
item[1] = item[1] * 100
return item
})
// 高い数値の表情を画像として出力する
const max = Math.max.apply(null, dataArr.map((o) => o[1]))
const resultFace = dataArr.find((v => Math.floor(v[1]) == Math.floor(max)))
return { path: faceData[`${ resultFace[0] }`] || FACE[`${ resultFace[0] }`], face: resultFace[0] || 'natural' }
}
// 顔を画像に変える
const changeFace = (result: any, canvas: HTMLCanvasElement, video: HTMLVideoElement, img: HTMLImageElement) => {
const ctx = canvas.getContext('2d')
ctx.clearRect(0, 0, video.clientWidth, video.clientHeight)
canvas.width = video.clientWidth // レスポンシブ対応
canvas.height = video.clientHeight // レスポンシブ対応
const box = result.detection.box
const box_x = Math.floor(box.x)
const box_y = Math.floor(box.y * 0.9) // landmark的におでこが見えるので少し上に
const box_width = Math.floor(box.width * 1.2) // landmark的に画像が小さいので気持ち大きめで表示
const box_height = (box.height * 1.2)
ctx?.drawImage(img, box_x, box_y, box_width, box_height)
}
const faceLoop = async (video: HTMLVideoElement, canvas: HTMLCanvasElement, img: HTMLImageElement) => {
// 一人分の顔取得
const result = await faceapi.detectSingleFace(video, new faceapi.TinyFaceDetectorOptions()).withFaceLandmarks().withFaceExpressions();
//
if (result) {
const resizedDetections = faceapi.resizeResults(result, { width: video.clientWidth, height: video.clientHeight })
const src = await expression(resizedDetections)
// img onloadしてから呼ばないと画像がバツバツ切れるくさい
img.onload = () => {
changeFace(resizedDetections, canvas, video, img)
}
img.src = src.path
img.alt = src.face
}
requestAnimationFrame(async () => await faceLoop(video, canvas, img))
}
const playFaceTracking = () => {
// ...
}
useEffect(() => {
loadModels()
setFaceData(FACE)
}, [])
通过这种方式,您可以通过分析面部表情来切换图像。
这对于面网格是不可能的。
挺有趣的。
概括
在尝试了 Face Mesh 和 face-api.js 之后,我想,“我很高兴它们都有优点。”
两人在开会的时候都能把脸藏起来,我想他们达到了目的。
最后,写一个比较总结。
面网
- 使用它就像将视频图像和人脸识别的各种对应关系放在 Canvas 上一样
- 由于landmarks很多,可以进行详细的人脸分析(landmarks数量为468,是face-api的9.5倍以上!)
- 有这么多的地标,很难知道地标在脸上的位置 → 见上一篇文章
- 即使你把脸转向一边,你仍然可以认出你的脸
- 将图像放在人脸上时,即使人脸抖动也能识别人脸,因此人脸识别的准确率很高。
- 无法分析面部表情。我不能,但是除了 Face Mesh 之外我还可以做其他事情,那就是MediaPipe 官方请看一下。
face-api.js
- 视频图像和人脸识别不共存,视频图像用于Video标签,人脸识别用于Canvas标签。
- landmark的数量没有Face Mesh多,但是可以进行人脸分析(landmark的数量为68)
- landmark的数量比Face Mesh少,文章也比较多,所以相比Face Mesh更容易理解哪个landmark点是人脸的一部分。
- 即使你把脸转向一边,你仍然可以认出你的脸
- 当您将图像放在脸上时,请经常摇晃您的脸。我要露脸所以你在使用的时候要小心一点。
- 能够分析面部表情。人脸识别还可以做其他事情,那就是face-api.js请看一下。
参考网站
- https://phoneappli.hatenablog.com/entry/2021/07/28/164928
- https://note.com/npaka/n/nc9c244b11089
- https://qiita.com/yuikoito/items/a494402993ac4be46d97
原创声明:本文系作者授权爱码网发表,未经许可,不得转载;
原文地址:https://www.likecs.com/show-308626114.html