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

做项目要用到活体检测和拍照的

实现效果

活体检测组件

包需到下载 tracking-min.js 和 face-min.js 压缩文件,自行百度。

点击查看活体检测组件代码
<template><el-dialog:visible="modalVisible"width="681px"custom-class="compaines-dialog"title="Complete Registration"class="face-dialog"v-dialogDrag:close-on-click-modal="false"@close="close":append-to-body="true"><div class="face" v-loading="faceloading"><p class="big-title">Liveness detection</p><!-- <p v-if="steps === 'open' || steps === 'screen'">Please place your face into the outlined area,we will take the photoautomatically!</p> --><p v-if="steps === 'open' || steps === 'screen'">{{ faceTips[imgList.length] }}</p><divv-if="steps === 'screen' && imgList.length > 0"style="text-align: center; font-size: 30px"><svg-icon :iconClass="faceLocation[imgList.length]" /></div><p v-if="steps === 'end'"><span v-if="faceOk" class="success">Successful!</span><span v-else class="fail">Failed!</span></p><div class="video-container" v-show="steps !== 'end'"><videoid="video"preloadautoplayloopmutedwidth="295"height="345":style="reverse ? 'transform:rotateY(180deg);' : ''"></video><canvas id="canvas" width="295" height="345"></canvas><canvasid="shortCut"width="295"height="345"style="opacity: 0"></canvas><canvasid="canvas1"width="295"height="345"style="opacity: 0"></canvas><i @click="reverseVideo" v-show="steps === 'screen'"><svg-icon iconClass="icon-camera" class="icon-camera" /></i></div><div v-show="steps === 'end'" style="text-align: center"><img v-if="faceOk" src="@/icons/img/face-success.png" alt="" /><img v-else src="@/icons/img/face-fail.png" alt="" /></div><div class="btns"><div class="add-num w300" @click="start" v-if="steps === 'open'">TURN CAMERA ON</div><divclass="retake-btn w300"style="margin-right: 0"@click="close"v-if="steps === 'screen'">TURN CAMERA OFF</div><divclass="retake-btn w300"@click="tryAgain"v-if="steps === 'end' && !faceOk">TRY AGAIN</div><divclass="add-num w300"@click="finish"v-if="steps === 'end' && faceOk">FINISH</div><p class="tips" v-if="steps === 'screen'">(To complete the liveness detection your camera must remain on)</p></div><div class="imgs" v-show="false"><p>未保存图片</p><p>已保存图片</p><div id="img"></div></div></div></el-dialog>
</template>
<script>
import './tracking-min.js'
import './face-min.js'
import { livenessCheck } from '@modules/kyc/api/system/system'
import debounce from 'lodash/debounce'export default {name: 'testTracking',model: {prop: 'formData',event: 'input',},props: {modalVisible: {type: Boolean,default: false,},formData: {type: Object | String,},option: {type: String,default: '',},},data() {return {saveArray: {},imgView: false,timer: true,steps: 'open',imgList: [],faceTips: ['Please place your face into the outlined area,we will take the photo automatically!','Look to the left','Look to the right','Tilt your head up','Tilt your head down',],faceLocation: ['','arrow-left','arrow-right','arrow-up','arrow-down','',],faceloading: false,faceOk: false,startPhoto: false,reverse: true,}},created() {this.start = debounce(this.start, 500)},methods: {// 打开摄像头start() {window.navigator.mediaDevices.getUserMedia({video: true,}).then((stream) => {this.openVideo()}).catch((err) => {this.$message.error('Cannot capture user camera')})},openVideo() {let that = thisthis.steps = 'screen'this.startPhoto = truelet canvas = document.getElementById('canvas')let context = canvas.getContext('2d')let tracker = new tracking.ObjectTracker('face')tracker.setInitialScale(4)tracker.setStepSize(2)tracker.setEdgesDensity(0.1)this.trackerTask = tracking.track('#video', tracker, { camera: true })tracker.on('track', function (event) {context.clearRect(0, 0, canvas.width, canvas.height)event.data.forEach(function (rect) {if (that.reverse) {context.strokeRect(295 - rect.x - rect.width,rect.y,rect.width,rect.height)} else {context.strokeRect(rect.x, rect.y, rect.width, rect.height)}context.strokeStyle = '#fff'context.fillStyle = '#fff'that.saveArray.x = rect.xthat.saveArray.y = rect.ythat.saveArray.width = rect.widththat.saveArray.height = rect.height})})this.timer = truethis.setPhotoInterval()},setPhotoInterval() {const countFun = () => {setTimeout(() => {if (this.timer && this.startPhoto) {countFun()if (this.reverse) {if (this.saveArray.x < 150 &&this.saveArray.y < 150 &&this.saveArray.width > 150 &&this.saveArray.height > 150) {this.getPhoto()}} else {if (295 - this.saveArray.x - this.saveArray.width < 150 &&this.saveArray.y < 150 &&this.saveArray.width > 150 &&this.saveArray.height > 150) {this.getPhoto()}}}}, 1000)}countFun()},// 获取人像照片getPhoto() {try {let video = document.getElementById('video')let cut = document.getElementById('shortCut')let context2 = cut.getContext('2d')context2.drawImage(video, 0, 0, 295, 345)this.keepImg()} catch (error) {}},// 将canvas转化为图片convertCanvasToImage(canvas) {let image = new Image()image.src = canvas.toDataURL('image/png')return image},//将base64转换为文件,dataurl为base64字符串,filename为文件名(必须带后缀名,如.jpg,.png)dataURLtoFile(dataurl, filename) {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 File([u8arr], filename, { type: mime })},// 保存图片keepImg() {//先保存完整的截图let cut = document.getElementById('shortCut')let context = cut.getContext('2d')//从完整截图里面,截取左侧294x345大小的图片,添加到canvas1里面let imgData = context.getImageData(0, 0, 294, 345)let canvas1 = document.getElementById('canvas1')let context1 = canvas1.getContext('2d')context1.putImageData(imgData, 0, 0)let img = document.getElementById('img')//把canvas1里面的294x345大小的图片保存let photoImg = document.createElement('img')photoImg.src = this.convertCanvasToImage(canvas1).srcimg.appendChild(photoImg)this.imgList.push(this.dataURLtoFile(this.convertCanvasToImage(canvas1).src,`person${this.imgList.length}.jpg`))this.timer = false//捕捉成功后停顿3秒,再捕捉下一张,捕捉5张后上传文件if (this.imgList.length === 5) {this.sendImages()} else {setTimeout(() => {this.timer = truethis.setPhotoInterval()}, 3000)}},sendImages() {let formData = new FormData()this.imgList.forEach((item) => {formData.append('files', item)})this.faceloading = trueformData.append('actionId', this.formData.id)livenessCheck(formData, { isUpload: true }).then((res) => {if (res.success) {this.faceOk = true} else {this.faceOk = false}this.faceloading = falsethis.steps = 'end'}).catch((err) => {this.openVideo()this.faceloading = falsethis.imgList = []})},tryAgain() {this.imgList = []this.openVideo()},finish() {this.closeFace()this.$emit('Liveness check success')this.$emit('close', 'success')},clearCanvas() {let c = document.getElementById('canvas')let c1 = document.getElementById('canvas1')let cxt = c.getContext('2d')let cxt1 = c1.getContext('2d')cxt.clearRect(0, 0, 581, 436)cxt1.clearRect(0, 0, 581, 436)},closeFace() {try {this.startPhoto = falsethis.timer = falsethis.imgList = []this.clearCanvas()// 关闭摄像头let video = document.getElementById('video')video.srcObject.getTracks()[0].stop()// 停止侦测this.trackerTask.stop()} catch (error) {}},close() {this.closeFace()if(this.faceOk){this.$emit('close', 'success')}else{this.$emit('close')}},reverseVideo() {this.reverse = !this.reverse},},watch: {},
}
</script>
<style lang="scss">
@import './face.scss';
</style>

拍照组件代码

点击查看拍照组件代码
<template><el-dialog:visible="modalVisible"width="681px"custom-class="compaines-dialog"title="Complete Registration"class="face-dialog"@close="close"><div class="face" v-loading="faceloading"><p class="big-title" v-if="steps !== 'save'">Take a profile picture</p><p class="big-title success" v-if="steps === 'save'">Complete!</p><p v-if="steps === 'open'">Please turn on your camera and center your face within the below guides.</p><p v-if="steps === 'take'">Position your face within the outlined area,click the button and the image will be saved as your profile picture!</p><p v-if="steps === 'save'">Happy with your picture? If not, you can take another one.</p><div class="video-container"><videoid="video"preloadautoplayloopmutedwidth="295"height="345":style="reverse ? 'transform:rotateY(180deg);' : ''"></video><canvas id="canvas" width="295" height="345"></canvas><canvas id="shortCut" v-show="false"></canvas><img :src="imgSrc" alt="" v-show="steps === 'save'" /><i @click="reverseVideo" v-show="steps==='take'"><svg-icon iconClass="icon-camera" class="icon-camera" /></i></div><div class="btns"><div class="add-num w300" @click="start" v-if="steps === 'open'">TURN CAMERA ON</div><div class="add-num w300" @click="getPhoto" v-if="steps === 'take'">SAVE THE IMAGE</div><div class="retake-btn" @click="openVideo" v-if="steps === 'save'">RETAKE</div><div class="add-num" @click="keepImg" v-if="steps === 'save'">USE PICTURE</div><p class="tips" v-if="steps === 'take'">(To take a profile picture your camera must remain on)</p><div class="imgs" v-show="false"><canvasid="canvas1"width="295"height="345"v-show="steps === 'save'"></canvas><p>save images</p><div id="img"></div></div></div></div></el-dialog>
</template>
<script>
import './tracking-min.js'
import './face-min.js'
import { individualPhoto } from '@modules/kyc/api/system/system'
import debounce from 'lodash/debounce'
export default {name: 'testTracking',model: {prop: 'formData',event: 'input',},props: {modalVisible: {type: Boolean,default: false,},formData: {type: Object,},option: {type: String,default: '',},},data() {return {saveArray: {},imgView: false,timer: null,steps: 'open',imageFile: {},faceloading: false,btnLoading: false,imgSrc: '',reverse: true,}},created() {this.start = debounce(this.start, 500)},methods: {// 打开摄像头start() {window.navigator.mediaDevices.getUserMedia({video: true,}).then((stream) => {this.openVideo()}).catch((err) => {this.$message.error('Cannot capture user camera')})},openVideo() {let that = thisthis.steps = 'take'let saveArray = {}let canvas = document.getElementById('canvas')let context = canvas.getContext('2d')let tracker = new tracking.ObjectTracker('face')tracker.setInitialScale(4)tracker.setStepSize(1.5)tracker.setEdgesDensity(0.1)this.imgSrc = ''this.trackerTask = tracking.track('#video', tracker, { camera: true })tracker.on('track', function (event) {context.clearRect(0, 0, canvas.width, canvas.height)event.data.forEach(function (rect) {if (that.reverse) {context.strokeRect(295 - rect.x - rect.width,rect.y,rect.width,rect.height)} else {context.strokeRect(rect.x, rect.y, rect.width, rect.height)}context.strokeStyle = '#fff'context.fillStyle = '#fff'saveArray.x = rect.xsaveArray.y = rect.ysaveArray.width = rect.widthsaveArray.height = rect.height})})},// 获取人像照片getPhoto() {let video = document.getElementById('video')let can = document.getElementById('shortCut')can.width = video.videoWidthcan.height = video.videoHeightlet context2 = can.getContext('2d')if (this.reverse) {context2.scale(-1, 1)context2.translate(-video.videoWidth, 0)}context2.drawImage(video, 0, 0, video.videoWidth, video.videoHeight)this.imgSrc = this.convertCanvasToImage(can).srcthis.steps = 'save'this.clearCanvas()// 停止侦测this.trackerTask.stop()// 关闭摄像头video.srcObject.getTracks()[0].stop()// this.imgView = true},// 截屏screenshot() {this.getPhoto()},// 将canvas转化为图片convertCanvasToImage(canvas) {let image = new Image()image.src = canvas.toDataURL('image/png')return image},//将base64转换为文件,dataurl为base64字符串,filename为文件名(必须带后缀名,如.jpg,.png)dataURLtoFile(dataurl, filename) {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 File([u8arr], filename, { type: mime })},// 保存图片keepImg() {// let can = document.getElementById('shortCut')// let context = can.getContext('2d')// let imgData = context.getImageData(0, 0, 294, 345)// let canvas1 = document.getElementById('canvas1')// let context1 = canvas1.getContext('2d')// context1.putImageData(imgData, 0, 0)// let img = document.getElementById('img')// let photoImg = document.createElement('img')// photoImg.src = this.convertCanvasToImage(canvas1).src// img.appendChild(photoImg)// this.imageFile = this.dataURLtoFile(//   this.convertCanvasToImage(canvas1).src,//   'person.jpg'// )this.imageFile = this.dataURLtoFile(this.imgSrc, 'person.jpg')let formData = new FormData()formData.append('file', this.imageFile)this.faceloading = trueindividualPhoto(formData, { isUpload: true }).then((res) => {if (res.success) {this.faceloading = falsethis.closeFace()this.$emit('close', 'success')this.$store.dispatch('GetBusinessUser').then((res) => {}).catch((err) => {})} else {this.openVideo()this.faceloading = falsethis.imgList = []}}).catch((err) => {this.openVideo()this.faceloading = falsethis.imgList = []})},clearCanvas() {let c = document.getElementById('canvas')let c1 = document.getElementById('canvas1')let cxt = c.getContext('2d')let cxt1 = c1.getContext('2d')cxt.clearRect(0, 0, 581, 436)cxt1.clearRect(0, 0, 581, 436)},closeFace() {try {this.steps = 'open'this.clearCanvas()// 关闭摄像头let video = document.getElementById('video')video.srcObject.getTracks()[0].stop()// 停止侦测this.trackerTask.stop()} catch (error) {}},close() {this.closeFace()this.$emit('close')},reverseVideo() {this.reverse = !this.reverse},},watch: {faceView(v) {if (v == false) {this.closeFace()}},},destroyed() {// clearInterval(this.timer)},
}
</script>
<style lang="scss">
@import './face.scss';
</style>

样式文件

点击查看样式代码
.face {p {text-align: center;font-size: 16px;color: #333333;}.big-title {margin-top: 36PX;font-size: 24PX;font-weight: 600;color: #030229;text-align: center;}.success {color: #47BFAF;}.fail {color: #C81223;}.video-container {background: url(~@/icons/img/face.png);background-size: cover;position: relative;width: 295PX;height: 345PX;border-radius: 4%;overflow: hidden;margin: 0 auto;margin-top: 34PX;img,video,#canvas,#shortCut,#canvas1 {position: absolute;}img {width: 100%;height: 100%;object-fit: cover;}video{object-fit: cover;}.icon-camera{position: absolute;font-size: 32px;bottom: 20px;right: 20px;cursor: pointer;}}.btns {padding: 10PX;text-align: center;margin-top: 6PX;.tips {font-size: 14PX;color: #666;margin-top: 16PX;line-height: 24PX;}}.imgs {padding: 10PX;p {font-size: 16PX;}}.add-num {display: inline-block;font-size: 16PX;padding: 12PX 14PX;margin-right: 4PX;border-radius: 4PX;color: #ffffff;background: #47BFAF;cursor: pointer;}.retake-btn {width: 145PX;display: inline-block;font-size: 16PX;padding: 12PX 14PX;margin-right: 24PX;border-radius: 4PX;color: #828282;background: #E7E7E7;cursor: pointer;}.w300 {width: 300PX;}
}.face-dialog {.el-dialog__body {padding-top: 0;padding-bottom: 15px;}
}

【Vue】前端人脸识别框架 tracking.js 活体检测/拍照在 vue2 的使用相关推荐

  1. 人脸识别系统中的活体检测技术有哪些分类

    人脸识别系统在实际应用中会面对照片.视频.面具等道具攻击,为了这防止这些欺诈手段,在系统中应用到活体检测,检测识别的人员是否为活体,提高应用的安全性.由畅视智能与你分享应用到人脸识别系统中的活体检测技 ...

  2. 云栖大会人脸识别闸机【技术亮点篇6】--人脸识别闸机采用活体检测技术

    云栖大会人脸识别闸机[技术亮点篇6]–人脸识别闸机采用活体检测技术 云栖大会使用的人脸识别闸机采用了活体检测技术,而为云栖大会提供闸机硬件的艾力奋会展服务公司的人脸识别系统中,也采用了活体检测技术.活 ...

  3. 人脸识别 android p,虹软人脸识别 - faceId及IR活体检测的更新介绍

    虹软人脸识别 - faceId及IR活体检测的介绍 前几天虹软推出了 Android ArcFace 2.2版本的SDK,相比于2.1版本,2.2版本中的变化如下: VIDEO模式新增faceId(类 ...

  4. 人脸识别干货讲解:活体检测算法总结

    这些年,我们可以看到人脸识别在超市.高铁站.机场等场所的应用,大大提高了我们购物和出行的效率,但同时也带来了人脸识别的安全隐患,尤其是在金融支付领域.很多头部大厂都在争夺这方面的制高点,刷脸支付领域是 ...

  5. 虹软人脸识别WPF版本,含活体检测

    虹软人脸识别WPF版本,3.0类库,含活体检测 源码地址: https://gitee.com/dacaba/arcface-demo-csharp-wpf3 将对应appid和appkey替换App ...

  6. 虹软人脸识别 - faceId及IR活体检测的介绍

    前几天虹软推出了 Android ArcFace 2.2版本的SDK,相比于2.1版本,2.2版本中的变化如下: • VIDEO模式新增faceId(类似于这篇文章中提到的trackId) • 新增I ...

  7. php活体检测,人脸门禁系统中活体检测的必要性

    人脸识别技术日趋成熟,商业化应用愈加广泛.为防止恶意者伪造或窃取他人的人脸特征用于身份认证,人脸识别系统需具备活体检测功能,以判断提交的人脸特征是否来自有生命的真实个体. 人脸识别技术日趋成熟,商业化 ...

  8. vue 使用人脸识别_使用Vue.js和Kairos构建简单的人脸识别应用

    vue 使用人脸识别 Face Detection and Recognition have become an increasingly popular topic these days. It's ...

  9. SpringCloud+MySQL+Vue实现人脸识别智能考勤管理系统

    一.前言 学生的课堂考勤是高校教务管理工作中一项非常重要的内容.随着学生群体数与日俱增,部分高校采用了刷卡签到.指纹验证以及有约束性的人脸认证等考勤方式,但由于这些方式都存在显露的弊端,比如排队等候. ...

最新文章

  1. Research on NFT
  2. JZOJ 3870. 【NOIP2014八校联考第4场第1试10.19】单词检索(search)
  3. ValueError: do_handshake_on_connect should not be specified for non-blocking sockets
  4. 用C语言实现解析简单配置文件的小工具
  5. Redis---概述
  6. 【洛谷 - P1772 】[ZJOI2006]物流运输(dp)
  7. 一键离线下载python安装包:
  8. java vector 输出_5.7(java学习笔记)Vector、Enumeration
  9. 大屏监控系统实战(12)-10分钟投票增量曲线制作(一)
  10. 【华为云技术分享】程序员实用JDK小工具归纳
  11. 【英语学习】【医学】Unit 09 The Respiratory System
  12. Flutter图片处理之高斯模糊
  13. cs 61c学习总结
  14. 华为RH2288 V3安装Windows server/Linux详细教程
  15. python基础课程讲解基本语法常见运算符以及结构语句
  16. 【愚公系列】2023年06月 网络安全(交通银行杯)-木册木兰
  17. inlinehook 看这一篇
  18. 【Windows 安装JDK8】如何安装java JDK8
  19. vue在IE浏览器报Error in nextTick: InvalidCharacterError解决方案
  20. 原生JS实现小米轮播图和网易云轮播图

热门文章

  1. 操作系统实验(进程调度)
  2. ChatGPT指令大全(英文版)
  3. 博通wifi驱动详解(一)
  4. 基于组态王的水塔液位控制系统设计
  5. 精彩英语吵架100句
  6. Android面试题---JNI
  7. ajax请求超时解决方案
  8. 友善之臂mini6410开发板学习笔记
  9. linux对目录空间使用限制,Linux quotacheck命令使用详解:检查磁盘的使用空间和限制...
  10. 在ubuntu16.04上搭建samba文件共享服务器