Files
video/core/face.py
2025-09-04 22:59:27 +08:00

114 lines
4.0 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import os
import numpy as np
import cv2
from PIL import Image # 确保正确导入Image类
from insightface.app import FaceAnalysis
# 导入获取人脸信息的服务
from service.face_service import get_all_face_name_with_eigenvalue
# 全局变量
_face_app = None
_known_faces_embeddings = {} # 存储姓名到特征值的映射
_known_faces_names = [] # 存储所有已知姓名
def load_model():
"""加载人脸识别模型及已知人脸特征库"""
global _face_app, _known_faces_embeddings, _known_faces_names
# 初始化InsightFace模型
try:
_face_app = FaceAnalysis(name='buffalo_l', root=os.path.expanduser('~/.insightface'))
_face_app.prepare(ctx_id=0, det_size=(640, 640))
except Exception as e:
print(f"Face model load failed: {e}")
return False
# 从服务获取所有人脸姓名和特征值
try:
face_data = get_all_face_name_with_eigenvalue()
# 处理获取到的人脸数据
for person_name, eigenvalue_data in face_data.items():
# 处理特征值数据 - 兼容数组和字符串两种格式
if isinstance(eigenvalue_data, np.ndarray):
# 如果已经是numpy数组直接使用
eigenvalue = eigenvalue_data.astype(np.float32)
elif isinstance(eigenvalue_data, str):
# 清理字符串:移除方括号、换行符和多余空格
cleaned = eigenvalue_data.replace('[', '').replace(']', '').replace('\n', '').strip()
# 按空格或逗号分割(处理可能的不同分隔符)
values = [v for v in cleaned.split() if v]
# 转换为数组
eigenvalue = np.array(list(map(float, values)), dtype=np.float32)
else:
# 不支持的类型
print(f"Unsupported eigenvalue type for {person_name}")
continue
# 归一化处理
norm = np.linalg.norm(eigenvalue)
if norm != 0:
eigenvalue = eigenvalue / norm
_known_faces_embeddings[person_name] = eigenvalue
_known_faces_names.append(person_name)
except Exception as e:
print(f"Error loading face data from service: {e}")
return True if _face_app else False
def detect(frame, threshold=0.4):
"""检测并识别人脸,返回结果元组(是否匹配到已知人脸, 结果字符串)"""
global _face_app, _known_faces_embeddings, _known_faces_names
if not _face_app or not _known_faces_names or frame is None:
return (False, "未初始化或无效帧")
try:
faces = _face_app.get(frame)
except Exception as e:
print(f"Face detect error: {e}")
return (False, f"检测错误: {str(e)}")
result_parts = []
has_matched = False # 新增标记:是否有匹配到的已知人脸
for face in faces:
# 特征归一化
embedding = face.embedding.astype(np.float32)
norm = np.linalg.norm(embedding)
if norm == 0:
continue
embedding = embedding / norm
# 对比已知人脸
max_sim, best_name = -1.0, "Unknown"
for name in _known_faces_names:
known_emb = _known_faces_embeddings[name]
sim = np.dot(embedding, known_emb)
if sim > max_sim:
max_sim = sim
best_name = name
# 判断匹配结果
is_match = max_sim >= threshold
if is_match:
has_matched = True # 只要有一个匹配成功就标记为True
bbox = face.bbox
result_parts.append(
f"{'匹配' if is_match else '不匹配'}: {best_name} (相似度: {max_sim:.2f}, 边界框: {bbox})"
)
# 构建结果字符串
if not result_parts:
result_str = "未检测到人脸"
else:
result_str = "; ".join(result_parts)
# 第一个返回值改为:是否匹配到已知人脸
return (has_matched, result_str)