基于face-api.js和感知哈希的人脸相似度比对网页实现

前言

最近在探索前端人脸识别技术,发现face-api.js是一个很强大的库,可以在浏览器中直接运行人脸检测、特征提取等模型。结合感知哈希算法,可以快速实现人脸相似度比对。本文将详细解析一个我开发的轻量级演示页面:它支持上传两张图片,本地检测人脸,计算感知哈希相似度,并允许用户对结果进行点赞/点踩,所有统计数据通过后端API保存。适合对前端AI、Canvas操作、文件上传交互感兴趣的开发者参考。


一、项目概述

这是一个纯前端(含少量后端交互)的人脸比对演示工具。主要功能:

  • 加载face-api.js的SSD Mobilenet V1、人脸关键点、人脸识别模型。
  • 双栏图片上传(支持点击或拖拽),实时预览。
  • 人脸检测并绘制边界框和关键点。
  • 点击“运行人脸比对”按钮,基于感知哈希算法计算两张图片的相似度。
  • 展示比对结果(相似度百分比、汉明距离、结论)。
  • 用户可以对每次比对结果进行“点赞”或“点踩”,每完成一次对比,对比次数+1。
  • 所有计数(对比次数、点赞数、点踩数)通过后端API同步,避免刷新丢失。

界面采用毛玻璃设计(backdrop-filter),整体风格清爽。


二、技术栈

  • HTML5/CSS3:结构、样式,毛玻璃效果使用 backdrop-filter: blur()。
  • JavaScript (ES6):逻辑交互。
  • face-api.js:人脸检测、关键点定位、特征描述符(用于绘制,实际相似度计算未使用其识别网络,仅用于检测和绘图)。
  • Canvas API:绘制人脸框、缩放图像、灰度转换等。
  • 感知哈希(pHash)算法:自行实现,用于计算图像相似度。
  • Fetch API:与后端交互,获取/更新统计数据。

后端接口(未开源,但逻辑简单):

  • GET /api/get_stats:返回当前统计 { compareCount, likeCount, dislikeCount }
  • POST /api/update_stats:接收 { type: 'compare'|'like'|'dislike' },更新对应计数并返回最新统计。

三、界面设计要点

页面采用双栏布局,左右对称,分别对应图片A和B。主要区域包括:

  1. 模型状态栏:显示模型加载进度,用圆点颜色表示状态(黄色加载中,绿色完成,红色失败)。
  2. 反馈面板
  • 当前完成对比次数(只读输入框)。
  • 点赞/点踩按钮,显示当前计数,并限制每次对比只能评价一次。
  1. 图片上传面板
  • 每个面板包含上传按钮、清空按钮、预览容器。
  • 支持点击上传和拖拽上传(通过监听drag事件)。
  • 预览容器内会动态绘制检测到的人脸框和关键点。
  1. 比对按钮:只有模型加载完成后才启用。
  2. 结果输出区:只读文本域,显示详细的比对结果和算法说明。

所有容器都有半透明毛玻璃效果,背景为浅灰渐变,营造科技感。


四、核心功能实现详解

1. 模型加载

使用face-api.js的load方法从CDN加载权重文件。顺序加载:ssdMobilenetv1(检测)、faceLandmark68Net(关键点)、faceRecognitionNet(识别,实际未使用但加载以备后续)。加载成功后,按钮可用,并调用loadStats()从后端获取初始统计数据。

await faceapi.nets.ssdMobilenetv1.load(CONFIG.MODEL_BASE_URL);
await faceapi.nets.faceLandmark68Net.load(CONFIG.MODEL_BASE_URL);
await faceapi.nets.faceRecognitionNet.load(CONFIG.MODEL_BASE_URL);

2. 图片上传与预览

为两个文件输入框绑定change事件,读取文件后用FileReader生成DataURL,设置给对应的<img>元素。同时清空之前可能绘制的人脸框Canvas。

拖拽上传:在预览容器上监听dragoverdragleavedrop事件,将文件对象取出并调用相同的处理函数。

3. 人脸检测与绘制

