MediaPipe人脸检测后,如何实现人脸识别及特征匹配?
解决方案:人脸特征匹配与跨库结合实现人脸识别
一、基于MediaPipe Face Mesh特征的匹配方案
你当前保存的是单用户50帧的人脸关键点(landmarks),直接用单帧特征与50个样本匹配会存在误差,优化步骤如下:
预存特征预处理
采集完成后,对该用户的50组landmarks取均值,得到该用户的基准特征向量(将三维关键点扁平化成长一维数组),替换原有的保存方式,以此降低单帧波动带来的匹配误差。实时特征匹配逻辑
实时流中提取当前人脸的Face Mesh特征,同样扁平化后,与所有预存的用户基准特征计算相似度:- 欧氏距离:距离越小,特征相似度越高,可设置阈值(如0.05,需根据实际测试调整)
- 余弦相似度:值越接近1,特征相似度越高,阈值可设为0.95左右
代码修改示例
修改capture_faces函数中保存特征的部分:# 将人脸关键点保存为子文件夹中的pickle文件(改为保存平均特征) import numpy as np avg_landmarks = np.mean(face_landmarks_list, axis=0).flatten() # 扁平化为一维数组 pickle_file_path = os.path.join(save_path, f"{name}_avg_landmarks.pkl") with open(pickle_file_path, "wb") as f: pickle.dump({"name": name, "avg_landmarks": avg_landmarks}, f)在实时流循环中添加匹配逻辑:
# 加载所有预存用户的平均特征 def load_all_user_features(): user_features = [] for root, dirs, files in os.walk(SAVE_DIR): for file in files: if file.endswith("_avg_landmarks.pkl"): with open(os.path.join(root, file), "rb") as f: data = pickle.load(f) user_features.append(data) return user_features # 初始化时加载特征 user_features = load_all_user_features() # 实时匹配函数 def match_face(current_landmarks, user_features, threshold=0.05): current_flat = np.array(current_landmarks).flatten() min_dist = float('inf') matched_name = "未知人员" for user in user_features: dist = np.linalg.norm(current_flat - user["avg_landmarks"]) if dist < min_dist and dist < threshold: min_dist = dist matched_name = user["name"] return matched_name # 在实时流的人脸检测部分添加匹配 if results.detections: for detection in results.detections: # ... 原有的bbox计算代码 ... # 裁剪人脸区域 face_frame = frame[ymin:ymin + height, xmin:xmin + width] frame_rgb_face = cv2.cvtColor(face_frame, cv2.COLOR_BGR2RGB) # 提取实时Face Mesh特征 with mp_face_mesh.FaceMesh(static_image_mode=True, max_num_faces=1, min_detection_confidence=0.5) as face_mesh: mesh_results = face_mesh.process(frame_rgb_face) if mesh_results.multi_face_landmarks: landmarks = [list((lm.x, lm.y, lm.z)) for lm in mesh_results.multi_face_landmarks[0].landmark] matched_name = match_face(landmarks, user_features) else: matched_name = "未知人员" # 绘制文字 cv2.putText(frame, matched_name, (xmin, ymin - 10), font, 0.9, (0, 0, 255) if matched_name == "未知人员" else (0, 255, 0), 2, cv2.LINE_AA)
二、结合DeepFace/OpenCV实现更高准确率的人脸识别
MediaPipe的Face Mesh特征更偏向人脸姿态分析,并非专门为识别优化,结合DeepFace或OpenCV能获得更好的识别效果:
1. 结合DeepFace方案
DeepFace封装了多个预训练人脸识别模型(如VGG-Face、Facenet),可以用MediaPipe做实时人脸检测,裁剪出人脸后交给DeepFace提取特征并匹配:
- 安装DeepFace:
pip install deepface - 修改代码逻辑:
from deepface import DeepFace # 采集时为用户生成DeepFace基准特征 def save_deepface_features(name, save_path): # 取该用户的一张清晰人脸图像(比如第25帧) sample_img_path = os.path.join(save_path, "face_24.jpg") # 提取特征 embedding = DeepFace.represent(img_path=sample_img_path, model_name="Facenet")[0]["embedding"] # 保存特征 with open(os.path.join(save_path, f"{name}_deepface_embedding.pkl"), "wb") as f: pickle.dump({"name": name, "embedding": embedding}, f) # 在capture_faces函数末尾调用 save_deepface_features(name, save_path) # 实时匹配 def match_deepface(current_face_img, user_features, threshold=0.6): current_embedding = DeepFace.represent(img_path=current_face_img, model_name="Facenet")[0]["embedding"] min_dist = float('inf') matched_name = "未知人员" for user in user_features: dist = np.linalg.norm(np.array(current_embedding) - np.array(user["embedding"])) if dist < min_dist and dist < threshold: min_dist = dist matched_name = user["name"] return matched_name # 实时流中使用 # 裁剪得到face_frame后,直接传入匹配函数 matched_name = match_deepface(face_frame, deepface_user_features)
2. 结合OpenCV人脸识别方案
OpenCV提供了LBPH、EigenFace、FisherFace三种人脸识别器,适合轻量场景:
- 训练阶段:收集用户人脸图像,用
cv2.face.LBPHFaceRecognizer_create()训练模型 - 实时阶段:检测人脸后,将裁剪区域转为灰度图,输入模型预测
三、注意事项
- 阈值需要根据实际场景测试调整,不同光线、姿态下阈值可能不同
- 实时匹配时,建议每N帧做一次匹配(比如每5帧),减少计算开销
- 若用户数量较多,可以考虑用KNN或聚类算法优化匹配速度
内容的提问来源于stack exchange,提问作者Chamod Abeyrathne
相关产品推荐
相关产品推荐

