faceApi-人脸识别和人脸检测

需求:浏览器通过模型检测前方是否有人(距离和正脸),检测到之后拍照随机保存一帧

实现步骤:

  1. 获取浏览器的摄像头权限
  2. 创建video标签并通过video标签展示摄像头影像
  3. 创建canvas标签并通过canvas标签绘制摄像头影像并展示
  4. 将canvas的当前帧转成图片展示保存

pnpm install @vladmandic/face-api 下载依赖

pnpm install @vladmandic/face-api

下载model模型

将下载的model模型放到项目的public文件中 如下图

创建video和canvas标签

复制代码
      <video ref="videoRef" style="display: none"></video>
      <template v-if="!picture || picture == ''">
        <canvas ref="canvasRef" width="400" height="400"></canvas>
      </template>
      <template v-else>
        <img ref="image" :src="picture" alt="" />
      </template>
    </div>
.video 复制代码
  width: 400px;
  height: 400px;
  border-radius: 50%;
  overflow: hidden;
  position: fixed;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
}

.video_box {
  position: fixed;
  width: 400px;
  height: 400px;
  border-radius: 50%;
  overflow: hidden;
}

@keyframes moveToTopLeft {
  0% {
    right: 50%;
    top: 50%;
    transform: translate(-50%, -50%);
  }

  100% {
    right: -68px;
    top: -68px;
    transform: scale(0.5);
  }
}

.video_box {
  animation: moveToTopLeft 2s ease forwards;
}

介绍分析

video 类选择器 让视频流居中

picture变量 判断是否转成照片

video_box视频流的某一帧转成照片后 动态移动到屏幕右上角

主要逻辑代码 主要逻辑代码 主要逻辑代码!!!

import 复制代码
import * as faceApi from '@vladmandic/face-api'

const videoRef = ref()
const options = ref(null)
const canvasRef = ref(null)
let timeout = null
// 初始化人脸识别
const init = async () => {
    await faceApi.nets.ssdMobilenetv1.loadFromUri("/models") //人脸检测
    // await faceApi.nets.tinyFaceDetector.loadFromUri("/models") //人脸检测  人和摄像头距离打开
    await faceApi.nets.faceLandmark68Net.loadFromUri("/models") //特征检测 人和摄像头距离必须打开
    // await faceApi.nets.faceRecognitionNet.loadFromUri("/models") //识别人脸 
    // await faceApi.nets.faceExpressionNet.loadFromUri("/models") //识别表情,开心,沮丧,普通
    // await faceApi.loadFaceLandmarkModel("/models");

    options.value = new faceApi.SsdMobilenetv1Options({
        minConfidence: 0.5, // 0.1 ~ 0.9
    });
    await cameraOptions()
}

// 打开摄像头
const cameraOptions = async() => {
    let constraints = {
      video: true
    }
    // 如果不是通过loacalhost或者通过https访问会将报错捕获并提示
    try {
      if (navigator.mediaDevices) {
        navigator.mediaDevices.getUserMedia(constraints).then((MediaStream) => {
          // 返回参数
          videoRef.value.srcObject = MediaStream;
          videoRef.value.play();
          recognizeFace()
        }).catch((error) => {
          console.log(error);
        });
      } else {
        console.log('浏览器不支持开启摄像头,请更换浏览器')
      }
  
    } catch (err) {
      console.log('非https访问')
    }
  }

//   检测人脸
const recognizeFace = async () => {
    if (videoRef.value.paused) return clearTimeout(timeout);
    canvasRef.value.getContext('2d', { willReadFrequently: true }).drawImage(videoRef.value, 0, 0, 400, 400);
    // 直接检测人脸  灵敏较高
    // const results = await new faceApi.DetectAllFacesTask(canvasRef.value, options.value).withFaceLandmarks();
    // if (results.length > 0) {
    //   photoShoot()
    // }
    // 计算人与摄像头距离和是否正脸
    const results = await new faceApi.detectSingleFace(canvasRef.value, options.value).withFaceLandmarks()
    if (results) {
      // 计算距离
      const { positions } = results.landmarks;
      const leftPoint = positions[0];
      const rightPoint = positions[16];
      // length 可以代替距离的判断   距离越近  length值越大
      const length = Math.sqrt(
          Math.pow(leftPoint.x - rightPoint.x, 2) +
            Math.pow(leftPoint.y - rightPoint.y, 2),
      );
        // 计算是否正脸
      const { roll, pitch, yaw } = results.angle
      //roll水平角度 pitch上下角度 yaw 扭头角度
      console.log(roll, pitch, yaw, length)
      if (roll >= -10 && roll <= 10 && pitch >= -10 && pitch <= 10 && yaw>= -20 && yaw <= 20 && length >= 90 && length <= 110) {
        
        photoShoot()

      }

    }
    

    timeout = setTimeout(() => {
      return recognizeFace()
    }, 0)
  }
  const picture = ref(null)
  const photoShoot = () => {
    // 拿到图片的base64
    let canvas = canvasRef.value.toDataURL("image/png");
    // 停止摄像头成像
    videoRef.value.srcObject.getTracks()[0].stop()
    videoRef.value.pause()
    if(canvas) {
        // 拍照将base64转为file流文件
        let blob = dataURLtoBlob(canvas);
        let file = blobToFile(blob, "imgName");
        // 将blob图片转化路径图片
        picture.value = window.URL.createObjectURL(file)

    } else {
        console.log('canvas生成失败')
    }
}
/**
         * 将图片转为blob格式
         * dataurl 拿到的base64的数据
         */
const 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 文件名字
*/
const blobToFile = (theBlob, fileName) => {
  theBlob.lastModifiedDate = new Date().toLocaleDateString();
  theBlob.name = fileName;
  return theBlob;
}

// 判断是否在区间
const isInRange = (number, start, end) => {
  return number >= start && number <= end
}
export { init, videoRef, canvasRef, timeout, picture }
相关推荐
爱技术的小伙子几秒前
【ChatGPT】 让ChatGPT模拟客户服务对话与应答策略
人工智能·chatgpt
OptimaAI28 分钟前
【 LLM论文日更|检索增强:大型语言模型是强大的零样本检索器 】
人工智能·深度学习·语言模型·自然语言处理·nlp
谢眠33 分钟前
机器学习day4-朴素贝叶斯分类和决策树
人工智能·机器学习
HelpHelp同学37 分钟前
教育机构内部知识库:教学资源的集中管理与优化
人工智能·知识库软件·搭建知识库·知识管理工具
深度学习lover43 分钟前
<项目代码>YOLOv8 番茄识别<目标检测>
人工智能·python·yolo·目标检测·计算机视觉·番茄识别
IT古董44 分钟前
【机器学习】机器学习中用到的高等数学知识-1.线性代数 (Linear Algebra)
人工智能·python·线性代数·机器学习
飞腾开发者1 小时前
飞腾平台Arm NN软件栈安装使用指南
linux·运维·人工智能·机器学习·计算机视觉
Watermelo6171 小时前
通过MongoDB Atlas 实现语义搜索与 RAG——迈向AI的搜索机制
人工智能·深度学习·神经网络·mongodb·机器学习·自然语言处理·数据挖掘
AI算法-图哥2 小时前
pytorch量化训练
人工智能·pytorch·深度学习·文生图·模型压缩·量化
大山同学2 小时前
DPGO:异步和并行分布式位姿图优化 2020 RA-L best paper
人工智能·分布式·语言模型·去中心化·slam·感知定位