vue3 基于faceapi.js实现人脸识别

先贴代码

<template><div class="app-container"><div>{{ title }}</div><div class="x-face-detect-modal"><video ref="video" autoplay :onCanplay="handleVideoCanPlay" /><canvas ref="canvas" width="{this.width}" height="{this.height}" /></div></div>
</template>
<script setup lang="ts">
import { ref, onMounted } from 'vue'
import { uploadFile } from '@/api/base' // 这里需要使用 图片对比接口
import { detectSingleFace, nets, matchDimensions, resizeResults, draw, SsdMobilenetv1Options, Box } from 'face-api.js'
const options = new SsdMobilenetv1Options({// 最小置信阈值// 默认值:0.5minConfidence: 0.5
})
const formId = 'x-face-detect-form'
const title = ref('人脸识别') //  初始化title
const canvas = ref('canvas') // 图像画布
const video = ref('video') // 视频元素
const stream = ref(null) // 当前流
const getUserMediaFail = ref(false) // 获取用户媒体失败
const boxObject = ref({ width: 100, height: 100 }) // 初始化box
const viewFinderBox = ref({topLeft: {x: 0,y: 0},topRight: {x: 0,y: 0},bottomLeft: {x: 0,y: 0},bottomRight: {x: 0,y: 0}
}) // 初始化viewFinderBox// 加载算法模型 文件存储在 public 文件夹下models文件夹。// 需要文件的话联系我
const init = async () => {await nets.ssdMobilenetv1.loadFromUri('/models')
}/** @name 调用摄像头 */
const getUserMedia = (success: NavigatorUserMediaSuccessCallback, error: NavigatorUserMediaErrorCallback) => {//优先使用前置摄像头(如果有的话):{ video: { facingMode: "user" } }//强制使用后置摄像头:{ video: { facingMode: { exact: "environment" } } }// video: {//    width: { min: 1024, ideal: 1280, max: 1920 },//    height: { min: 776, ideal: 720, max: 1080 }// }//ideal(应用最理想的)值const constraints = {video: {facingMode: 'user',width: { ideal: canvas.value.width },height: { ideal: canvas.value.height }}}if (navigator.mediaDevices.getUserMedia) {// 最新的标准APInavigator.mediaDevices.getUserMedia(constraints).then(success).catch(error)} else if (navigator.webkitGetUserMedia) {// webkit核心浏览器navigator.webkitGetUserMedia(constraints, success, error)} else if (navigator.mozGetUserMedia) {// firfox浏览器navigator.mozGetUserMedia(constraints, success, error)} else if (navigator.getUserMedia) {// 旧版APInavigator.getUserMedia(constraints, success, error)}
}
/** @name 初始化取景框 */
const initViewFinder = () => {if (!video.value) returnconst marginLeft = (video.value.width - boxObject.value.width) / 2const marginTop = (video.value.width - boxObject.value.height) / 2if (canvas.value) {canvas.value.width = video.value.widthcanvas.value.height = video.value.height}viewFinderBox.value = {topLeft: {x: marginLeft,y: marginTop},topRight: {x: marginLeft + boxObject.value.width,y: marginTop},bottomLeft: {x: marginLeft,y: marginTop + boxObject.value.height},bottomRight: {x: marginLeft + boxObject.value.width,y: marginTop + boxObject.value.height}}
}/** @name 绘制取景框 */
const drawViewFinder = () => {const context = canvas.value?.getContext('2d')const rectWith = 50if (!context) returncontext.clearRect(0, 0, canvas.value?.width || 0, canvas.value?.height || 0)const fontLeft = video.value ? (video.value.width - 200) / 2 : 200context.font = '20px Arial'context.fillText('请保持脸部在取景框内', fontLeft, 50)const keys = Object.keys(viewFinderBox.value)keys.forEach((key) => {const point = viewFinderBox.value[key]if (!point) returncontext.moveTo(point.x, point.y)switch (key) {case 'topLeft':context.lineTo(point.x + rectWith, point.y)context.moveTo(point.x, point.y)context.lineTo(point.x, point.y + rectWith)breakcase 'topRight':context.lineTo(point.x - rectWith, point.y)context.moveTo(point.x, point.y)context.lineTo(point.x, point.y + rectWith)breakcase 'bottomLeft':context.lineTo(point.x + rectWith, point.y)context.moveTo(point.x, point.y)context.lineTo(point.x, point.y - rectWith)breakcase 'bottomRight':context.lineTo(point.x - rectWith, point.y)context.moveTo(point.x, point.y)context.lineTo(point.x, point.y - rectWith)breakdefault:break}})context.lineWidth = 2context.strokeStyle = 'white'context.stroke()
}/** @name 截取快照 */
const cameraShoot = (video: HTMLVideoElement, startPoint: { x: number; y: number }, width: number, height: number) => {const canvas = document.createElement('canvas')canvas.width = video.videoWidthcanvas.height = video.videoHeightcanvas.getContext('2d')?.drawImage(video, startPoint.x - 40, startPoint.y - 40, width + 80, height + 80, 0, 0, canvas.width, canvas.height)return new Promise<Blob | null>((resolve) =>// eslint-disable-next-line no-promise-executor-returncanvas.toBlob(resolve, 'image/jpeg'))
}
// 画盒子
const drawBox = (box, label) => {if (!canvas.value) returnconst context = canvas.value.getContext('2d')context?.clearRect(box.x, box.y, box.width, box.height)const drawBox = new draw.DrawBox(box, {label: label})drawBox.draw(canvas.value)
}// 停止
const handleStopVideo = () => {if (stream.value) {stream.value.getTracks().forEach((track) => {track.stop()})}
}/** @name 人脸检测 */
const detectFace = async () => {// eslint-disable-next-line no-promise-executor-return//非常重要:防止卡死await new Promise((resolve) => requestAnimationFrame(resolve))//绘制取景框// drawViewFinder()if (!canvas.value || !video.value || !video.value.currentTime || video.value.paused || video.value.ended)return detectFace()// 检测图像中具有最高置信度得分的脸部const result = await detectSingleFace(video.value, options)if (!result) return detectFace()// 匹配尺寸const dims = matchDimensions(canvas.value, video.value, true)// 调整检测到的框的大小,以防显示的图像的大小与原始const resizedResult = resizeResults(result, dims)const box = resizedResult.box// 检测框是否在取景框内// if (!checkInViewFinder(box)) return detectFace()// drawViewFinder()// 将检测结果绘制到画布(此处不用,可以直接用来绘制检测到的人脸盒子)// draw.drawDetections(this.canvas, resizedResult.box);drawBox(box, '识别中')video.value.pause()// //截取人脸图片const image = await cameraShoot(video.value,resizedResult.box.topLeft,resizedResult.box.width,resizedResult.box.height)if (!image) {drawBox(box, '识别失败')await delay(1000)video.value.play()return detectFace()}let files = new window.File([image], '人脸头像.jpeg', {type: 'image/jpeg'})// 调用接口传入截取的人脸头像进行检测// const detectResult = await uploadFile({ file: files })    // 没有图片对比接口就暂时用 图片上传代理了// if (!detectResult) {//   drawBox(box, '识别失败')video.value.play()return detectFace()// }// handleStopVideo()
}
// onMounted
onMounted(() => {console.log('mounted', canvas.value, video.value)// 获取用户媒体流getUserMedia((streams) => {//后续用于停止视频流stream.value = streams//显示视频if (video.value) {video.value['srcObject'] = streams}},(error) => (getUserMediaFail.value = true))init()detectFace()
})
</script>
<style lang="scss">
.x-face-detect-modal {display: flex;flex-direction: column;align-items: center;justify-content: center;position: relative;transform: rotateY(180deg);// overflow: hidden;canvas {position: absolute;top: 0;}video {object-fit: fill;}
}
</style>

vue3 基于faceapi.js实现人脸识别相关推荐

  1. vue基于face-api.js实现人脸识别

    一.face-api.js Face-api.js 是一个 JavaScript API,是基于 tensorflow.js 核心 API 的人脸检测和人脸识别的浏览器实现.它实现了一系列的卷积神经网 ...

  2. java+js实现人脸识别-基于百度api

    java+js实现人脸识别-基于百度api 我的第一次分享 第一步-我们了解下实现的思路 代码部分:1.js代码 2.后台代码 3.如何使用百度大脑 4.如何使用 navigator.mediaDev ...

  3. 身份验证错误错误指定的句柄无效_基于 Web 端的人脸识别身份验证「实践」

    作者:沫沫 政采云前端团队 转发链接:https://mp.weixin.qq.com/s/fRDpXixnLIy9c0Uh2tMezQ 前言 近些年来,随着生物识别技术的逐渐成熟,基于深度学习的人脸 ...

  4. 基于 Web 端的人脸识别身份验证

    效果展示 人脸识别效果图 前言 近些年来,随着生物识别技术的逐渐成熟,基于深度学习的人脸识别技术取得了突破性进展,准确率显著提高.现阶段,人脸识别身份验证作为非常重要的身份验证方式,已被广泛的应用于诸 ...

  5. 《繁凡的论文精读》(一)CVPR 2019 基于决策的高效人脸识别黑盒对抗攻击(清华朱军)

    点我一文弄懂深度学习所有基础和各大主流研究方向! <繁凡的深度学习笔记>,包含深度学习基础和 TensorFlow2.0,PyTorch 详解,以及 CNN,RNN,GNN,AE,GAN, ...

  6. 第十九课.基于sklearn的SVM人脸识别

    目录 数据集 确定人脸的类别标记 划分训练集和测试集与训练 实验为基于sklearn的SVM人脸识别,使用 SVM 算法对戴眼镜的人脸和不戴眼镜的人脸进行分类,从而完成 识别戴眼镜的人脸 的任务:实验 ...

  7. 基于改进的RPCA人脸识别算法

    from:http://www.chinaaet.com/article/3000011311 基于改进的RPCA人脸识别算法 作者:首照宇,杨晓帆,莫建文 2015/11/15 18:04:00 摘 ...

  8. 基于稀疏表示的人脸识别 (SRC,LASRC,RASL,MRR)

    FROM:http://blog.csdn.net/loadstar_kun/article/details/39453839 1.  问题背景 信号的稀疏表示并不是新的东西.我们很早就一直在利用这一 ...

  9. 基于Python的开源人脸识别库:离线识别率高达99.38%

    基于Python的开源人脸识别库:离线识别率高达99.38% 2019年04月18日 18:13:18 AI终结者 阅读数 1233 项目地址:https://github.com/ageitgey/ ...

最新文章

  1. html中content属性,CSS3的content属性用法详解
  2. TOP命令 %Cpu(s)解读 CPU状态信息us,sy,ni,id,wa,hi,si,st含义
  3. SAP WM LT42创建TO,报错-No entry in Table 329S (NM1 B)-
  4. 阿里云(一)云存储OSS的命令行osscmd的安装和使用
  5. python刷题相关资料汇总(一)
  6. java web 定制化界面_实现javaWeb网页自定义出错界面
  7. 2021甘肃平凉高考成绩查询,甘肃省教育考试院:2021年甘肃高考查分入口、查分系统...
  8. curl查看swift状态命令_微服务之——docker高级命令
  9. 无法启动调试--未安装 Silverlight Developer 运行时。请安装一个匹配版本
  10. 创建微信订阅号全攻略
  11. MySQL auto_increment介绍及自增键断层的原因分析
  12. 信仰:生或者死——读海子、史铁生
  13. 使用SSH完成linux和windows之间的文件互传(linux端)
  14. 为什么火狐浏览器打开默认是hao123
  15. 照片批量重命名为拍摄日期
  16. java面试题:Redis常见面试题(实际面试有被问到)
  17. IntelliJ IDEA必装插件以及SpringBoot使用小技巧合集
  18. ESP32-FPV-Camera介绍和使用
  19. mrtrix3处理DTI数据代码——DWI数据进行概率追踪和纤维素追踪
  20. Proxmox VE 网络配置 NAT共享IP 端口映射iptables、brook

热门文章

  1. 为什么人往往只能看到自己愿意相信的真相
  2. 2021年高级消防设施操作员考前必背考点,考题及答案
  3. 计算机系统导论自考,天津2012年自考“计算机系统导论”课程考试大纲.doc
  4. vue2.x饿了吗实战总结
  5. 大数据金融行业企业应用几点思考
  6. 【转载】字符串匹配的KMP算法
  7. AngularJS学习之$q和promise介绍
  8. sakai的相关概念
  9. git pull 出现The following untracked working tree files would be overwritten by merge:bin/run.sh
  10. 获取RecyclerView的viewholder的几种方式