drawFaceBoxes函数接收图片元素和容器ID,完成以下工作:

  • 移除旧Canvas。
  • 创建新的Canvas覆盖在图片上,并设置样式为绝对定位。
  • 调用faceapi.detectAllFaces(img).withFaceLandmarks().withFaceDescriptors()获取检测结果。
  • 使用faceapi.matchDimensions调整Canvas尺寸,然后用faceapi.draw.drawDetectionsfaceapi.draw.drawFaceLandmarks绘制边界框和关键点。
  • 返回检测结果数组,供后续计数。

注意:此处的绘制是在单独的Canvas上,不影响原始图片。

4. 感知哈希算法

感知哈希(pHash)是一种计算图像相似度的经典算法,流程:

  • 将图像转为灰度图(getGrayImageData遍历像素计算灰度值)。
  • 缩放至8×8像素(resizeGrayData使用最近邻采样)。
  • 计算64个像素的均值。
  • 生成64位二进制哈希:每个像素值大于均值为1,否则为0。
  • 汉明距离:两个哈希值不同位的个数。
  • 相似度转换:距离越大越不相似,最大距离64,相似度 = 100 – (distance/64)*100。

此算法抗干扰能力强,对缩放、亮度变化有一定鲁棒性,但严格来说不适合作为人脸识别(可能将不同人误判为相似),但作为轻量演示足够。

5. 比对逻辑

compareFaces函数为入口:

  • 禁用按钮,显示计算中。
  • 调用drawFaceBoxes获取检测结果并绘制。
  • 检查两张图是否都检测到人脸,若无则报错。
  • 分别生成两张图片的感知哈希。
  • 计算汉明距离和相似度。
  • 构造结果文本(包含相似度、距离、人脸数、结论、算法说明)。
  • 提交compare统计(submitStats('compare')),并重置投票状态,允许对本次结果进行评价。
  • 异常处理,显示错误提示。

6. 点赞/点踩

  • 点赞和点踩按钮分别绑定点击事件。
  • 检查是否已经评价过本次对比(hasVotedForCurrentCompare标志)。
  • 调用submitStats传入'like''dislike'
  • 后端返回最新统计后更新UI。
  • 如果后端请求失败,本地计数增加,保证用户体验(防崩溃)。

7. 后端交互

使用Fetch API:

  • loadStats() 在页面加载时调用,填充计数。
  • submitStats(type) 发送POST请求,并在请求成功后更新UI;失败时本地兜底。

后端API预期返回JSON格式:{ compareCount, likeCount, dislikeCount }


五、关键代码片段解析

灰度图像数据获取

function getGrayImageData(img) {
    const canvas = document.createElement('canvas');
    const ctx = canvas.getContext('2d');
    canvas.width = img.naturalWidth;
    canvas.height = img.naturalHeight;
    ctx.drawImage(img, 0, 0);
    const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
    const grayData = [];
    for (let i = 0; i < imageData.data.length; i += 4) {
        const gray = Math.floor((imageData.data[i] + imageData.data[i+1] + imageData.data[i+2]) / 3);
        grayData.push(gray);
    }
    return { data: grayData, width: canvas.width, height: canvas.height };
}

感知哈希生成

function generatePHash(img) {
    const gray = getGrayImageData(img);
    const smallSize = 8;
    const scaled = resizeGrayData(gray, smallSize, smallSize);
    const avg = scaled.data.reduce((sum, val) => sum + val, 0) / scaled.data.length;
    let hash = '';
    for (const val of scaled.data) {
        hash += val > avg ? '1' : '0';
    }
    return hash;
}

提交统计数据(带容错)

async function submitStats(type) {
    try {
        const res = await fetch(CONFIG.API_BASE + '/update_stats', {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({ type })
        });
        const data = await res.json();
        stats.compareCount = data.compareCount ?? stats.compareCount;
        stats.likeCount = data.likeCount ?? stats.likeCount;
        stats.dislikeCount = data.dislikeCount ?? stats.dislikeCount;
        updateUI();
    } catch (err) {
        console.error('更新失败', err);
        // 本地兜底
        if(type === 'like') stats.likeCount++;
        if(type === 'dislike') stats.dislikeCount++;
        if(type === 'compare') stats.compareCount++;
        updateUI();
    }
}

