face-api.js多人识别实战教程
欢迎各位小伙伴来到golang学习网,相聚于此都是缘哈哈哈!今天我给大家带来《face-api.js 多人脸识别实战教程》,这篇文章主要讲到等等知识,如果你对文章相关的知识非常感兴趣或者正在自学,都可以关注我,我会持续更新相关文章!当然,有什么建议也欢迎在评论留言提出!一起学习!

本教程详细阐述了如何使用 face-api.js 在浏览器环境中实现稳定且准确的多目标人脸识别。针对常见的多人脸误识别问题,文章深入分析了 `LabeledFaceDescriptors` 和 `FaceMatcher` 的正确构建与使用方法,确保每个已知人脸都能被独立且准确地识别,并提供了完整的 Svelte 代码示例及优化建议。
在现代 Web 应用中集成人脸识别功能,face-api.js 是一个强大且易于使用的 JavaScript 库。然而,开发者在使用过程中常会遇到一个挑战:当系统需要识别多个已知人脸时,可能会出现所有检测到的人脸都被错误地标记为同一个人的情况,即使“未知”人脸能够被正确识别。本文将深入探讨这一问题,并提供一个健壮的解决方案,确保 face-api.js 能够准确地区分和识别画面中的多个人脸。
理解问题:单人识别与多目标误识别
问题的核心在于 face-api.js 中 LabeledFaceDescriptors 的构建方式。原始代码可能存在以下逻辑缺陷:
- 共享描述符数组: 在为每个已知客户(customer)生成 LabeledFaceDescriptors 时,可能错误地使用了同一个全局数组来存储所有客户的人脸描述符(descriptor)。
- FaceMatcher 初始化: 如果 FaceMatcher 使用了包含混合描述符的共享数组进行初始化,它将无法区分不同的人脸,因为它认为所有描述符都属于同一个“身份池”。
这导致的结果是,当摄像头前出现多个人脸时,face-api.js 虽然能检测到所有面部,但在进行匹配时,由于内部描述符的混淆,它会倾向于将所有已知面孔都识别为第一个或最接近的匹配项,从而出现“只识别一个人”的假象。
核心概念回顾:face-api.js 中的关键组件
要解决上述问题,我们需要正确理解 face-api.js 中的几个核心概念:
1. 人脸检测与特征提取
- detectSingleFace() / detectAllFaces(): 用于从图像或视频中检测人脸。
- .withFaceLandmarks(): 提取人脸关键点,如眼睛、鼻子、嘴巴的位置。
- .withFaceDescriptor(): 基于人脸关键点生成一个高维向量(人脸描述符),该描述符是人脸的唯一数字指纹,用于后续的匹配。
2. LabeledFaceDescriptors:标签化人脸描述符
这是解决多目标识别问题的关键。faceapi.LabeledFaceDescriptors 类用于将一个特定的人脸描述符数组与一个唯一的标签(如人名)关联起来。它的构造函数是 new faceapi.LabeledFaceDescriptors(label: string, descriptors: Float32Array[])。
- label: 标识这个人的名称。
- descriptors: 一个包含该人物多个人脸描述符的数组。通常,为了提高识别鲁棒性,我们会为同一个人提供多张不同角度或表情的照片,并从中提取多个描述符。
3. FaceMatcher:人脸匹配器
faceapi.FaceMatcher 类用于将一个未知人脸的描述符与一组已知的 LabeledFaceDescriptors 进行比较,找出最佳匹配。
- 初始化: new faceapi.FaceMatcher(labeledDescriptors: LabeledFaceDescriptors[], distanceThreshold?: number)。它接收一个 LabeledFaceDescriptors 对象的数组,其中每个对象代表一个已知人物。
- 匹配: faceMatcher.findBestMatch(queryDescriptor: Float32Array)。它会计算查询描述符与所有已知描述符之间的距离,并返回距离最近的匹配项(FaceMatch 对象),包含匹配的标签和距离。distanceThreshold 用于判断匹配的严格程度,距离越小表示相似度越高。
解决方案:构建准确的 LabeledFaceDescriptors
解决多目标误识别问题的核心在于确保每个已知人物都拥有独立且正确关联的 LabeledFaceDescriptors 对象。
错误示例分析
在原始代码中,getLabeledFaceDescriptions 函数可能将所有客户的描述符都推送到一个名为 descriptions 的全局数组中。随后,在 map 函数内部,针对每个 customer 调用 new faceapi.LabeledFaceDescriptors(customer.name, descriptions)。此时,descriptions 数组已经包含了所有(或部分)客户的描述符,导致每个 LabeledFaceDescriptors 对象都引用了同一个混淆的描述符集合,从而使 FaceMatcher 无法区分不同的人。
正确实现方式
我们应该为每个客户创建一个独立的描述符数组,并用该数组来构建其对应的 LabeledFaceDescriptors 对象。
// 假设 $customers 和 $baseURL 是 Svelte store 或可访问的变量
// $customers 结构示例: [{ name: 'Customer A', image_url: '/path/to/a.jpg' }, ...]
async function getLabeledFaceDescriptors(customers, baseURL) {
const labeledDescriptors = await Promise.all(
customers.map(async (customer) => {
if (!customer.image_url) {
console.warn(`Customer ${customer.name} has no image_url, skipping.`);
return null;
}
const descriptorsForThisCustomer = []; // 为每个客户创建一个独立的描述符数组
// 可以根据需要从多张图片或同一图片的不同检测中获取多个描述符
// 这里假设每位客户有一张图片,从中提取一个描述符
try {
const img = await faceapi.fetchImage(baseURL + customer.image_url);
const detection = await faceapi
.detectSingleFace(img)
.withFaceLandmarks()
.withFaceDescriptor();
if (detection && detection.descriptor) {
descriptorsForThisCustomer.push(detection.descriptor);
} else {
console.warn(`No face detected for ${customer.name} from image: ${baseURL + customer.image_url}`);
}
} catch (error) {
console.error(`Error processing image for ${customer.name}:`, error);
return null;
}
if (descriptorsForThisCustomer.length > 0) {
// 使用该客户专属的描述符数组创建 LabeledFaceDescriptors
return new faceapi.LabeledFaceDescriptors(
customer.name,
descriptorsForThisCustomer
);
}
return null;
})
);
// 过滤掉任何未能成功获取描述符的客户
return labeledDescriptors.filter((d) => d !== null);
}实现多目标人脸识别流程
以下是一个完整的 Svelte 组件示例,展示了如何在浏览器中实现多目标人脸识别。
1. 模型加载
在开始人脸识别之前,需要加载 face-api.js 所需的模型。
// Svelte script context
import { onMount, onDestroy } from 'svelte';
import * as faceapi from 'face-api.js';
let video;
let detections;
let width = 640; // 调整为适合您的视频流尺寸
let height = 480;
let canvas, ctx;
let container;
let faceMatcher; // 全局 FaceMatcher 实例
// 假设 $customers 和 $baseURL 是 Svelte store,需要在实际应用中注入
// 例如: import { customers, baseURL } from './stores';
// 或者通过 props 传递
export let customers = []; // 假设通过 props 传递客户数据
export let baseURL = ''; // 假设通过 props 传递基础 URL
const detectionOptions = {
withLandmarks: true,
withDescriptors: true,
minConfidence: 0.5,
MODEL_URLS: {
Mobilenetv1Model:
"https://raw.githubusercontent.com/ml5js/ml5-data-and-models/main/models/faceapi/ssd_mobilenetv1_model-weights_manifest.json",
FaceLandmarkModel:
"https://raw.githubusercontent.com/ml5js/ml5-data-and-models/main/models/faceapi/face_landmark_68_model-weights_manifest.json",
FaceRecognitionModel:
"https://raw.githubusercontent.com/ml5js/ml5-data-and-models/main/models/faceapi/face_recognition_model-weights_manifest.json",
},
};
onDestroy(() => {
if (video) {
video.pause();
if (video.srcObject) {
video.srcObject.getTracks().forEach(track => track.stop());
}
video.srcObject = null;
video.remove();
}
if (canvas) {
canvas.remove();
}
});
onMount(() => {
initFaceRecognition();
});
// ... (getLabeledFaceDescriptors 函数如上所示) ...
async function initFaceRecognition() {
// 获取视频流
video = await getVideo();
// 创建画布
canvas = createCanvas(width, height);
ctx = canvas.getContext('2d');
// 加载模型
await Promise.all([
faceapi.nets.ssdMobilenetv1.loadFromUri(detectionOptions.MODEL_URLS.Mobilenetv1Model),
faceapi.nets.faceRecognitionNet.loadFromUri(detectionOptions.MODEL_URLS.FaceRecognitionModel),
faceapi.nets.faceLandmark68Net.loadFromUri(detectionOptions.MODEL_URLS.FaceLandmarkModel),文中关于的知识介绍,希望对你的学习有所帮助!若是受益匪浅,那就动动鼠标收藏这篇《face-api.js多人识别实战教程》文章吧,也可关注golang学习网公众号了解相关技术文章。
咸鱼平台官网入口及登录指南
- 上一篇
- 咸鱼平台官网入口及登录指南
- 下一篇
- 嘀嗒出行支付方式全解析
-
- 文章 · 前端 | 1分钟前 |
- JavaScript数组排序实战技巧
- 430浏览 收藏
-
- 文章 · 前端 | 5分钟前 | 区别 CSS动画 Transition @keyframes 触发方式
- CSS过渡与动画区别详解
- 415浏览 收藏
-
- 文章 · 前端 | 7分钟前 |
- CSS卡片翻转动画实现教程
- 492浏览 收藏
-
- 文章 · 前端 | 8分钟前 |
- CSS卡片悬停效果:translate与transition教程
- 164浏览 收藏
-
- 文章 · 前端 | 9分钟前 |
- CSSGrid实现自适应导航栏教程
- 231浏览 收藏
-
- 文章 · 前端 | 14分钟前 |
- CSS过渡实现浮动提示框动画:opacity与transform结合使用
- 111浏览 收藏
-
- 文章 · 前端 | 16分钟前 |
- 编码解码错误怎么解决?
- 173浏览 收藏
-
- 文章 · 前端 | 23分钟前 |
- WebAssembly引用类型与JS对象交互技巧
- 223浏览 收藏
-
- 文章 · 前端 | 25分钟前 |
- Flexbox两列布局快速实现方法
- 259浏览 收藏
-
- 文章 · 前端 | 26分钟前 |
- 如何选CSS框架?实用工具对比分析
- 127浏览 收藏
-
- 文章 · 前端 | 32分钟前 |
- CSS固定导航栏怎么实现?
- 428浏览 收藏
-
- 文章 · 前端 | 32分钟前 |
- CSS中:required与:optional的区别详解
- 278浏览 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 485次学习
-
- ChatExcel酷表
- ChatExcel酷表是由北京大学团队打造的Excel聊天机器人,用自然语言操控表格,简化数据处理,告别繁琐操作,提升工作效率!适用于学生、上班族及政府人员。
- 3176次使用
-
- Any绘本
- 探索Any绘本(anypicturebook.com/zh),一款开源免费的AI绘本创作工具,基于Google Gemini与Flux AI模型,让您轻松创作个性化绘本。适用于家庭、教育、创作等多种场景,零门槛,高自由度,技术透明,本地可控。
- 3388次使用
-
- 可赞AI
- 可赞AI,AI驱动的办公可视化智能工具,助您轻松实现文本与可视化元素高效转化。无论是智能文档生成、多格式文本解析,还是一键生成专业图表、脑图、知识卡片,可赞AI都能让信息处理更清晰高效。覆盖数据汇报、会议纪要、内容营销等全场景,大幅提升办公效率,降低专业门槛,是您提升工作效率的得力助手。
- 3417次使用
-
- 星月写作
- 星月写作是国内首款聚焦中文网络小说创作的AI辅助工具,解决网文作者从构思到变现的全流程痛点。AI扫榜、专属模板、全链路适配,助力新人快速上手,资深作者效率倍增。
- 4522次使用
-
- MagicLight
- MagicLight.ai是全球首款叙事驱动型AI动画视频创作平台,专注于解决从故事想法到完整动画的全流程痛点。它通过自研AI模型,保障角色、风格、场景高度一致性,让零动画经验者也能高效产出专业级叙事内容。广泛适用于独立创作者、动画工作室、教育机构及企业营销,助您轻松实现创意落地与商业化。
- 3796次使用
-
- JavaScript函数定义及示例详解
- 2025-05-11 502浏览
-
- 优化用户界面体验的秘密武器:CSS开发项目经验大揭秘
- 2023-11-03 501浏览
-
- 使用微信小程序实现图片轮播特效
- 2023-11-21 501浏览
-
- 解析sessionStorage的存储能力与限制
- 2024-01-11 501浏览
-
- 探索冒泡活动对于团队合作的推动力
- 2024-01-13 501浏览

