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. java 反射遍历_java使用反射遍历类的字段
  2. 为什么Go没有三元运算符
  3. 建设网站需要的Bootstrap介绍与操作
  4. Windows下git安装及使用技巧
  5. 我的世界服务器自定义代码,《我的世界》服务器指令代码秘籍大全
  6. mybatis 之 parameterType=Map
  7. 查找 EXC_BAD_ACCESS 问题根源的方法
  8. JDK8高性能队列“Disruptor“
  9. 软考 数据库系统工程师
  10. 量子统计的正则分布和巨正则分布计算思路过程
  11. 使用ADF Faces 之二:数据可视化组件 Thematic Map
  12. 东芝和摩飞多功能锅到底哪一款值得拔草呢?本篇深度评测让你剁手不后悔;
  13. Teamspeak3集成要注意的问题
  14. 【C语言小题】分数求和
  15. 网关系统就该这么设计,万能通用,稳的一批!
  16. java/php/net/python学生社团管理系统设计
  17. POI java导出Excel设置自适应行高
  18. 数字化时代,全方位解读商业智能BI
  19. 10.13(129. 求根到叶子节点数字之和 130. 被围绕的区域)
  20. Idea中自动注释的缩进(避免添加注释自动到行首)

热门文章

  1. 大数据 memcache缓存序列化太慢策略
  2. Android百度地图和人人网简单的应用(获取路线,分享到人人)
  3. 为了忘却的记忆—大学生活
  4. 精灵图专用 快速定位网站
  5. Oracle安装时 [INS-32025] 所选安装与指定oracle主目录中已安装的软件冲突
  6. 线束导通测试仪使用说明书
  7. OpenCV入门系列2:图像叠加、填充和腐蚀
  8. 吃鸡专用计算机,死得不明不白 推荐你一台吃鸡专用显示器
  9. 2016年上海面试记
  10. 加密ENCODE或解密DECODE函数