【笔记】前端人脸检测之clmtrackr.js的使用

clmtrackr.js使用示例代码

html代码:

 <div class="video-con">
        <video id="video" playsinline autoplay width="300" height="300"></video>
        <canvas style="visibility: hidden" id="canvas" width="300" height="300"></canvas>
      </div>

js代码:

import clm from "./clmtrackr.js";
export class FaceDemo {
  constructor(options, successFunction) {
    const opts = {
      videoId: "video",
      canvasId: "canvas",
      mediaConfig: {
        audio: false,
        video: {
          width: { min: 320, ideal: 720 },
          height: { min: 320, ideal: 720 },
          facingMode: "user"
        }
      }
    };

    this.video = document.getElementById(videoId);
    this.canvasId = canvasId;
	this.trackingStarted = false; // 是否开始检测人脸
	this.chunks = []; // 视频文件
	this.mediaRecorder = null; // 录制的视频对象

    this.getUserMedia();
  }

  // 原生设备摄像头兼容性getUserMedia
  getUserMedia() {
    window.URL = window.URL || window.webkitURL || window.msURL || window.mozURL;
    if (navigator.mediaDevices === undefined) {
      navigator.mediaDevices = {};
    }
    if (navigator.mediaDevices.getUserMedia === undefined) {
      navigator.mediaDevices.getUserMedia = function (constraints) {
        const getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia;
        if (!getUserMedia) {
          return Promise.reject(new Error("当前浏览器不支持getUserMedia"));
        }
        return new Promise(function (resolve, reject) {
          getUserMedia.call(navigator, constraints, resolve, reject);
        });
      };
    }
  }

  // 初始化多媒体视频录制实例
  initRecorder(stream) {
    const self = this;
    this.mediaRecorder = new MediaRecorder(stream);
    this.chunks = [];
    this.mediaRecorder.ondataavailable = function (event) {
      if (event.data && event.data.size > 0) {
        self.chunks.push(event.data);
      }
    };
    this.mediaRecorder.onstop = () => {
      let recorderFile = new Blob(this.chunks, {
        type: "video/mp4"
      });
	  
	  // 供下载视频文件
      const url = window.URL.createObjectURL(recorderFile);
      const a = document.createElement("a");
      a.style.display = "none";
      a.href = url;
      a.download = "video.mp4";
      document.body.appendChild(a);
      a.click();
	  
	  // 供提交视频流
      const file = new File([recorderFile], "video.mp4", {
        type: "video/mp4"
      });

    };
  }

  // 开始录制视频
  startRecorder() {
    this.mediaRecorder.start();
  }

  // 结束视频录制
  endRecorder() {
    this.mediaRecorder.stop();
  }


  init() {
    if (window.stream) {
      window.stream.getTracks().forEach((track) => {
        track.stop();
      });
    }
    return new Promise((resolve, reject) => {
      const self = this;
      navigator.mediaDevices
        .getUserMedia(this.options.mediaConfig)
        .then((stream) => {
          if ("srcObject" in this.video) {
            window.stream = stream;
            this.video.srcObject = stream;
          } else {
            this.video.src = window.URL && window.URL.createObjectURL(stream);
          }
          this.initRecorder(stream); // 初始化视频录制实例
          this.startRecorder(); // 开始录制视频
          this.video.onloadedmetadata = function () {
            self.video.play();
            setTimeout(() => {
              self.positionLoop();
            }, 1000);
          };

          this.video.onresize = function () {
            if (self.trackingStarted) {
              this.ctrack.stop();
              this.ctrack.reset();
              this.ctrack.start(self.video);
            }
          };
          resolve();
        })
        .catch((err) => {
          console.log("失败:" + err.message);
          reject(err);
        });
    });
  }

  positionLoop() {
    const self = this;
    this.ctrack = new clm.tracker();
    this.ctrack.init();
    this.ctrack.start(this.video);
    this.trackingStarted = true;
    this.drawCanvas = document.getElementById(this.canvasId);
    this.canvasCtx = this.drawCanvas.getContext("2d");

    function drawLoop() {
      requestAnimationFrame(drawLoop);
      const positions = self.ctrack && self.ctrack.getCurrentPosition();

      if (positions) {
        // 检测到人脸模型数据,进行相应的操作
      } else {
        // 没有检测到人脸
        console.log("没有检测到人脸");
      }
    }

    drawLoop();
  }
}

常见代码片段整理

根据官方文档,目前navigator.mediaDevices.getUserMedia在ios上只支持11版本以上,且只能在safari正常运行。安卓目前没有发现版本限制,需要兼容的代码:

getUserMedia() {
    window.URL = window.URL || window.webkitURL || window.msURL || window.mozURL;
    if (navigator.mediaDevices === undefined) {
      navigator.mediaDevices = {};
    }
    if (navigator.mediaDevices.getUserMedia === undefined) {
      navigator.mediaDevices.getUserMedia = function (constraints) {
        const getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia;
        if (!getUserMedia) {
          return Promise.reject(new Error("当前浏览器不支持getUserMedia"));
        }
        return new Promise(function (resolve, reject) {
          getUserMedia.call(navigator, constraints, resolve, reject);
        });
      };
    }
  }

第一次启用成功调用前置摄像头,第二次需要调用后置却黑屏或者失败

前置摄像头调用后,摄像功能需要关闭后才能正常执行第二次调用,否则会报错:设备被占用。解决方法,在每次执行调用方法前,先关闭摄像设备。

if (window.stream) {
      window.stream.getTracks().forEach((track) => {
        track.stop();
      });
}

设置录制视频分辨率

navigator.mediaDevices.getUserMedia({
    audio: true,
    video: {
      width: { min: 320, ideal: 720 },
      height: { min: 320, ideal: 720 },
      facingMode: "user"
    }
})

MediaRecorder录制视频

initRecorder(stream) {
    const self = this;
    this.mediaRecorder = new MediaRecorder(stream);
    this.chunks = [];
    this.mediaRecorder.ondataavailable = function (event) {
      if (event.data && event.data.size > 0) {
        self.chunks.push(event.data);
      }
    };
    this.mediaRecorder.onstop = () => {
      let recorderFile = new Blob(this.chunks, {
        type: "video/mp4"
      });
	  
	  // 供下载视频文件
      const url = window.URL.createObjectURL(recorderFile);
      const a = document.createElement("a");
      a.style.display = "none";
      a.href = url;
      a.download = "video.mp4";
      document.body.appendChild(a);
      a.click();
	  
	  // 供提交视频流
      const file = new File([recorderFile], "video.mp4", {
        type: "video/mp4"
      });

    };
  }

参考地址

posted @ 2023-01-18 10:01  风雨后见彩虹  阅读(619)  评论(0编辑  收藏  举报