使用tracking.js实现刷脸拍照功能

2,892 阅读1分钟

一、前言

1.主要内容:使用tracking.js实现捕捉到人脸后拍照功能。

2.tracking.js

Tracking.js 是一个独立的JavaScript库,用于跟踪从相机实时收到的数据。跟踪的数据既可以是颜色,也可以是人,也就是说我们可以通过检测到某特定颜色,或者检测一个人体/脸的出现与移动,来触发JavaScript 事件。它是非常易于使用的API,具有数个方法和事件(足够使用了)。                                  —— 努力挣钱的小鑫

3.实现效果实例

image.png

二、功能实现

1.引入tracking.js

这里使用的方式是在tracking.js官网下载,将tracking-min.js与face.js文件直接放到项目中。

image.png

使用人脸跟踪器核心代码

// 创建一个人脸跟踪器对象
var objects = new tracking.ObjectTracker('face'); 

// 创建监听事件
objects.on('track', function(event) {
  if (event.data.length === 0) {
    // No objects were detected in this frame.
  } else {
    event.data.forEach(function(rect) {
      // rect.x, rect.y, rect.height, rect.width
    });
  }
});

2.拍照组件

<template>
  <div class="face_recognition">
    <div class="video_box">
      <video
        id="video"
        preload
        autoplay
        loop
        muted
        x5-video-player-type="h5-page"
        webkit-playsinline="true"
        playsinline="true"
        width="250"
        height="250"
      ></video>

      <!-- canvas用来绘制识别出人脸的矩形框 -->
      <canvas id="canvas" width="250" height="250"></canvas>
      <!-- canvas1用来截取video中识别到人脸的某一帧照片 -->
      <canvas id="canvas1" width="250" height="250"></canvas>
    </div>
  </div>
</template>

