使用effet.js 拿到特征值就行人脸比对

475 阅读3分钟

使用effet.js 拿到特征值就行人脸比对

前言

effet.js 是一款轻量级的人脸样式框架,专注于为网页呈现生动的面部动画效果。它基于 facemesh.js 进行二次开发,提供简单易用的 API,并支持获取 468 个精确的人脸特征点。

1.提取特征值

我们已经人脸添加为示例,拿到468点位

代码示例:

<template>
  <div>
    <div ref="faceVueTest" id="faceId" ></div>
    <el-button @click="startFace">开启人脸</el-button>
    <el-button @click="restartFace">重启人脸</el-button>
    <el-button @click="closeFace">关闭人脸</el-button>
  </div>
  </template>
   
  <script>
  // $faceEffet 对象是在main.js 注册好的全局对象
  export default {
    name: "index",
    data(){
      return {
      }
    },
    beforeDestroy(){
      if (this.$faceEffet){
        this.$faceEffet.close();
      }
    },
    methods:{
      startFace(){
          // 人脸容器的初始化
        this.$faceEffet.init({
          el:this.$refs.faceVueTest, // 直接传入html元素 也可以直接传入字符 'faceId'
          type:'addFace', 
          callBack:this.callBack // 阶段回调函数,会打印每个执行步骤,一般是在这个方法调用后端接口
        })
      },
      callBack(data){
          // 验证过程的回调打印
        console.log(data)
      },
      restartFace(){
          // 重启人脸容器
        this.$faceEffet.restart()
      },
      closeFace(){
          // 关闭人脸容器
        this.$faceEffet.close();
      }
    }
  }
  </script> 

其中features是我们人脸的特征点

callBack 打印的结果:

image-20241125110424971

2.保存特征值

我们可以将features数组数据存入到我们的数据

将某个人的人脸特征值(整个 features 数组)保存为文件或数据库条目,例如 JSON 格式:

{
  "id": "person_1",
  "features": [
    [x1, y1, z1],
    [x2, y2, z2],
    ...
    [x468, y468, z468]
  ]
}

可以使用 JSON 文件或数据库存储这些特征值,供后续比对使用。

3.计算相似度

当需要比对两个人脸时,核心是计算两个 features 特征数组的相似度。通常采用以下方法:

(1)欧几里得距离

计算两个 features 中每个关键点的欧几里得距离,然后将这些距离的平均值作为整体相似度:

公式:

image-20241125110727389

代码示例:

function calculateDistance(point1, point2) {
    return Math.sqrt(
        Math.pow(point1[0] - point2[0], 2) +
        Math.pow(point1[1] - point2[1], 2) +
        Math.pow(point1[2] - point2[2], 2)
    );
}

function compareFaces(features1, features2) {
    let totalDistance = 0;
    for (let i = 0; i < features1.length; i++) {
        totalDistance += calculateDistance(features1[i], features2[i]);
    }
    return totalDistance / features1.length; // 返回平均距离
}

距离越小,相似度越高。如果平均距离低于某个阈值(例如 0.05),就可以认为两张脸相似。

(2)余弦相似度

用余弦相似度计算两组向量的相似性,适合特征值向量化后使用。

公式:

image-20241125110806217

代码示例:

function calculateCosineSimilarity(features1, features2) {
    let dotProduct = 0;
    let normA = 0;
    let normB = 0;

    for (let i = 0; i < features1.length; i++) {
        dotProduct += features1[i][0] * features2[i][0] + 
                      features1[i][1] * features2[i][1] + 
                      features1[i][2] * features2[i][2];
        normA += Math.pow(features1[i][0], 2) + Math.pow(features1[i][1], 2) + Math.pow(features1[i][2], 2);
        normB += Math.pow(features2[i][0], 2) + Math.pow(features2[i][1], 2) + Math.pow(features2[i][2], 2);
    }

    normA = Math.sqrt(normA);
    normB = Math.sqrt(normB);

    return dotProduct / (normA * normB); // 返回相似度,范围在 -1 到 1
}

结果越接近 1,表示两张脸越相似。

4.比对过程

完整流程如下:

  1. 从数据库中加载保存的特征值。
  2. 用 effet.js 提取待比对人脸的 features
  3. 使用上述算法(欧几里得距离或余弦相似度)进行比对。
  4. 根据相似度或距离结果判断是否为同一张脸。

5.优化和注意事项

  • 归一化处理:由于人脸的比例可能不同(例如距离摄像头远近),建议对关键点进行归一化处理,将特征值标准化到 [0, 1] 范围。

​ 示例:

function normalize(features) {
    const min = Math.min(...features.flat());
    const max = Math.max(...features.flat());
    return features.map(([x, y, z]) => [(x - min) / (max - min), (y - min) / (max - min), (z - min) / (max - min)]);
}

  • 检测精度:在低光照或部分遮挡的情况下,检测精度可能降低,可以结合多个检测框架提升准确率。

更多资源