【学习一下!】前端识别人脸,并增加眼镜挂件

144 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第4天,点击查看活动详情

一般人脸识别加处理都是后端来处理,现在尝试下用前端来实现一下
主要用的的库是face-api.js
www.npmjs.com/package/fac…

这个库基于tensorflow 又封装了一层,使得可以在浏览器和node环境中运行,

本文在浏览器环境简单实现一个demo

首先引入包,然后本地引入项目中的训练模型,在weights/目录下

image.png

引入包后,可以通过挂载到window上的 faceapi 变量调用方法

  1. 引入模型
// 加载模型
async function loadModel() {
  await faceapi.nets.ssdMobilenetv1.load("./weights");
  await faceapi.loadFaceLandmarkModel("./weights/face_landmark");
}

loadFaceLandmarkModel 是获取五官和脸部轮廓的标记点

  1. 分析图片(实时图片或者视频都可以通过循环调用方法来实现)

这里先做一个静态图片分析

传入 img dom 或者视频等

const getFace = async () => {
  const detections = await faceapi
    .detectAllFaces(imgDom.value)
    .withFaceLandmarks();
  pointList.value = detections[0].landmarks._positions;
  pointList.value.forEach((point, index) => {
    drwaPoint(index, point);
  });
};

此时在landmarks的positions 里面可以拿到人脸轮廓的标记点
能拿到点后我们能做的事就很多了,比如想给人脸增加一个眼镜,鼻子,嘴巴等

image.png

  1. 通过canvas 把 人脸的标记点绘制出来
const drwaPoint = (index, point) => {
  const heightLightList = [36, 45, 30, 33, 48, 54];
  cxt.value.fillStyle = heightLightList.includes(index) ? "blue" : "red";
  cxt.value.font = "5px bold";
  cxt.value.textAlign = "center";
  cxt.value.textBaseline = "middle";
  cxt.value.fillText(index, point.x, point.y);
};

此时人脸上就会显示轮廓标记

image.png

将几个关键的点做区分标记,方便后面做操作

4.拿到特殊点,然后根据点使用canvas绘制图片上去m

const addImg = (src, pointList, offsetX, offSetY) => {
  const img = new Image();
  img.src = src;
  const point1 = pointList[0];
  const point2 = pointList[1];
  const width =
    Math.sqrt((point2.x - point1.x) ** 2 + (point2.y - point1.y) ** 2) + 20;
  img.onload = () => {
    cxt.value.drawImage(
      img,
      point1.x - offsetX,// 图片没找到合适的,适当增加偏移量
      point1.y - offSetY,// 图片没找到合适的,适当增加偏移量
      width,
      width
    );
  };
};

然后依次绘制眼镜,鼻子,嘴巴

  addImg("assets/yanjing.png", [pointList.value[36], pointList.value[45]], 10, 60);
  addImg( "assets/zuiba.png",[pointList.value[48], pointList.value[54]], 10, 40);
  addImg("assets/bizi.png", [pointList.value[29], pointList.value[33]], 20, 20);

效果如下

image.png

image.png

现在只是简单的实现了人脸轮廓,后续可以增加视频实时采集

打印一下 faceapi.nets 看到里面还有很多有意思的方法

  • ageGenderNet: new AgeGenderNet() // 年龄识别
  • faceExpressionNet: new FaceExpressionNet(), // 表情识别
  • faceLandmark68Net: new FaceLandmark68Net(), // 面部点位识别(68点)
  • faceLandmark68TinyNet: new FaceLandmark68TinyNet(), // 面部快速点位识别
  • faceRecognitionNet: new FaceRecognitionNet(), // 面部识别
    ...

比如识别一下年龄

// 先加载对应模型
  await faceapi.nets.ageGenderNet.load("/weights/age");
  
  ... 
  const detections = await faceapi
    .detectAllFaces(imgDom.value)
    .withFaceLandmarks()
    // 调用年龄识别api
    .withAgeAndGender(); 

这时候就能拿到对应的年龄数据

image.png

其他的api,有兴趣的小伙伴可以试试。

还可以使用 tensorflow 获取更精细的一些标记点,根据点来判断人物状态,比如是否微笑,是否点头等