face-liveness-detection
v1.1.0
Published
A frontend-only solution for face liveness detection using MediaPipe Face Mesh, with anti-camera-shake protection and face area guidance
Downloads
359
Maintainers
Readme
Face Liveness Detection
基于 MediaPipe Face Mesh 的纯前端人脸活体检测库。
✨ 特性
- 🎯 纯前端检测 - 无需后端,数据不上传,保护隐私
- 🎭 多动作验证 - 支持眨眼、张嘴、左右转头、点头 5 种动作
- 🎨 人脸区域引导 - 彩色圆形区域,覆盖层颜色闪动效果
- 🛡️ 防摄像头移动 - 三重防护机制,防止晃动摄像头触发误判
- 🔊 语音提示 - 自动播报动作指令,用户体验友好
- 📸 自动拍照 - 完成所有动作后自动采集人脸照片
- 🎲 随机顺序 - 支持随机或固定动作顺序
- ⚙️ 高度可配置 - 阈值、UI、语音等全部可定制
🚀 安装
npm install face-liveness-detection快速开始
import {
checkSupport,
checkCameraPermission,
createLivenessDetector
} from 'face-liveness-detection';
// 检测环境支持
const support = checkSupport();
if (!support.supported) {
console.error('不支持活体检测:', support.reasons);
return;
}
// 检测摄像头权限
const permission = await checkCameraPermission();
if (!permission.granted) {
console.error(permission.message);
return;
}
const detector = createLivenessDetector({
videoElement: document.getElementById('video'),
canvasElement: document.getElementById('canvas'),
statusElements: {
faceDetected: document.getElementById('faceDetected'),
blink: document.getElementById('blink'),
openMouth: document.getElementById('openMouth'),
turnLeft: document.getElementById('turnLeft'),
turnRight: document.getElementById('turnRight'),
nod: document.getElementById('nod')
},
captureBtn: document.getElementById('captureBtn'),
resultContainer: document.getElementById('resultContainer'),
capturedImage: document.getElementById('capturedImage'),
// 事件回调
onComplete: base64Image => {
console.log('检测完成', base64Image.length);
},
onActionComplete: (action, current, total) => {
console.log(`完成 ${action} (${current}/${total})`);
},
onError: error => {
console.error('检测出错', error);
},
// 配置
config: {
actions: ['blink', 'openMouth', 'turnLeft'],
actionOrder: 'random'
}
});
await detector.start();
// 终止检测
detector.stop();
// 重置检测
detector.reset();
await detector.start();
// 获取采集的 Base64 图片
const base64 = detector.getBase64Image();📚 配置
const config = {
// 语音提示
voice: {
enabled: true,
lang: 'zh-CN',
rate: 1.0,
prompts: {
faceDetected: '检测到人脸',
blink: '请眨眼',
blinkComplete: '眨眼完成',
openMouth: '请张嘴',
openMouthComplete: '张嘴完成',
turnLeft: '请向左转头',
turnLeftComplete: '左转头完成',
turnRight: '请向右转头',
turnRightComplete: '右转头完成',
nod: '请点头',
nodComplete: '点头完成',
allComplete: '所有动作已完成',
capturing: '请保持不动,正在比对'
}
},
// 眨眼检测
blink: {
threshold: 0.6 // 闭眼比例阈值
},
// 张嘴检测
mouth: {
threshold: 0.07 // 张嘴阈值
},
// 人脸区域检测
faceArea: {
enabled: true, // 是否启用区域检测
circleRatio: 0.6, // 圆形直径占画面宽度比例(0.6 = 60%)
stayDuration: 1000, // 初始停留时间(毫秒)
strictMode: false, // 严格模式(true: 整个人脸必须在圆内,false: 大部分关键点在圆内即可)
borderWidth: 4, // 边框宽度
borderColors: ['#00FF00', '#00FFFF', '#0080FF', '#FF00FF'], // 覆盖层颜色循环(绿、青、蓝、紫)
colorChangeInterval: 500, // 颜色变化间隔(毫秒)
maskOpacity: 0.8, // 遮罩透明度
promptText: '请将人脸移入检测区域' // 提示文字
},
// 动作列表
actions: ['blink', 'openMouth', 'turnLeft', 'turnRight', 'nod'],
// 动作顺序: 'random' 随机 | 'fixed' 固定
actionOrder: 'random',
// 调试模式
debug: false,
// 显示面部关键点
showLandmarks: false
};🎭 可用动作
| 动作 | 标识 | 说明 |
| ------ | ----------- | --------------------- |
| 眨眼 | blink | 闭眼达到阈值 |
| 张嘴 | openMouth | 张嘴达到阈值 |
| 左转头 | turnLeft | 连续 3 帧鼻子向右偏移 |
| 右转头 | turnRight | 连续 3 帧鼻子向左偏移 |
| 点头 | nod | 低头达到阈值 |
🛡️ 防摄像头移动机制
系统内置三重防护,防止通过摇动摄像头作弊:
1️⃣ 画面稳定性检测
- 跟踪人脸中心点的绝对位置变化
- 连续 2 帧移动 > 8% 画面宽度,立即阻断所有检测
- 防止摇动摄像头触发眨眼、张嘴等动作
2️⃣ 单帧异常检测(针对转头)
- 检测鼻子偏移单帧变化量
- 变化 > 0.15 ,判定为画面异常移动
- 重置历史,阻断转头检测
3️⃣ 连续帧判定(针对转头)
- 左转头:连续 3 帧鼻偏移 > 0.15
- 右转头:连续 3 帧鼻偏移 < -0.15
- 防止瞬间抖动或画面异常触发
🔧 API
checkSupport()
检测当前环境是否支持活体检测。
const { supported, reasons } = checkSupport();
// supported: boolean - 是否支持
// reasons: string[] - 不支持的原因列表检测项:
- 浏览器环境
- 摄像头访问 (getUserMedia)
- WebAssembly 支持
- HTTPS 或 localhost
- Canvas 2D 支持
checkCameraPermission()
检测摄像头权限(异步)。
const { granted, error, message } = await checkCameraPermission();
if (!granted) {
console.error(message); // "摄像头权限被拒绝..."
}错误类型:
NotAllowedError- 权限被拒绝NotFoundError- 无摄像头设备NotReadableError- 摄像头被占用
createLivenessDetector(options)
创建检测器实例。
参数:
videoElement- 视频元素canvasElement- Canvas 元素statusElements- 状态显示元素captureBtn- 拍照按钮(可选)resultContainer- 结果容器(可选)capturedImage- 采集图片元素(可选)onComplete(base64)- 完成回调onActionComplete(action, current, total)- 动作完成回调onError(error)- 错误回调config- 配置项(部分配置即可)
detector.start()
开始活体检测。
await detector.start();detector.stop()
终止检测。
detector.stop();detector.reset()
重置检测状态。
detector.reset();
await detector.start(); // 重新开始detector.getBase64Image()
获取采集的 Base64 图片。
const base64 = detector.getBase64Image();
// 返回: string | null👨💻 开发
# 克隆仓库
git clone https://github.com/aliujun/face-liveness-detection.git
cd face-liveness-detection
# 安装依赖
npm install
# 启动 demo
npm run dev
# 构建 npm 包
npm run build
# 构建 demo
npm run build:demo📝 更新日志
v1.1.0 (2025-12-20)
新增特性
- ✨ 人脸区域引导:彩色圆形区域,覆盖层颜色闪动效果
- 🛡️ 防摄像头移动:三重防护机制
- 画面稳定性检测:连续 2 帧移动 > 8% 画面宽度即阻断
- 单帧异常检测:鼻子偏移变化 > 0.15 即阻断
- 连续帧判定:转头动作需连续 3 帧确认
配置优化
- 新增
faceArea配置项,支持自定义圆形区域样式 - 新增
borderColors配置,支持多个颜色循环 - 新增
colorChangeInterval配置,可调颜色变化速度
性能提升
- 优化转头检测逻辑,降低误触发率
- 优化画面渲染效果,提升流畅度
Bug 修复
- 修复眨眼检测的竞态条件问题
- 修复摇动摄像头可以触发转头动作的问题
v1.0.2
- 基础功能实现
- 支持 5 种动作检测
- 语音提示功能
📝 License
MIT
