输入两张图片 A、B,输出相似度,以及“是否判为同一个人”。计算顺序是:
A → 检测人脸 → 对齐 → 同一个特征网络 → 向量 aB → 检测人脸 → 对齐 → 同一个特征网络 → 向量 ba、b → 余弦相似度 → 与阈值比较两张原图不必尺寸相同,进入身份网络的脸图必须遵守同一套输入规则。无脸或有多张脸时,本例直接报错,不擅自选一张脸。
1. 找到脸
检测器预测人脸框,有的还预测双眼、鼻尖和嘴角。神经网络检测器一般先产生候选框和分数,再用非极大值抑制(NMS)去掉重叠候选。
框可以写成 (x, y, width, height)。YuNet、RetinaFace 是常见选择;通用目标检测模型需要专门的人脸权重,才能承担这个任务。人脸框的位置用于裁剪,关键点用于对齐,检测分数只表示候选像不像脸。
2. 对齐五官
同一个人歪头 15°,五官的图像坐标会一起旋转。直接把矩形框缩放到固定大小,眼睛的位置仍可能不同。
常见做法是把检测到的关键点 p_i 对应到模板点 q_i,求缩放 s、二维旋转 R 和平移 t:
再用这个相似变换重采样图片。眼睛和嘴的位置统一后,网络比较容易把注意力放在身份差异上。
二维对齐主要修正位置、尺度和画面内旋转,不能补出大侧脸被遮住的半张脸。模板、输入尺寸、颜色通道和归一化要与权重一致。
3. 提取身份特征
设对齐后的脸图为 x,特征网络为 fθ:
z 是特征向量(embedding),e 是单位长度的向量。维数由模型决定,常见实现有 128、512 维;换模型后,即使维数相同也不能交叉比较。
卷积层用局部滤波器计算边缘、明暗和纹理响应,后续层组合更大范围的模式。训练调整这些滤波器,使最终向量对身份有区分力。某一维通常不对应“鼻子宽度”或“眼睛大小”,不能逐维当作人工定义的五官测量值。
同一个网络分别处理 A、B,不需要每来两张照片就重新训练。训练时也不必包含这次要比较的人:网络学到的表征可以用于未见过的身份,但效果仍取决于训练数据和图片条件。
4. ArcFace 怎样训练
ArcFace 是训练时使用的角度间隔损失。它约束身份特征的分布;推理时仍然提取向量并计算距离。
普通身份分类训练希望图片被分到正确的人。ArcFace 将特征与分类权重归一化,用夹角表示接近程度;对正确身份额外加入角度间隔 m,让分类要求更严格。
单个样本的损失可写成:
y 是正确身份,θ_y 是特征与该身份分类权重的夹角,s 是尺度。训练反复更新网络参数,使同一身份的向量集中、不同身份更容易分开。推理时通常去掉训练用的身份分类层,使用 embedding。ArcFace 论文给出了这个损失及其几何解释。
另一条常见路线是 FaceNet 的三元组损失:让同人的距离小于异人的距离,并留出间隔。LBPH 则统计局部纹理直方图,原理简单,但对姿态、光照变化的适应性有限。
5. 比较两个向量
余弦相似度计算方向的接近程度:
取值范围为 [-1, 1],越大越相似。余弦距离常定义为 d = 1 - c,范围为 [0, 2],越小越相似。代码里必须看清用的是哪一个。
用二维向量算一次:a=(1,0),b=(0.8,0.6),两个向量长度都为 1。因此 c=0.8、d=0.2。若为演示暂取相似度阈值 0.75,这一对会被判为同人。这个阈值仅用于算例。
import numpy as np
def cosine_similarity(a, b): a, b = np.asarray(a, dtype=float), np.asarray(b, dtype=float) if a.ndim != 1 or a.shape != b.shape or a.size == 0: raise ValueError("需要两个等长的一维特征") if not np.isfinite(a).all() or not np.isfinite(b).all(): raise ValueError("特征含无效数值") # 先缩放,避免很大的有限数值在求平方和时溢出。 sa, sb = np.max(np.abs(a)), np.max(np.abs(b)) if sa == 0 or sb == 0: raise ValueError("特征不能是零向量") a, b = a / sa, b / sb a, b = a / np.linalg.norm(a), b / np.linalg.norm(b) return float(np.clip(a @ b, -1, 1))
score = cosine_similarity([1, 0], [0.8, 0.6])print(score) # 0.8对于单位向量,欧氏距离与余弦相似度的关系是:||a-b||² = 2-2c。这时两种度量的排序一致,阈值需要换算。
6. 选择阈值
准备同人的不同照片对,以及异人照片对。固定检测、对齐和特征网络,计算每一对的分数。对一个候选相似度阈值 τ:
误接受率 FAR = 异人分数 ≥ τ 的对数 / 异人总对数误拒绝率 FRR = 同人分数 < τ 的对数 / 同人总对数提高阈值通常减少误接受、增加误拒绝。阈值在独立验证集上选择,最终效果再用未参与选择的测试集衡量。拆分时避免同一张图或近重复图同时出现在两边。
c=0.8 不表示“80% 是同一个人”。它是向量几何分数,尚未经过概率校准。OpenCV 官方 SFace 教程在不同数据集上也列出了不同阈值,说明阈值依赖模型与评测条件。来源
完整的两图片实现见算法示例,其中保留了检测、对齐、特征和余弦计算的各个步骤。
评论