You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

OpenCV face_recognition多图训练单人特征编码合并问题

face_recognition 多图训练人脸识别修复方案

问题背景

基于face_recognition模块搭建人脸识别系统时,需要支持同一人员使用多张照片训练:known_faces目录下包含4个以人员命名的子文件夹(示例命名为A、B、C、D),每个子文件夹内存放对应人员的10张照片。
原有实现代码如下:

import face_recognition
import os
import cv2
import numpy as np
from numpy import load

KNOWN_FACES_DIR = 'known_faces'
TOLERANCE = 0.4
FRAME_THICKNESS = 3
FONT_THICKNESS = 2
MODEL = 'cnn'
video = cv2.VideoCapture(0)


print('Encoding faces...')
known_faces = []
known_names = []

for name in os.listdir(KNOWN_FACES_DIR):
    for filename in os.listdir(f'{KNOWN_FACES_DIR}/{name}'):
        image = face_recognition.load_image_file(f'{KNOWN_FACES_DIR}/{name}/{filename}')
        box = face_recognition.face_locations(image,model=MODEL)[0]
        encoding = face_recognition.face_encodings(image,box)[0]
        known_faces.append(encoding)
        known_names.append(name)

print(known_faces)

np.save('face_repr.npy', known_faces)
np.save('labels.npy', known_names)

运行代码后实际打印的是known_names列表(属于变量打印错误,known_faces存储的是128维人脸编码向量),输出为40个名称项,按顺序重复10次A、10次B、10次C、10次D。原有逻辑为40张图像分别生成独立编码,被误认为会识别出40个不同人员,实际期望是最终对应4个有效人员身份。

核心认知误区:同一人员对应多个人脸编码不会被判定为多个不同身份,只要匹配逻辑正确,所有关联同个名字的编码都会映射到同一人员。

可选解决方案

方案1:保留多编码逻辑(推荐,识别准确率更高)

该方案不需要修改现有编码存储结构,仅需要补全异常判断、修正识别阶段的匹配规则即可。同一人员不同角度、不同光线、不同表情的编码都能作为匹配参考,识别准确率更高。

编码阶段修正

原代码直接取face_locations和face_encodings返回结果的第0项,若某张训练图未检测到人脸会直接触发索引报错,修正后代码:

print('Encoding faces...')
known_faces = []
known_names = []

for name in os.listdir(KNOWN_FACES_DIR):
    person_dir = os.path.join(KNOWN_FACES_DIR, name)
    # 跳过目录下的非文件夹文件
    if not os.path.isdir(person_dir):
        continue
    for filename in os.listdir(person_dir):
        img_path = os.path.join(person_dir, filename)
        try:
            image = face_recognition.load_image_file(img_path)
            # 检测人脸位置,未检测到人脸跳过当前图片
            face_locations = face_recognition.face_locations(image, model=MODEL)
            if not face_locations:
                print(f"未在{img_path}检测到人脸,已跳过")
                continue
            encoding = face_recognition.face_encodings(image, known_face_locations=[face_locations[0]])[0]
            known_faces.append(encoding)
            known_names.append(name)
        except Exception as e:
            print(f"处理{img_path}出错:{str(e)},已跳过")

np.save('face_repr.npy', known_faces)
np.save('labels.npy', known_names)

识别阶段匹配逻辑

匹配时取与当前人脸距离最小的已知编码作为匹配项,只要距离小于阈值即可判定为对应人员,参考代码:

while True:
    ret, frame = video.read()
    if not ret:
        break
    rgb_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
    # 检测当前帧人脸位置和编码
    face_locations = face_recognition.face_locations(rgb_frame, model=MODEL)
    face_encodings = face_recognition.face_encodings(rgb_frame, face_locations)

    for face_encoding, (top, right, bottom, left) in zip(face_encodings, face_locations):
        # 计算当前人脸和所有已知编码的距离
        face_distances = face_recognition.face_distance(known_faces, face_encoding)
        # 取距离最小的匹配项
        best_match_idx = np.argmin(face_distances)
        if face_distances[best_match_idx] <= TOLERANCE:
            match_name = known_names[best_match_idx]
            # 画人脸框
            cv2.rectangle(frame, (left, top), (right, bottom), (0,255,0), FRAME_THICKNESS)
            # 写人名标签
            cv2.putText(frame, match_name, (left, top-10), cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0,255,0), FONT_THICKNESS)
    
    cv2.imshow('Face Recognition', frame)
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

video.release()
cv2.destroyAllWindows()

方案2:生成单人员平均编码(匹配速度更快)

如果希望每个人员仅对应1组编码,最终存储4组编码对应4个人员,可以对同一个人的所有人脸编码求平均值,用平均向量作为该人员的特征代表。该方案匹配时计算量更小,运行速度更快,符合最初“4名人员生成4组对应编码”的预期。
编码阶段修改为:

print('Encoding faces...')
known_faces = []
known_names = []

for name in os.listdir(KNOWN_FACES_DIR):
    person_dir = os.path.join(KNOWN_FACES_DIR, name)
    if not os.path.isdir(person_dir):
        continue
    person_encodings = []
    for filename in os.listdir(person_dir):
        img_path = os.path.join(person_dir, filename)
        try:
            image = face_recognition.load_image_file(img_path)
            face_locations = face_recognition.face_locations(image, model=MODEL)
            if not face_locations:
                print(f"未在{img_path}检测到人脸,已跳过")
                continue
            encoding = face_recognition.face_encodings(image, known_face_locations=[face_locations[0]])[0]
            person_encodings.append(encoding)
        except Exception as e:
            print(f"处理{img_path}出错:{str(e)},已跳过")
    # 对当前人员的所有编码求平均,得到单组代表编码
    if person_encodings:
        avg_encoding = np.mean(person_encodings, axis=0)
        known_faces.append(avg_encoding)
        known_names.append(name)

np.save('face_repr.npy', known_faces)
np.save('labels.npy', known_names)

该方案最终生成的known_faces长度为4,known_names为['A','B','C','D'],识别阶段逻辑和单图训练的实现完全一致即可。

注意事项

  • 当前设置的TOLERANCE = 0.4阈值过于严格,face_recognition默认阈值为0.6,阈值越低判定越严格,越容易出现漏识别,建议根据实际测试效果调整到0.45-0.55区间。
  • 训练图尽量覆盖不同光线、角度、表情,避免使用模糊、遮挡严重的图片,能有效提升识别准确率。
  • 如果设备没有独立GPU,建议将MODEL参数改为hog,CPU运行速度会比cnn模型快很多。

内容的提问来源于stack exchange,提问作者Nikhil Anand

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 21:27:20