Files
video/ocr/face_recognizer.py

139 lines
5.5 KiB
Python
Raw Normal View History

2025-09-03 14:38:42 +08:00
import os
import cv2
import numpy as np
import insightface
from insightface.app import FaceAnalysis
2025-09-03 16:22:21 +08:00
2025-09-03 14:38:42 +08:00
class FaceRecognizer:
"""
封装InsightFace人脸识别功能支持从文件夹加载已知人脸
"""
2025-09-03 16:22:21 +08:00
2025-09-03 14:38:42 +08:00
def __init__(self, known_faces_dir: str):
self.known_faces_dir = known_faces_dir
self.app = self._initialize_insightface()
self.known_faces_embeddings = {}
self.known_faces_names = []
self._load_known_faces()
def _initialize_insightface(self):
2025-09-03 16:22:21 +08:00
"""初始化InsightFace FaceAnalysis应用"""
print("初始化InsightFace引擎...")
2025-09-03 14:38:42 +08:00
try:
2025-09-03 16:22:21 +08:00
app = FaceAnalysis(name='buffalo_l', root='~/.insightface')
app.prepare(ctx_id=0, det_size=(640, 640))
print("InsightFace引擎初始化完成")
2025-09-03 14:38:42 +08:00
return app
except Exception as e:
2025-09-03 16:22:21 +08:00
print(f"InsightFace初始化失败: {e}")
print("请检查依赖是否安装及模型是否可访问")
2025-09-03 14:38:42 +08:00
return None
def _load_known_faces(self):
2025-09-03 16:22:21 +08:00
"""加载已知人脸特征"""
2025-09-03 14:38:42 +08:00
if not os.path.exists(self.known_faces_dir):
2025-09-03 16:22:21 +08:00
print(f"已知人脸目录不存在,已创建: {self.known_faces_dir}")
2025-09-03 14:38:42 +08:00
os.makedirs(self.known_faces_dir, exist_ok=True)
return
2025-09-03 16:22:21 +08:00
print(f"从目录加载人脸特征: {self.known_faces_dir}")
2025-09-03 14:38:42 +08:00
for person_name in os.listdir(self.known_faces_dir):
person_dir = os.path.join(self.known_faces_dir, person_name)
if os.path.isdir(person_dir):
2025-09-03 16:22:21 +08:00
print(f"处理人物: {person_name}")
2025-09-03 14:38:42 +08:00
embeddings = []
for filename in os.listdir(person_dir):
if filename.lower().endswith(('.png', '.jpg', '.jpeg')):
image_path = os.path.join(person_dir, filename)
try:
img = cv2.imread(image_path)
if img is None:
2025-09-03 16:22:21 +08:00
print(f"无法读取图片: {image_path},已跳过")
2025-09-03 14:38:42 +08:00
continue
2025-09-03 16:22:21 +08:00
2025-09-03 14:38:42 +08:00
faces = self.app.get(img)
if faces:
embeddings.append(faces[0].embedding)
2025-09-03 16:22:21 +08:00
print(f"提取特征成功: {filename}")
2025-09-03 14:38:42 +08:00
else:
2025-09-03 16:22:21 +08:00
print(f"未检测到人脸: {filename},已跳过")
2025-09-03 14:38:42 +08:00
except Exception as e:
2025-09-03 16:22:21 +08:00
print(f"处理图片出错 {image_path}: {e}")
2025-09-03 14:38:42 +08:00
if embeddings:
self.known_faces_embeddings[person_name] = np.array(embeddings).mean(axis=0)
self.known_faces_names.append(person_name)
2025-09-03 16:22:21 +08:00
print(f"人物 {person_name} 加载完成,共 {len(embeddings)} 张照片")
2025-09-03 14:38:42 +08:00
else:
2025-09-03 16:22:21 +08:00
print(f"人物 {person_name} 无有效特征,已跳过")
print(f"人脸加载完成,共 {len(self.known_faces_names)}")
2025-09-03 14:38:42 +08:00
def recognize(self, frame, threshold=0.4):
2025-09-03 16:22:21 +08:00
"""识别人脸并返回结果"""
2025-09-03 14:38:42 +08:00
if not self.app or not self.known_faces_names:
return False, None, None
2025-09-03 16:22:21 +08:00
faces = self.app.get(frame)
2025-09-03 14:38:42 +08:00
if not faces:
return False, None, None
for face in faces:
for known_name in self.known_faces_names:
known_embedding = self.known_faces_embeddings[known_name]
2025-09-03 16:22:21 +08:00
2025-09-03 14:38:42 +08:00
embedding1 = face.embedding.astype(np.float32)
embedding2 = known_embedding.astype(np.float32)
dot_product = np.dot(embedding1, embedding2)
norm_embedding1 = np.linalg.norm(embedding1)
norm_embedding2 = np.linalg.norm(embedding2)
2025-09-03 16:22:21 +08:00
similarity = 0.0 if (norm_embedding1 == 0 or norm_embedding2 == 0) else (
dot_product / (norm_embedding1 * norm_embedding2)
)
2025-09-03 14:38:42 +08:00
if similarity >= threshold:
2025-09-03 16:22:21 +08:00
print(f"检测到已知人物: {known_name} (相似度: {similarity:.4f})")
return True, known_name, similarity
2025-09-03 14:38:42 +08:00
2025-09-03 16:22:21 +08:00
return False, None, None
2025-09-03 14:38:42 +08:00
2025-09-03 16:22:21 +08:00
def test_single_image(self, image_path: str, threshold=0.4):
"""测试单张图片识别"""
if not os.path.exists(image_path):
print(f"图片不存在: {image_path}")
return False, None, None
frame = cv2.imread(image_path)
if frame is None:
print(f"无法读取图片: {image_path}")
return False, None, None
result, name, similarity = self.recognize(frame, threshold)
if result:
print(f"识别结果: {name} (相似度: {similarity:.4f})")
faces = self.app.get(frame)
for face in faces:
bbox = face.bbox.astype(int)
cv2.rectangle(frame, (bbox[0], bbox[1]), (bbox[2], bbox[3]), (0, 255, 0), 2)
text = f"{name}: {similarity:.2f}"
cv2.putText(frame, text, (bbox[0], bbox[1] - 10),
cv2.FONT_HERSHEY_SIMPLEX, 0.9, (0, 255, 0), 2)
cv2.imshow('识别结果', frame)
print("按任意键关闭窗口...")
cv2.waitKey(0)
cv2.destroyAllWindows()
else:
print("未识别到已知人脸")
return result, name, similarity
#
2025-09-03 14:38:42 +08:00
# if __name__ == "__main__":
# recognizer = FaceRecognizer(known_faces_dir="known_faces")
2025-09-03 16:22:21 +08:00
# test_image_path = r"F:\OCR\RapidOCR-main\known_faces\B\14sino-qiu02-master1050.jpg"
2025-09-03 14:38:42 +08:00
# recognizer.test_single_image(test_image_path, threshold=0.4)