• face-api.js 学习笔记


    参考

    Build Real Time Face Detection With JavaScript (youtube get started)

    face-api.js — JavaScript API for Face Recognition in the Browser with tensorflow.js

    教程 | face-api.js:在浏览器中进行人脸识别的JavaScript接口 (有提到相似度)

    face-api.js github

    face-api.js documentation

    注意事项: 

    由于 face-api.js 作者从 2020 Apr 之后就没有维护了, 以至于在 node.js 的时候无法使用最新的 @tensorflow/tfjs-node (issue 在这里)

    后来有个好心人 folk 出来改. 所以推荐大家使用新的版本 @vladmandic/face-api      

    Get started

    Build Real Time Face Detection With JavaScript (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 = document.createElement('canvas');
      canvas.style.position = 'absolute';
      document.body.append(canvas);
    
      // 配置显示尺寸
      const displaySize = {  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 = faceapi.resizeResults(detections, displaySize);
    
        canvas.getContext('2d')?.clearRect(0, 0, canvas.width, canvas.height); // 清空画布
        faceapi.draw.drawDetections(canvas, resizedDetections); // 位置
        faceapi.draw.drawFaceLandmarks(canvas, resizedDetections); // 路阔
        faceapi.draw.drawFaceExpressions(canvas, resizedDetections); // 表情
      }, 100);
    });
    
    setTimeout(async () => {
      // 加载 models
      await Promise.all([
        faceapi.nets.tinyFaceDetector.loadFromUri('/face-api-models'),
        faceapi.nets.faceLandmark68Net.loadFromUri('/face-api-models'),
        faceapi.nets.faceRecognitionNet.loadFromUri('/face-api-models'),
        faceapi.nets.faceExpressionNet.loadFromUri('/face-api-models'),
      ]);
      // 开启 webcam, 把 webcam 的流引入 video 显示
      navigator.getUserMedia(
        { 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([
        faceapi.nets.tinyFaceDetector.loadFromUri('/face-api-models'),
        faceapi.nets.faceLandmark68Net.loadFromUri('/face-api-models'),
        faceapi.nets.faceRecognitionNet.loadFromUri('/face-api-models'),
        faceapi.nets.faceExpressionNet.loadFromUri('/face-api-models'),
        faceapi.nets.ageGenderNet.loadFromUri('/face-api-models'),
      ]);
      const processAsync = async (image: HTMLImageElement) => {
        const imageContainer = image.parentElement!;
        const canvas = document.createElement('canvas');
        canvas.style.position = 'absolute';
        canvas.style.left = '0';
        canvas.style.top = '0';
        imageContainer.append(canvas);
        const displaySize = {  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 = faceapi.resizeResults(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: Math.round(resizedDetection.age) + ' year old ' + resizedDetection.gender,
        });
        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 是有跑的, 要留意哦)

    安装 Python (我是通过 visual studio installer 安装的 3.x 版本, windows server 的话通过 installer 安装 2.x 版本 (可能 3.x 也是 ok), 在配置的时候记得选要 setup path)

    set environment variables path

    常见问题

    代码

    参考: face-api.js docs 

    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;
    faceapi.env.monkeyPatch({ Canvas, Image, ImageData });
    
    (async () => {
      await Promise.all([
        // 换成了 from disk
        faceapi.nets.tinyFaceDetector.loadFromDisk('face-api-models'),
        faceapi.nets.faceLandmark68Net.loadFromDisk('face-api-models'),
        faceapi.nets.faceRecognitionNet.loadFromDisk('face-api-models'),
        faceapi.nets.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;
    faceapi.env.monkeyPatch({ Canvas, Image, ImageData });
    
    (async () => {
      await Promise.all([
        // 换成了 from disk
        faceapi.nets.tinyFaceDetector.loadFromDisk('face-api-models'),
        faceapi.nets.faceLandmark68Net.loadFromDisk('face-api-models'),
        faceapi.nets.faceRecognitionNet.loadFromDisk('face-api-models'),
        faceapi.nets.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
  • 相关阅读:
    字符串导出xml文件并弹出下载对话框
    Resource interpreted as Document but transferred with MIME type application/json
    org.w3c.dom document 和xml 字符串 互转
    Java xml出现错误 javax.xml.transform.TransformerException: java.lang.NullPointerException
    plsql developer中如何设置sql window显示行号
    Oracle表数据转换为XML格式数据
    Java用于取得当前日期相对应的月初,月末,季初,季末,年初,年末时间
    JS 中Json常用操作
    详解html中的marquee属性
    .net core 3.0中的Json API
  • 原文地址:https://www.cnblogs.com/keatkeat/p/15106226.html
Copyright © 2020-2023  润新知