下面的程序直接读取本地图片,不调用任何业务服务。

人脸比对使用 YuNet + SFace,单图活体使用一个 MiniFASNetV2 权重。共同的检测器只是为了简化示例,不表示两类任务使用相同特征。

1. 准备环境和模型

使用 Python 3.11,新建空目录,将这些文件保存到同一目录:

Terminal window
python -m venv .venv
.\.venv\Scripts\python -m pip install numpy==1.26.4 opencv-python==4.11.0.86
.\.venv\Scripts\python -m pip install torch==2.6.0 --index-url https://download.pytorch.org/whl/cpu

从 OpenCV Zoo 获取两个模型,放在 models 目录:

models/
face_detection_yunet_2023mar.onnx
face_recognition_sface_2021dec.onnx

分别对应 YuNet 和 SFace。模型文件使用 Git LFS 存储,确认下载的是完整 ONNX,不能把只有几行文本的 LFS 指针当模型。

活体部分需要上游的网络结构、裁剪代码和权重:

Terminal window
New-Item -ItemType Directory -Force Silent-Face-Anti-Spoofing/src/model_lib,Silent-Face-Anti-Spoofing/resources/anti_spoof_models | Out-Null
$faceSource = 'https://raw.githubusercontent.com/minivision-ai/Silent-Face-Anti-Spoofing/b6d5f04ad78778917853b25c778acef6d5626d15'
Invoke-WebRequest "$faceSource/src/model_lib/MiniFASNet.py" -OutFile Silent-Face-Anti-Spoofing/src/model_lib/MiniFASNet.py
Invoke-WebRequest "$faceSource/src/generate_patches.py" -OutFile Silent-Face-Anti-Spoofing/src/generate_patches.py
Invoke-WebRequest "$faceSource/resources/anti_spoof_models/2.7_80x80_MiniFASNetV2.pth" -OutFile Silent-Face-Anti-Spoofing/resources/anti_spoof_models/2.7_80x80_MiniFASNetV2.pth

在新建目录中运行这些命令,只获取固定版本所需的三个文件,避开上游旧日志中 Windows 不支持的路径。本文只加载 resources/anti_spoof_models/2.7_80x80_MiniFASNetV2.pth。它的 SHA-256 应为:

a5eb02e1843f19b5386b953cc4c9f011c3f985d0ee2bb9819eea9a142099bec0

可用 Get-FileHash -Algorithm SHA256 文件路径 检查。仅加载可信来源的权重,程序不会自动下载模型。

2. 两张图的人脸比对

Terminal window
.\.venv\Scripts\python compare_faces.py a.jpg b.jpg --detector models/face_detection_yunet_2023mar.onnx --recognizer models/face_recognition_sface_2021dec.onnx --threshold 0.363

这里的 0.363 来自 OpenCV 官方 SFace 教程的 LFW 示例,只用于复现实例,不是通用阈值。换人群、图像条件或模型后,应按人脸比对中的方法重新选择。

程序的主要计算是:

face = single_face(detector, image)
aligned = recognizer.alignCrop(image, face)
embedding = recognizer.feature(aligned).copy().reshape(-1)

对 A、B 各运行一次,然后计算 similarity = 1 - cosine_distance(a, b)。SFace 的对齐和输入处理由对应 OpenCV 类完成,不手动套用 ArcFace 的预处理。

输出字段含义
similarity余弦相似度,越大越相似
distance1 − similarity,越小越相似
threshold本次使用的相似度阈值
same_personsimilarity 是否大于等于阈值
feature_dimensions实际输出向量的长度

没有脸、检测到多张脸、图片读不出、模型文件错误时,程序报错。报错不等于“不是同一个人”。

3. 一张图的活体检测

Terminal window
.\.venv\Scripts\python single_image_pad.py face.jpg --detector models/face_detection_yunet_2023mar.onnx --repo Silent-Face-Anti-Spoofing --weights Silent-Face-Anti-Spoofing/resources/anti_spoof_models/2.7_80x80_MiniFASNetV2.pth --threshold 0.8

0.8 是便于观察输出的示例阈值,没有声称它具有某种防伪效果。程序要求显式传入阈值,避免把演示数字隐藏成模型默认值。

脚本只支持上面这个权重,并复用固定版本的 CropImage,主要计算是:

patch = cropper.crop(
org_img=image, bbox=bbox, scale=2.7,
out_w=80, out_h=80, crop=True
)
# BGR uint8 → BGR float32,保持 0–255,HWC → NCHW
x = torch.from_numpy(
np.ascontiguousarray(patch.transpose(2, 0, 1))
).float().unsqueeze(0)
model.eval()
with torch.inference_mode():
logits = model(x)
scores = torch.softmax(logits, dim=1)[0]
live_score = float(scores[1])
is_live = live_score >= threshold

完整脚本还处理越界人脸框、权重加载、无效输出,使用 weights_only=True 读取权重。它不需要两张图片,也不采集转头过程。

输出包含三类 class_scores、最大类 argmax_class、真人类 live_score 和阈值判定 is_live。分数是模型输出,不代表已知这张图的真实采集来源。

本例的 YuNet 检测框可能不同于上游检测框,采用的也是单模型阈值规则,因此不承诺复现上游双模型程序的全部结果。单图活体解释了裁剪、特征和分数之间的关系。

4. 不加载模型的计算

Terminal window
.\.venv\Scripts\python algorithms.py
.\.venv\Scripts\python -m unittest test_algorithms -v

第一条命令计算 [1,0] 与 [0.8,0.6] 的余弦距离 0.2,以及二分类 logits [1,3] 的真人类分数约 0.881。第二条检查距离方向、数值输入和几何公式。

安装好 NumPy、OpenCV、PyTorch 后,还可以运行:

Terminal window
.\.venv\Scripts\python -m unittest test_image_pipeline -v

它检查单图张量的通道、数值范围、布局、阈值规则,以及无脸和多人分支。测试网络使用固定 logits,只验证计算,不测试防伪能力。

5. 姿态示例

下载 pnp_pose.py,运行:

Terminal window
.\.venv\Scripts\python pnp_pose.py

程序用已知旋转合成二维点,调用 PnP 反求,检查是否恢复 25° 及接近零的重投影误差。换成真人图时,还需要提供关键点与三维模板的对应关系和相机内参,不能只把图片路径塞给 PnP。

另有 landmark_camera.py 可观察关键点模型的姿态与嘴部数值。它是可选的几何观察器,不做人脸比对或活体判断;额外依赖 mediapipe==0.10.31 和官方 face_landmarker.task 模型:

Terminal window
.\.venv\Scripts\python -m pip install mediapipe==0.10.31
.\.venv\Scripts\python landmark_camera.py --model models/face_landmarker.task

具体角度与比例的推导见姿态计算。模型与图片保存在本地,不必复制进网站资源目录。