From 0cd6836a850be1b70ec8a020b41ad500c39f4a2c Mon Sep 17 00:00:00 2001 From: liuwei Date: Mon, 14 Apr 2025 12:30:32 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BA=BA=E8=84=B8=E8=AF=86=E5=88=AB=E7=B2=BE?= =?UTF-8?q?=E5=BA=A6=E8=A6=81=E6=B1=82=E6=8F=90=E5=8D=87=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- plugins/kid_photo_extractor/main.py | 55 ++++++++++++++++++++++++----- 1 file changed, 47 insertions(+), 8 deletions(-) diff --git a/plugins/kid_photo_extractor/main.py b/plugins/kid_photo_extractor/main.py index 4e8fe58..cdbfba2 100644 --- a/plugins/kid_photo_extractor/main.py +++ b/plugins/kid_photo_extractor/main.py @@ -56,18 +56,36 @@ class FaceAnalyzer: self.logger.error(f"读取图片失败: {image_path}, 错误: {e}") return [] - # 使用更宽松的人脸检测参数 + # 使用更精确的人脸检测参数 faces = DeepFace.extract_faces( img_path=image_path, enforce_detection=False, - detector_backend='opencv', # 使用更快的opencv检测器 - align=True + detector_backend='retinaface', # 使用更精确的RetinaFace检测器 + align=True, + threshold=0.7 # 提高置信度阈值,减少误检 ) + # 过滤掉可能的误检 + valid_faces = [] + for face in faces: + # 检查人脸区域的大小,过滤掉太小的区域(可能是图标) + if 'facial_area' in face: + area = face['facial_area'] + face_width = area['w'] + face_height = area['h'] + + # 过滤条件:人脸必须足够大(通常图标较小) + min_face_size = 40 # 最小人脸尺寸(像素) + if face_width > min_face_size and face_height > min_face_size: + # 检查人脸宽高比,过滤掉不合理的比例 + aspect_ratio = face_width / face_height + if 0.5 <= aspect_ratio <= 2.0: # 正常人脸的宽高比范围 + valid_faces.append(face) + # 记录检测到的人脸数量 - self.logger.info(f"在图片 {image_path} 中检测到 {len(faces)} 个人脸") + self.logger.info(f"在图片 {image_path} 中检测到 {len(faces)} 个人脸,有效人脸 {len(valid_faces)} 个") - return faces + return valid_faces except Exception as e: self.logger.error(f"人脸检测失败: {image_path}, 错误: {e}") self.logger.error(traceback.format_exc()) # 打印完整的错误堆栈 @@ -96,8 +114,29 @@ class FaceAnalyzer: # 保存临时裁剪图片 temp_path = f"{image_path}.temp.jpg" cv2.imwrite(temp_path, img) - image_path = temp_path + # 二次验证:使用人脸验证模型确认这确实是一张人脸 + try: + verification = DeepFace.verify( + img1_path=temp_path, + enforce_detection=False, + detector_backend='retinaface', + model_name='VGG-Face', # 使用VGG-Face模型进行验证 + distance_metric='cosine' + ) + + # 如果验证失败(不是人脸),则返回None + if not verification.get('verified', False) and verification.get('distance', 0) > 0.5: + self.logger.info(f"二次验证失败,可能不是真实人脸: {image_path}") + if os.path.exists(temp_path): + os.remove(temp_path) + return None, None + except Exception as e: + # 验证失败不中断流程,只记录日志 + self.logger.warning(f"人脸二次验证失败: {e}") + + image_path = temp_path + except Exception as e: self.logger.error(f"读取图片失败: {image_path}, 错误: {e}") return None, None @@ -105,9 +144,9 @@ class FaceAnalyzer: # 提取人脸特征向量用于后续比对 embedding_result = DeepFace.represent( img_path=image_path, - model_name='Facenet', + model_name='ArcFace', # 使用ArcFace模型,对不同年龄段人脸效果更好 enforce_detection=False, - detector_backend='opencv' # 使用更快的opencv检测器 + detector_backend='retinaface' # 使用更精确的检测器 ) # 处理embedding结果,确保它是一个数值数组