网络编程
位置:首页>> 网络编程>> JavaScript>> 如何使用VUE+faceApi.js实现摄像头拍摄人脸识别

如何使用VUE+faceApi.js实现摄像头拍摄人脸识别

作者:BarryKerrigan  发布时间:2023-07-02 16:32:04 

标签:face,api.js,人脸识别

需求:

前端获取到摄像头信息,通过模型来进行判断人像是否在镜头中,镜头是否有被遮挡。

实现步骤:

1、通过video标签来展示摄像头中的内容

2、通过canvas来绘制视频中信息进行展示

3、在拍照时候将canvas的当前帧转成图片

第一步:下载引入必要包

下载依赖

face-api.js是核心依赖必须要下

npm install face-api.js

element-ui为了按钮好看一点(可以不下) ,axios用于请求发送

npm istall element-ui axios -S

 element-ui根据官方文档进行引入使用

import Vue from 'vue';
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
import App from './App.vue';
Vue.use(ElementUI);
new Vue({
 el: '#app',
 render: h => h(App)
});

下载model

下载地址: 模板地址

将项目中的model放入VUE中的public文件加下

如何使用VUE+faceApi.js实现摄像头拍摄人脸识别

如何使用VUE+faceApi.js实现摄像头拍摄人脸识别

第二步:先把HTML写上去 

<template>
   <div>
       <el-button type="primary" @click="useCamera">打开摄像头</el-button>
       <el-button type="plain" @click="photoShoot">拍照</el-button>
       <el-alert
           :title="httpsAlert"
           type="info"
           :closable="false"
           v-show="httpsAlert !== ''">
       </el-alert>
       <div class="videoImage" ref="faceBox">
           <video ref="video" style="display: none;"></video>
           <canvas ref="canvas" width="400" height="400" v-show="videoShow"></canvas>
           <img ref="image" :src="picture" alt="" v-show="pictureShow">
       </div>
   </div>
</template>

第三步 可以开始代码了

首先引入下载好的face-api.js包

import * as faceApi from 'face-api.js'

 以下是需要用到的属性

1、视频和图片不同时出现

videoShow: false,
pictureShow: false,

2、生成图片后用于保存图片路径

picture: '',

3、因为在操作时会用到DOM所以将要用到虚拟DOM保存在data中

canvas: null,
video: null,
image: null,

 4、模型识别时直接传入此属性,在初始化时赋值(可省略,直接卸载逻辑代码中)

options: ''

 5、在人脸识别时对结果进行反馈(识别出人像数量大于1或小于1时给出提示)

noOne: '',
moreThanOne: '',

6、如果用户不是在https下进行使用摄像头调用给出提示

httpsAlert: ''

属性准备好之后就可以开始初始化了

1、初始化模型

2、获取需要用到的虚拟DOM

async init() {
   await faceApi.nets.ssdMobilenetv1.loadFromUri("/models");
   await faceApi.loadFaceLandmarkModel("/models");
   this.options = new faceApi.SsdMobilenetv1Options({
       minConfidence: 0.5, // 0.1 ~ 0.9
   });
   // 视频中识别使用的节点
   this.video = this.$refs.video
   this.canvas = this.$refs.canvas
   this.image = this.$refs.image
}

调用摄像头

通过navigator.mediaDevices.getUserMedia()

useCamera(){
   this.videoShow = true
   this.pictureShow = false
   this.cameraOptions()
},
cameraOptions(){
   let constraints = {
       video: {
           width: 400,
           height: 400
       }
   }
   // 如果不是通过loacalhost或者通过https访问会将报错捕获并提示
   try{
       let promise = navigator.mediaDevices.getUserMedia(constraints);
       promise.then((MediaStream) => {
           // 返回参数
           this.video.srcObject = MediaStream;
           this.video.play();
           this.recognizeFace()
       }).catch((error) => {
           console.log(error);
       });
   }catch(err){
       this.httpsAlert = `您现在在使用非Https访问,
       请先在chrome://flags/#unsafely-treat-insecure-origin-as-secure中修改配置,
       添将当前链接${window.location.href}添加到列表,
       并且将Insecure origins treated as secure修改为enabled,
       修改完成后请重启浏览器后再次访问!`
   }
}

识别视频中的人像

这里通过递归的方式将视频中的内容用canvas显示