<script>
import './tracking-min.js';
import './face-min.js';
import { Toast } from 'vant';
export default {
  name: 'faceRecognition',
  data() {
    return {
      deviceId: '',
      saveArray: {},
      trackerTask: null,
      tracker: null,
      canvasContext: null,
      canvas: null,
      videoEl: {}
    };
  },
  methods: {
    openVideo() {
      this.steps = 'screen';
      this.canvas = document.getElementById('canvas');
      this.canvasContext = this.canvas.getContext('2d');
      // 创建一个人脸跟踪器对象
      this.tracker = new tracking.ObjectTracker('face');
      // 设置识别的放大比例
      this.tracker.setInitialScale(4);
      // 设置步长
      this.tracker.setStepSize(2);
      // 边缘密度
      this.tracker.setEdgesDensity(0.1);
      // 打开相机
      this.trackerTask = tracking.track('#video', this.tracker, {
        camera: true
      });
      this.videoEl = document.getElementById('video');
      this.isUndefinedForGetuserMedia();
    },
    // 判读是否支持getUserMedia api
    isUndefinedForGetuserMedia() {
      tracking
        .promiseInitUserMedia_(this.videoEl, {
          camera: true
        })
        .catch(() => {
          Toast('暂不支持自动人脸识别,请点击拍照识别');
          this.$emit('isAutoRecognition', false);
        });
    },
    judgeFace() {
      let tipFlag = false; // 是否检测
      let faceflag = false; // 是否进行拍照
      const that = this;
      // 创建监听 每帧都会触发
      this.tracker.on('track', function (event) {
        if (!tipFlag) {
          // 擦除一个透明的矩形区域
          that.canvasContext.clearRect(
            0,
            0,
            that.canvas.width,
            that.canvas.height
          );
          if (event.data.length === 0) {
            // 未检测到人脸
            if (!faceflag) {
              Toast('未检测到人脸');
            }
          } else if (event.data.length === 1) {
            // 长度为多少代表检测到几张人脸
            // 检测到一张人脸
            if (!tipFlag) {
              Toast('识别成功,正在拍照,请勿乱动~');
              // 给检测到的人脸绘制矩形
              event.data.forEach(function (rect) {
                that.canvasContext.strokeStyle = '#a64ceb';
                that.canvasContext.strokeRect(
                  rect.x,
                  rect.y,
                  rect.width,
                  rect.height
                );
              });
              if (!faceflag) {
                // 检测到人脸进行拍照,延迟三秒
                faceflag = true;
                setTimeout(() => {
                  that.getPhoto(); // 拍照
                  tipFlag = true;
                }, 3000);
              }
            }
          } else {
            // 检测到多张人脸
            if (!faceflag) {
              Toast('只可一人进行人脸识别!');
            }
          }
        }
      });
    },
    // 获取人像照片
    getPhoto() {
      try {
        const canvas1 = document.getElementById('canvas1');
        const context2 = canvas1.getContext('2d');
        // 在canvas1上绘制video中的人像照片
        context2.drawImage(this.videoEl, 0, 0, 250, 250);
        this.keepImg();
      } catch (error) {}
    },
    // 将canvas转化为图片
    convertCanvasToImage(canvas) {
      const image = new Image();
      image.src = canvas.toDataURL('image/jpeg');
      return image;
    },
    // 保存图片
    keepImg() {
      const canvas1 = document.getElementById('canvas1');
      const base64 = this.convertCanvasToImage(canvas1).src;
      // 拿到检测到人脸图片的base64编码,可根据后续业务场景转换类型
      this.$emit('videoChange', base64);
    },
    closeFace() {
      try {
        this.clearCanvas();
        // 关闭摄像头
        if (typeof window.stream === 'object') {
          this.videoEl.srcObject = null;
          window.stream.getTracks().forEach((track) => track.stop());
        }
        // 停止侦测
        this.trackerTask.stop(); // this.trackerTask.run(); 重新执行侦测
      } catch (error) {
        // eslint-disable-next-line no-console
        console.log('err', error);
      }
    },
    clearCanvas() {
      const c = document.getElementById('canvas');
      const c1 = document.getElementById('canvas1');
      const cxt = c.getContext('2d');
      const cxt1 = c1.getContext('2d');
      cxt.clearRect(0, 0, 250, 250);
      cxt1.clearRect(0, 0, 250, 250);
    }
  }
};
</script>

<style lang="scss" scoped>
.face_recognition {
  height: 250px;
  .video_box {
    align-items: center;
    display: flex;
    height: 250px;
    justify-content: center;
    margin: auto;
    position: relative;
    width: 250px;
    #video {
      border-radius: 50%;
      height: 100%;
      object-fit: cover;
      width: 100%;
    }
    #canvas {
      height: 100%;
      left: 0;
      position: absolute;
      top: 0;
      transform: rotateY(180deg);
      width: 100%;
    }
    #canvas1 {
      opacity: 0;
      position: absolute;
    }
  }
}
</style>

3.tracking-min.js

// 需要将错误抛出到调用层
(tracking.promiseInitUserMedia_ = function (
  r,
  n,
  facingMode = { facingMode: { exact: 'environment' } } // 场景需要强制使用后置摄像头,如果要用前置将这里改为'user'
) {
  return new Promise((resolve, reject) => {
    t.navigator.mediaDevices 
      .getUserMedia({
        video: facingMode,
        audio: !(!n || !n.audio)
      }) // 使用navigator.mediaDevices.getUserMediaAPI打开相机
      .then(function (t) {
        r.srcObject = t;
        window.stream = t; // 关闭摄像头需要
        resolve(true);
      })
      ['catch'](function (t) {
        reject('Cannot capture user camera.');
      });
  });
}),

三、其他

1.base64、file、blob类型转换与使用compressorjs进行图片压缩

使用compressorjs进行图片压缩 - 掘金 (juejin.cn)

2.参考文章

【tracking.js】前端人脸识别框架 Tracking.js 活体检测/拍照实现 - 努力挣钱的小鑫 - 博客园 (cnblogs.com)