六、用户体验细节

  • 每次上传新图片时,自动清空之前的结果,并移除人脸框Canvas。
  • 清空按钮释放Blob URL,避免内存泄漏。
  • 拖拽上传时会有边框高亮反馈。
  • 模型加载失败时,按钮保持禁用,并提示用户刷新。
  • 点赞/点踩限制:必须进行过至少一次对比,且每次对比只能评价一次,防止刷票。

七、可扩展性与改进方向

  1. 使用更精准的算法:目前基于pHash,可以替换为face-api.js的人脸识别描述符,计算欧氏距离,准确度更高。
  2. 增加多张人脸选择:如果一张图有多张人脸,可以让用户选择比对哪一对。
  3. 后端持久化:当前后端仅内存存储,可接入数据库,记录历史评价。
  4. 移动端适配:虽然已有媒体查询,但拖拽在移动端可能不友好,可增加备选方案。
  5. 国际化:界面文字可配置多语言。
  6. 批量测试:允许上传文件夹,批量计算相似度。

八、总结

这个项目展示了如何结合现代前端技术和传统图像处理算法,快速搭建一个有趣的人脸比对演示工具。通过face-api.js简化了人脸检测的复杂性,自行实现的pHash算法避免了依赖外部API,保证了隐私和速度。同时,点赞/点踩功能增加了互动性,后端交互让数据得以持久化。

如果你对前端AI应用感兴趣,不妨从这个项目入手,尝试替换算法或增加新特性。完整的代码已附在文中(用户提供的HTML),你可以直接复制运行体验。

欢迎在评论区交流讨论!

配图建议:

  • 网页整体截图,标注各区域功能
  • 人脸检测绘制效果图(带框和关键点)
  • 感知哈希流程图(原图→灰度→8×8→哈希)
  • 后端交互时序图

分类标签: #人脸识别 #face-api #JavaScript #感知哈希 #前端开发

基于face-api.js和感知哈希的人脸相似度比对网页实现
学习方法

思维模型工具箱:提升认知的九个核心框架

2026-3-13 16:19:21

哲学学习方法

悖论全解析:当逻辑遇上自指,思维如何陷入困境?

2026-3-13 16:35:41

16 条回复 A文章作者 M管理员
  1. RSTDD

    这网页真实用,人脸识别又快又准,比对起来特别方便!

  2. RSTDD

    这个网页太实用了,人脸比对又快又准,推荐给大家!

  3. RSTDD

    这个网页实现太实用了,人脸识别又快又准,体验感满分!

  4. RSTDD

    这网页真方便,人脸识别比对超准,推荐给需要的人!

  5. RSTDD

    这个网页实现很实用,人脸比对准确又方便,适合需要快速识别的场景!

  6. RSTDD

    这个网页实现挺有意思的,用起来也方便,人脸比对很准确!

  7. RSTDD

    这个网页实现太棒了,人脸识别又快又准,用起来超方便!

  8. RSTDD

    这个网页实用又方便,人脸比对效果不错,推荐给大家!

  9. RSTDD

    这个网页实现太棒了!用face-api.js和感知哈希做人脸比对,技术很实用,体验也很好!

  10. RSTDD

    这个网页实现挺实用的,用起来也方便,人脸比对效果不错!

  11. RSTDD

    这个网页实现很实用,人脸识别和哈希比对结合得不错,体验流畅!

  12. RSTDD

    这个网页实用又方便,人脸比对效果很准,推荐给大家!

  13. RSTDD

    这个网页太实用了,人脸识别又准又方便,推荐给大家!

  14. RSTDD

    这个网页实现很实用,人脸比对功能准确又方便,适合日常使用。

  15. RSTDD

    这个网页实现很实用,人脸识别和哈希比对结合得恰到好处,方便又高效!

  16. 李恩星

    我不是机器人

个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索