如何使用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文件加下
第二步:先把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


猜你喜欢
- k8s容器互联-flannel vxlan 原理篇容器系列文章容器系列视频vxlan 模式通信原理flannel 在为不同主机的pod分配i
- 了兑现我对大家的承诺,我们现在立即就将“借助数据库和ASP程序”编写出来的,可以同时适用于IIS和P
- 一、安装python基础环境:centos7.6安装:下载python:https://www.python.org/ftp/python/
- 本文实例讲述了python实现web方式logview的方法。分享给大家供大家参考。具体如下:这里用Python实现web方式查看日志的一个
- 一、基本概念查找(Searching)就是根据给定的某个值,在查找表中确定一个其关键字等于给定值的数据元素(或记录)。查找表(Search
- 如下所示:import numpy as np arr = [1,2,3,4,5,6]#求均值arr_mean = np.mean(arr)
- 首先,我们来随便写一个带空格的列表:list1 = ['122','2333','3444'
- 使用Python可视化Pygal包来生成可缩放的矢量图形文件!对于在尺寸不同的屏幕上显示图标,它们将自动缩放以适合观看者的屏幕,如果以在线的
- JAVA程序想要访问数据库,需要进行如下准备:1.安装一个数据库(这里使用mysql免安装版)2.下载该数据库的驱动包(这里使用mysql官
- 在最近的一个项目需要实现在MySQL单表多关键字模糊查询,但这数个关键字并不一定都存在于某个字段。例如现有table表,其中有title,t
- PyQt5窗口布局控件QStackedWidget介绍QTackedWidget是一个堆栈窗口控件,可以填充一些小控件,但是同一时间只有一个
- 近来想要做一做人脸识别相关的内容,主要是想集成一个系统,看到opencv已经集成了三种性能较好的算法,但是还是想自己动手试一下,毕竟算法都比
- 所谓网络爬虫,通俗的讲,就是通过向我们需要的URL发出http请求,获取该URL对应的http报文主体内容,之后提取该报文主体中我们所需要的
- 最近在学习vue,今天看到自定义事件的表单输入组件,纠结了一会会然后恍然大悟...官方教程写得不是很详细,所以我决定总结一下。v-model
- 前言:数据库备份的重要性不言而喻,特别是在生产环境,任何数据的丢失都可能产生严重的后果。所以,无论什么环境,我们都应该有相应的备份策略来定时
- 作为一个从 PHP 转 Java 的人,发现 alibaba 的 arthas 很好用。通过 arthas 的 redefine 命令,可以
- 卸载MySQL1、在控制面板,卸载MySQL的所有组件控制面板——》所有控制面板项——》程序和功能,卸载所有和MySQL有关的程序2、找到你
- 前言虚拟环境是程序执行时的独立执行环境,在同一台服务器中可以创建不同的虚拟环境供不同的系统使用,项目之间的运行环境保持独立性而相互不受影响。
- 面试题 01.09. 字符串轮转面试题 01.09. 字符串轮转 难度:easy字符串轮转。给定两个字符串 s1 和 s2,请编写代码检查
- 目录1 键的类型,列表/字典不可以,其它都可以2 多个对象可当作键名,顺序不同时是不同的键3 结论【有误】:今天看别人代码时发现一个事,就是