zoukankan      html  css  js  c++  java
  • 基于浏览器的人脸识别标记

    最近,Chrome在Chrome中集成了一套与图形识别相关的 API——Shape Detector API,只需要少量代码就能够实现人脸识别、二维码/条形码识别和文本识别。虽然这些 API 还处于实验阶段,只要条件允许,还是可以一下的。在 Windows 10 Chrome Canary 和 安卓 Chrome 等应用中,开启 chrome://flags/#enable-experimental-web-platform-features 功能,在控制台下输入

    window.FaceDetector
    
    window.BarcodeDetector
    
    window.TextDetector

    若得到“[native code]”,那么就可以使用这些 API 了。亲测 Windows7  Chrome 61 开启了 enable-experimental-web-platform-features 之后,虽然 window 包含以上三个 API,但调用 new FaceDetector.detector 时会报错:Face detection service unavailable.

    本来只是想简单的体验一下这个 API,没想到一不小心就写了这么多。。。

    Demo1

    demo代码

    在这个 demo 中,一共有三个类:

      (1)FaceTag:所有的逻辑操作(人脸识别、搜索面部、面部标记)都在该类中实现。

      (2)ShowImg:实现图片按原比例绘制、缩放图片、获取 base64、清除功能。

      (3)SignTool:实现绘制方框、绘制文字、清除功能。

    实际上,ShowImg 完全可以用 <img> 代替的,我只是为了能够缩小图片,缩短人脸检测的时间。由于图片一旦确定后,在检测和标记阶段是不变的,为了方便操作,ShowImg 和 SignTool 各包含一个 canvas。为了减少代码的重复,将创建 canvas 和获取 ctx 的任务交给了 FaceTag 。

    面部检测

    FaceDetector 真的很简单。

    创建实例的时候,可以给它传递 FaceDetectorOptions,这个对象只含两个有效参数:
      maxDetectedFaces:检测人脸的最大数目。
      fastMode:是否优先考虑速度。

    而它只提供了 detect(img) 一个方法,传入待检测的图像,结果以 Promise 的形式返回,是包含一组 DetectedFace 元素的数组,若检测不到则返回一个空数组。DetectedFace 的相关信息:x,y,left,top,right,bottom 等都包含在 boundingBox 中。

    至于检测结果的话,正脸的精确度挺高的,但是侧脸基本检测不到。
    class FaceTag {

      constructor(opt={}){
        ...
        this.detector = new FaceDetector(orignOpt.detectorOpt);
        ...
      }
      ...
      faceDetector(aspect = 1) {     return new Promise((resolve, reject) => {       let img = this.img.getImage();       this.detector.detect(img)         .then(faces => {           if(faces.length === 0) {             reject('检测不到面部哦');           }else {             this.faces = faces;             resolve(this.faces);           }         })         .catch(err => {           reject(err);         })     })   }
      ...
    }

    根据检测到的结果信息在 signTool 的 canvas 中绘制出来。

    class SignTool {
      ...
      /*
       * 标识面部
       * param {Array} faces 需要标识的部分
       */
      drawFaces(faces=[], aspect = 1) {
        faces.length > 0 && faces.forEach(face => {
          this.drawRect(face.boundingBox, aspect);
        })
      }
    
      /*
       * 绘制 rect
       * param {object} rect 需要绘制的 rect
       */
      drawRect(rect={}, aspect = 1) {
        this.ctx.save()
        this.ctx.beginPath();
        this.ctx.lineWidth = rect.lineWidth || 2;
        this.ctx.strokeStyle = rect.color || 'red';
        this.ctx.rect(Math.floor(rect.x * aspect),
          Math.floor(rect.y * aspect),
          Math.floor(rect.width * aspect),
          Math.floor(rect.height * aspect)
        );
        this.ctx.stroke();
        this.ctx.restore();
      }
      ...
    }

    选择面部

    本 demo 中为 signTool  的 canvas添加点击事件,通过鼠标坐标与检测到的所有面部信息进行比较,判断是否选中面部。选中之后,重新绘制一遍所有的面部,在将选中面部高亮。

    class FaceTag {
      ...  
      /*
       * signTool 的 canvas 添加点击事件
       */
      addEvent() {
        if(!this.signTool.canvas) {
          return;
        }
    
        let canvas = this.signTool.canvas;
        let canvasBox = canvas.getBoundingClientRect();
    
        canvas.addEventListener('click', e => {
        // 计算鼠标在canvas中的位置
        let eX = e.clientX - canvasBox.left;
        let eY = e.clientY - canvasBox.top;
    
        this.findFace(this.img.getImage(), eX, eY)
          .then(face => {
            this.signTool.drawFaces(this.faces);
            this.heightLighRect(face);
            // 保存选中的面部                            
            this.beTagFace = face;
          })
        })
      }  
      ... }

    最后,beTagFace 的信息,将文字标注在方框附近 ,对面部的标记就完成啦。

    Demo2

    demo代码

    本 demo 结合了 WebRTC,并将 面部检测部分移到了  Web Worker 中计算。

    /*
     * 获取视频流
     * @param {Object} opt video 的参数
     */
    getUserMedia(opt) {
      navigator.mediaDevices.getUserMedia({
        video: opt
      }).then(stream => {
        this.createVideo(stream);
         resizeCanvas();
      }).catch(err => {
        alert(err);
      })
    }
    
    /*
     * 创建 video 标签
     * @param {Object} stream 视频流
     */
    createVideo(stream) {
      this.video = document.createElement('video');
      this.video.autoplay = 'autoplay';
      this.video.src = window.URL.createObjectURL(stream);
      this.container.appendChild(this.video);
    }

    通过 navigator.mediaDevices.getUserMedia 获取权限打开摄像头,获取视频流。

    由于 detect()需要传入 ImageBitmapSource 对象,因此将视频流绘制到 canvas 中,通过 canvas 获取图像信息,将图像信息传递给 Web Worker,进行面部检测。之后的就和 demo1 大致相同。

  • 相关阅读:
    函数式宏定义与普通函数
    linux之sort用法
    HDU 4390 Number Sequence 容斥原理
    HDU 4407 Sum 容斥原理
    HDU 4059 The Boss on Mars 容斥原理
    UVA12653 Buses
    UVA 12651 Triangles
    UVA 10892
    HDU 4292 Food
    HDU 4288 Coder
  • 原文地址:https://www.cnblogs.com/xxhuan/p/7593757.html
Copyright © 2011-2022 走看看