Vue中使用Tracking.js实现人脸检测

/ 技术文章 / 0 条评论 / 2437浏览

Vue中使用Tracking.js实现人脸检测

网上随便逛逛的时候,发现了和很酷的纯JS库,就是Tracking.js https://trackingjs.com/docs.html#introduction 这个库可以帮助我们实现很多功能,比如人脸识别,对象追踪,甚至还有直接的Brief、FAST算法,这样九尾在前端实现图像匹配提供可能性

虽然听上去很高深,但是其实他的API非常简单,即使什么人脸识别算法都不懂(比如我),也能够用Tracking.js实现 并且,Tracking.js团队还提供了已经训练好了的人脸,眼睛和嘴巴的模板,使用时按需引入就行了,但是模板也要100多KB,还是要按需引入

例子

这边用Vue做一个小DEMO例子

需求

通过摄像头找到镜头中的人脸,并标注、截图、记录

实现

注意:window.navigator.mediaDevices.getUserMedia()只能在localhost或https下才能使用 tracking.js在Vue中的使用与其他js库并未有什么区别,最粗暴的引用方式就是直接在index.html里面引入就行了 ···

  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1.0">
    <title>face-login</title>

    <script src="./static/tracking/tracking-min.js"></script>
	<script src="./static/tracking/data/face-min.js"></script>
  </head>

···

展示部分,首先要先放一个video展示摄像头的视频流、一个canvas用来画框框 再放一个列表方截图 ···

<div class='camera-wrapper'>
  <span class="loading">正在加载摄像头,请稍等</span>
  <video id="video" class="video" width="320" height="240" preload autoplay loop muted></video>
  <canvas id="canvas" class="video" width="320" height="240"></canvas>
</div>

<div class="gallaray">
    <div class="gallaray-item" v-for="(c, index) in captures" :key="index">
        <img :src="c" height="150" />
    </div>
</div>

···

先定几个全局变量,等会会用 ···

  data() {
    return {
      tracker: Object, //人脸追踪器
      trackerTask: Object, // 用于控制食品和画布的工具
      video: Object, // 页面视频元素
      canvas: Object, // 页面画布元素
      context: Object, // 画布内容
      captures: [], // 截图列表
      message: String 
    };
  },

···

在组件created()或mounted()里面初始化tracking.js。首先要确定需要追踪什么,tracking.js提供了一个抽象类可以创建任意的追踪器 ···

var myTracker = new tracking.Tracker('target');

··· 当然,它还提供了现成的颜色追踪器和对象(人脸)追踪器,可以这样创建 ···

var colors = new tracking.ColorTracker(['magenta', 'cyan', 'yellow']);
var objects = new tracking.ObjectTracker(['face', 'eye', 'mouth']);

··· 一旦实例化追踪其后,就可以监听track事件,一旦追踪到对象, 追踪器的回调函数里,会包含这幅图中所有的对象所在位置(矩形) 然后你就可以为所欲为了 ···

myTracker.on('track', function(event) {
  if (event.data.length === 0) {
    // No targets were detected in this frame.
  } else {
    event.data.forEach(function(data) {
      // Plots the detected targets here.
    });
  }
});

···

控制部分 一般情况下,我们不需要直接操作Video和canvas,tracking.js都帮我们做掉了 Tracking.js 初始化时会 调用** window.navigator.mediaDevices.getUserMedia()** 方法获取摄像头,我们不用操心

打开摄像头,开始追踪 ···

tracking.track('#myVideo', myTracker);

··· 如果把上面的返回付给一个对象还能用它来控制视频的暂停、播放 ···

var trackerTask = tracking.track('#myVideo', myTracker);
trackerTask.stop(); // Stops the tracking
trackerTask.run(); // Runs it again anytime

···

当识别出3副一上的人脸时,我希望程序停止识别、停止截图、停止摄像头的工作 因此,还需要手工对video做一些干预 ···

onStopTracking() {
  this.trackerTask.stop();
  this.video.pause();
  this.video.srcObject.getVideoTracks().forEach(videoTrack => {
    videoTrack.stop();
  });
},

···

部分实现代码 ···

   initTracker() {
      let _this = this;

      this.message = null;
      this.video = document.getElementById("video");
      this.canvas = document.getElementById("canvas");
      this.context = this.canvas.getContext("2d");

      // 初始化tracking参数
      this.tracker = new tracking.ObjectTracker("face");
      this.tracker.setInitialScale(4);
      this.tracker.setStepSize(2);
      this.tracker.setEdgesDensity(0.1);
      this.tracker.on("track", event => {
        _this.onTracked(event);
      });

      // 如果是读取视频,可以用trackerTask.stop trackerTask.run来暂停、开始视频
      this.trackerTask = tracking.track(this.video, this.tracker);

      // 启用摄像头
      tracking.track(this.video, this.tracker, { camera: true });
    },

    onTracked(event) {
      let _this = this;

      // 判断终止条件, stop是异步的,不返回的话,还会一直截图
      if (this.captures.length >= 3) {
        this.onStopTracking();
        return;
      }

      // 画框框
      this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
      event.data.forEach(rect => {
        _this.context.lineWidth = 5;
        _this.context.strokeStyle = "#50e3ce";
        _this.context.strokeRect(rect.x, rect.y, rect.width, rect.height);
        _this.context.font = "11px Helvetica";
        _this.context.fillStyle = "#fff";
        _this.context.fillText(
          "x: " + rect.x + "px",
          rect.x + rect.width + 5,
          rect.y + 11
        );
        _this.context.fillText(
          "y: " + rect.y + "px",
          rect.x + rect.width + 5,
          rect.y + 22
        );

        // 截图
        _this.captureImage(rect.x, rect.y, rect.width, rect.height);
      });
    },
	
    onStopTracking() {
      this.trackerTask.stop();
      this.video.pause();
      this.video.srcObject.getVideoTracks().forEach(videoTrack => {
        videoTrack.stop();
      });
    },

···

好,现在就剩截图了。很简单,创建一个临时画布根据track事件返回的位置,将人脸截取出来,输出到我们的captures[]里就完成了 当然追踪器追踪到的人脸是脸部五官的区域,截图时可以上下左右,留一点位置,我是左右留了25px,上下,留了50px ···

   captureImage(x, y, width, height) {
      const buffer = 25;
      var bufferCanvas = document.createElement("canvas");
      var bfx = bufferCanvas.getContext("2d");

      bufferCanvas.width = width + buffer * 2;
      bufferCanvas.height = height + buffer * 4;
      bfx.drawImage(this.video, - x + buffer, - y + buffer * 2 ,320,240);
      this.captures.push(bufferCanvas.toDataURL("image/png"));
    },

···

这样基本功能就实现了,在美化一下页面 项目部分代码: https://github.com/z-funfan/face-login/tree/master/face-login