将canvas的节点传入到faceApi的方法中进行识别

通过faceApi返回的数组可以得到当前人脸的识别状况(数组长度0没有识别到人脸,长度1识别到一个人脸...以此类推)

async recognizeFace(){
   if (this.video.paused) return clearTimeout(this.timeout);
   this.canvas.getContext('2d', { willReadFrequently: true }).drawImage(this.video, 0, 0, 400, 400);
   const results = await faceApi.detectAllFaces(this.canvas, this.options).withFaceLandmarks();
   if(results.length === 0){
       if(this.moreThanOne !== ''){
           this.moreThanOne.close()
           this.moreThanOne = ''
       }
       if(this.noOne === ''){
           this.noOne = this.$message({
               message: '未识别到人脸',
               type: 'warning',
               duration: 0
           });
       }
   }else if(results.length > 1){
       if(this.noOne !== ''){
           this.noOne.close()
           this.noOne = ''
       }
       if(this.moreThanOne === ''){
           this.moreThanOne = this.$message({
               message: '检测到镜头中有多个人',
               type: 'warning',
               duration: 0
           });
       }
   }else{
       if(this.noOne !== ''){
           this.noOne.close()
           this.noOne = ''
       }
       if(this.moreThanOne !== ''){
           this.moreThanOne.close()
           this.moreThanOne = ''
       }
   }
   this.timeout = setTimeout(() => {
       return this.recognizeFace()
   });
},

拍照上传 

async photoShoot(){
   // 拿到图片的base64
   let canvas = this.canvas.toDataURL("image/png");
   // 拍照以后将video隐藏
   this.videoShow = false
   this.pictureShow = true
   // 停止摄像头成像
   this.video.srcObject.getTracks()[0].stop()
   this.video.pause()
   if(canvas) {
       // 拍照将base64转为file流文件
       let blob = this.dataURLtoBlob(canvas);
       let file = this.blobToFile(blob, "imgName");
       // 将blob图片转化路径图片
       let image = window.URL.createObjectURL(file)
       this.picture = image
       return
       let formData = new FormData()
       formData.append('file', this.picture)
       axios({
           method: 'post',
           url: '/user/12345',
           data: formData
       }).then(res => {
           console.log(res)
       }).catch(err => {
           console.log(err)
       })
   } else {
       console.log('canvas生成失败')
   }
},

需要用到的图片格式转换方法 

方法1:先将base64转为文件

方法2:设置新的文件中的参数信息

dataURLtoBlob(dataurl) {
   let arr = dataurl.split(','),
       mime = arr[0].match(/:(.*?);/)[1],
       bstr = atob(arr[1]),
       n = bstr.length,
       u8arr = new Uint8Array(n);
   while(n--) {
       u8arr[n] = bstr.charCodeAt(n);
   }
   return new Blob([u8arr], {
       type: mime
   });
},
blobToFile(theBlob, fileName) {
   theBlob.lastModifiedDate = new Date().toLocaleDateString();
   theBlob.name = fileName;
   return theBlob;
},

完整代码

