Vue+tracking.js 实现前端人脸检测功能
作者:pibaba 发布时间:2024-05-05 09:24:56
标签:vue,tracking.js,人脸检测,人脸识别
项目中需要实现人脸登陆功能,实现思路为在前端检测人脸,把人脸照片发送到后端识别,返回用户token登陆成功
前端调用摄像头使用tracking.js检测视频流中的人脸,检测到人脸后拍照上传后端。
后端使用face_recognition人脸识别库,使用Flask提供restfulAP供前端调用
实现效果如下图:
登陆界面:
摄像头检测人脸界面:
前端代码如下:
<template>
<div id="facelogin">
<h1 class="title is-1">{{FaceisDetected}}</h1>
<!-- <p>{{FaceisDetected}}</p> -->
<div class="content-cam">
<div class="camera-wrp sec">
<video width="320" height="320" ref="videoDom" id="video_cam" preload autoplay loop muted></video>
<canvas width="320" height="320" ref="canvasDOM" id="face_detect"></canvas>
<div class="control-btn"></div>
</div>
<div class="images-wrp sec">
<!-- <p class="title is-5">Image taken</p> -->
<div
:class="`img-item img-item-${index}`"
v-for="(image, index) in images"
:key="`img-wrp-${index}`"
:style="`background-image: url('${image}')`"
></div>
</div>
</div>
</div>
</template>
export default {
name: 'facelogin',
data() {
return {
count: 0,
isdetected: '请您保持脸部在画面中央',
videoEl: {},
canvasEL: {},
images: [],
trackCcv: false,
trackTracking: false,
autoCaptureTrackTraking: false,
userMediaConstraints: {
audio: false,
video: {
// ideal(应用最理想的)
width: {
min: 320,
ideal: 1280,
max: 1920
},
height: {
min: 240,
ideal: 720,
max: 1080
},
// frameRate受限带宽传输时,低帧率可能更适宜
frameRate: {
min: 15,
ideal: 30,
max: 60
},
// 摄像头翻转
facingMode: 'user'
}
}
}
},
computed: {
FaceisDetected() {
return this.isdetected
}
},
created() {
this.changeView()
},
mounted() {
// The getUserMedia interface is used for handling camera input.
// Some browsers need a prefix so here we're covering all the options
navigator.getMedia =
navigator.getUserMedia ||
navigator.webkitGetUserMedia ||
navigator.mozGetUserMedia ||
navigator.msGetUserMedia
this.init()
},
methods: {
async init() {
this.videoEl = this.$refs.videoDom
this.canvasEL = this.$refs.canvasDOM
await navigator.mediaDevices
.getUserMedia(this.userMediaConstraints)
.then(this.getMediaStreamSuccess)
.catch(this.getMediaStreamError)
await this.onPlay()
},
async onPlay() {
debugHelper.log('onPlay')
this.onTrackTracking()
},
changeView() {
this.setTitle('刷脸登陆')
this.setBackDisabled(false)
this.setBackIcon('arrow_back')
msgbus.vm.setBottomNavVisible(false)
msgbus.vm.setBottomBtnVisible(false)
msgbus.vm.setMsgInputVisible({ value: false })
},
onTrackTracking() {
const context = this
const video = this.videoEl
const canvas = this.canvasEL
const canvasContext = canvas.getContext('2d')
let tracker = new tracking.ObjectTracker('face')
video.pause()
video.src = ''
tracker.setInitialScale(4)
tracker.setStepSize(2)
tracker.setEdgesDensity(0.1)
tracking.track('#video_cam', tracker, { camera: true })
tracker.on('track', function(event) {
const { autoCaptureTrackTraking } = context
canvasContext.clearRect(0, 0, canvas.width, canvas.height)
event.data.forEach(function({ x, y, width, height }) {
canvasContext.strokeStyle = '#a64ceb'
canvasContext.strokeRect(x, y, width, height)
canvasContext.font = '11px Helvetica'
canvasContext.fillStyle = '#fff'
})
if (!isEmpty(event.data) && context.count <= 10) {
if (context.count < 0) context.count = 0
context.count += 1
//debugHelper.log(context.count)
if (context.count > 10) {
context.isdetected = '已检测到人脸,正在登录'
//context.$router.push({ name: 'pwdlogin' })
}
} else {
context.count -= 1
if (context.count < 0) context.isdetected = '请您保持脸部在画面中央'
//this.isdetected = '已检测到人脸,正在登录'
}
})
},
onDownloadFile(item) {
const link = document.createElement('a')
link.href = item
link.download = `cahyo-${new Date().toISOString()}.png`
link.click()
link.remove()
},
onTakeCam() {
const canvas = document.createElement('canvas')
const video = this.$el.querySelector('#video_cam')
const canvasContext = canvas.getContext('2d')
if (video.videoWidth && video.videoHeight) {
const isBiggerW = video.videoWidth > video.videoHeight
const fixVidSize = isBiggerW ? video.videoHeight : video.videoWidth
let offsetLeft = 0
let offsetTop = 0
if (isBiggerW) offsetLeft = (video.videoWidth - fixVidSize) / 2
else offsetTop = (video.videoHeight - fixVidSize) / 2
// make canvas size 300px
canvas.width = canvas.height = 300
const { width, height } = canvas
canvasContext.drawImage(
video,
offsetLeft,
offsetTop,
fixVidSize,
fixVidSize,
0,
0,
width,
height
)
const image = canvas.toDataURL('image/png')
this.images.push(image)
}
},
onDetectFace(param, index) {
const imgItem = document.querySelector(`.img-item-${index}`)
const image = new Image()
image.src = param
const tracker = new tracking.ObjectTracker('face')
tracker.setStepSize(1.7)
tracking.track(image, tracker)
tracker.on('track', function(event) {
event.data.forEach(function(rect) {
window.plot(rect.x, rect.y, rect.width, rect.height)
})
})
window.plot = function(x, y, w, h) {
const rect = document.createElement('div')
document.querySelector(`.img-item-${index}`).appendChild(rect)
rect.classList.add('rect')
rect.style.width = w + 'px'
rect.style.height = h + 'px'
rect.style.left = x + 'px'
rect.style.top = y + 'px'
rect.style.border = '2px solid yellow'
rect.style.position = 'absolute'
}
},
getMediaStreamSuccess(stream) {
window.stream = stream // make stream available to browser console
this.videoEl.srcObject = stream
debugHelper.log('getMediaStreamSuccess1')
//this.$store.commit('setVideoCanvasObject', this.videoEl)
debugHelper.log('getMediaStreamSuccess2')
},
// 视频媒体流失败
getMediaStreamError(error) {
alert('视频媒体流获取错误' + error)
},
// 结束媒体流
stopMediaStreamTrack() {
clearInterval(this.timeInterval)
if (typeof window.stream === 'object') {
this.videoEl.srcObject = null
//this.$store.commit('setVideoCanvasObject', '')
window.stream.getTracks().forEach(track => track.stop())
}
},
来源:https://www.cnblogs.com/pihaochen/p/11268718.html


猜你喜欢
- 随着对Dreamweaver cs3中集成Spry功能的深入学习,了解并掌握到Spry框架的一些功能模块,其中就有通过Dreamweaver
- 我们的浏览器访问网站时,默认为发送了一个HTTP的GET请求。在浏览网站时,会经常填写表单,比如填写用户名密码。点击登录后,会跳转到我们的主
- 首先得明确包和模块。包:在一个目录下存在__init__.py,那么该目录就是一个包。模块:一个.py文件就是一个模块。我们可以通过from
- Python Json使用本篇主要介绍一下 python 中 json的使用 如何把 dict转成json 、object 转成json 、
- using System;using System.Collections.Generic;using System.Text;using
- 我在pycharm中写python代码的时候并不喜欢在运算符前后添加空格,例如我经常就直接写a=3而不是写成a = 3这个样子。对于我而言,
- PHP PDO 大对象 (LOBs)应用程序在某一时刻,可能需要在数据库中存储"大"数据。"大"通常
- 有时,为了方便看数据的变化情况,需要画一个动态图来看整体的变化情况。主要就是用Matplotlib库。首先,说明plot函数的说明。plt.
- Protocol 和服务器一样,也是通过该类来实现。先看一个简短的例程:from twisted.internet.protoc
- 前言相信大家在网上经常看到有人秀出各种各样的字符画,对于这个五彩斑斓的世界来说,我们日常看到的都是一些高清的彩色的图片,偶尔来个粗糙的黑白的
- Go语言基础三切片的定义1. 切片:切片是数组的一个引用,因此切片是引用类型。但自身是结构体,值拷贝传递。2. 切片的长度可以改变,因此,切
- 网站或服务的性能关键点很大程度在于数据库的设计(假设你选择了合适的语言开发框架)以及如何查询数据上。我们知道MySQL的性能优化方法,一般有
- fixHtmlTag version 0.2 这个版本解决了上次遗留的问题,即就近闭合和嵌套闭合问题。具体可以看代码的注释。 <?ph
- 在使用爬虫爬取网络数据时,如果长时间对一个网站进行抓取时可能会遇到IP被封的情况,这种情况可以使用代理更换ip来突破服务器封IP的限制。随手
- 为了偷个懒,利用这个数据库,但是在附加的时候出错了。错误如下:一开始还以为数据库位置存在问题,所以重新放置了一个位置,仍然无效。最后,上网寻
- 数据库属于 IO 密集型的应用程序,其主要职责就是数据的管理及存储工作。而我们知道,从内存中读取一个数据库的时间是微秒级别,而从一块普通硬盘
- 一、概论超大型系统的特点为:1、处理的用户数一般都超过百万,有的还超过千万,数据库的数据量一般超过1TB;2、系统必须提供实时响应功能,系统
- 一、property() 函数讲解了解 @property 装饰器之前,我们首先要了解内置函数的 property()。class prop
- 考虑下述Python代码片段。对文件中的数据进行某些操作,然后将结果保存回文件中:with open(filename) as f:&nbs
- 主要逻辑是判断文件的最后修改时间与创建时间是否在秒级别上一致,此代码适用于Python 2.import timeimport os#Rea