import bingImage from '@/assets/bbt1.jpg';
import BingWallpaper from '@/assets/BingWallpaper.jpg';
import * as faceApi from 'face-api.js'
export default {
   name: 'Recognize',
   data(){
       return{
           videoShow: false,
           pictureShow: false,
           // 图片地址
           picture: '',
           // 用于视频识别的节点
           canvas: null,
           video: null,
           image: null,
           timeout: 0,
           // 模型识别的条件
           options: '',
           // 提示控制
           noOne: '',
           moreThanOne: '',
           // 不是通过Https访问提示
           httpsAlert: '',
       }
   },
   mounted() {
       // 初始化
       this.init()
   },
   beforeDestroy() {
       clearTimeout(this.timeout);
   },
   methods: {
       async init() {
           await faceApi.nets.ssdMobilenetv1.loadFromUri("/models");
           await faceApi.loadFaceLandmarkModel("/models");
           this.options = new faceApi.SsdMobilenetv1Options({
               minConfidence: 0.5, // 0.1 ~ 0.9
           });
           // 视频中识别使用的节点
           this.video = this.$refs.video
           this.canvas = this.$refs.canvas
           this.image = this.$refs.image
       },
       /**
        * 使用视频来成像摄像头
        */
       useCamera(){
           this.videoShow = true
           this.pictureShow = false
           this.cameraOptions()
       },
       /**
        * 使用摄像头
        */
       cameraOptions(){
           let constraints = {
               video: {
                   width: 400,
                   height: 400
               }
           }
           // 如果不是通过loacalhost或者通过https访问会将报错捕获并提示
           try{
               let promise = navigator.mediaDevices.getUserMedia(constraints);
               promise.then((MediaStream) => {
                   // 返回参数
                   this.video.srcObject = MediaStream;
                   this.video.play();
                   this.recognizeFace()
               }).catch((error) => {
                   console.log(error);
               });
           }catch(err){
               this.httpsAlert = `您现在在使用非Https访问,
               请先在chrome://flags/#unsafely-treat-insecure-origin-as-secure中修改配置,
               添将当前链接${window.location.href}添加到列表,
               并且将Insecure origins treated as secure修改为enabled,
               修改完成后请重启浏览器后再次访问!`
           }
       },
       /**
        * 人脸识别方法
        * 通过canvas节点识别
        * 节点对象执行递归识别绘制
        */
       async recognizeFace(){
           if (this.video.paused) return clearTimeout(this.timeout);
           this.canvas.getContext('2d', { willReadFrequently: true }).drawImage(this.video, 0, 0, 400, 400);
           const results = await faceApi.detectAllFaces(this.canvas, this.options).withFaceLandmarks();
           if(results.length === 0){
               if(this.moreThanOne !== ''){
                   this.moreThanOne.close()
                   this.moreThanOne = ''
               }
               if(this.noOne === ''){
                   this.noOne = this.$message({
                       message: '未识别到人脸',
                       type: 'warning',
                       duration: 0
                   });
               }
           }else if(results.length > 1){
               if(this.noOne !== ''){
                   this.noOne.close()
                   this.noOne = ''
               }
               if(this.moreThanOne === ''){
                   this.moreThanOne = this.$message({
                       message: '检测到镜头中有多个人',
                       type: 'warning',
                       duration: 0
                   });
               }
           }else{
               if(this.noOne !== ''){
                   this.noOne.close()
                   this.noOne = ''
               }
               if(this.moreThanOne !== ''){
                   this.moreThanOne.close()
                   this.moreThanOne = ''
               }
           }
           // 通过canvas显示video信息
           this.timeout = setTimeout(() => {
               return this.recognizeFace()
           });
       },
       /**
        * 拍照上传
        */
       async photoShoot(){
           // 拿到图片的base64
           let canvas = this.canvas.toDataURL("image/png");
           // 拍照以后将video隐藏
           this.videoShow = false
           this.pictureShow = true
           // 停止摄像头成像
           this.video.srcObject.getTracks()[0].stop()
           this.video.pause()
           if(canvas) {
               // 拍照将base64转为file流文件
               let blob = this.dataURLtoBlob(canvas);
               console.log(blob)
               let file = this.blobToFile(blob, "imgName");
               console.info(file);
               // 将blob图片转化路径图片
               let image = window.URL.createObjectURL(file)
               this.picture = image
               // 将拍照后的图片发送给后端
               let formData = new FormData()
               formData.append('file', this.picture)
               axios({
                   method: 'post',
                   url: '/user/12345',
                   data: formData
               }).then(res => {
                   console.log(res)
               }).catch(err => {
                   console.log(err)
               })
           } else {
               console.log('canvas生成失败')
           }
       },
       /**
        * 将图片转为blob格式
        * dataurl 拿到的base64的数据
        */
       dataURLtoBlob(dataurl) {
           let arr = dataurl.split(','),
               mime = arr[0].match(/:(.*?);/)[1],
               bstr = atob(arr[1]),
               n = bstr.length,
               u8arr = new Uint8Array(n);
           while(n--) {
               u8arr[n] = bstr.charCodeAt(n);
           }
           return new Blob([u8arr], {
               type: mime
           });
       },
       /**
        * 生成文件信息
        * theBlob 文件
        * fileName 文件名字
        */
       blobToFile(theBlob, fileName) {
           theBlob.lastModifiedDate = new Date().toLocaleDateString();
           theBlob.name = fileName;
           return theBlob;
       },
   }
}

来源:https://blog.csdn.net/m0_46114541/article/details/129158790

0
投稿

猜你喜欢

手机版 网络编程 asp之家 www.aspxhome.com