194 lines
5.5 KiB
Python
194 lines
5.5 KiB
Python
|
|
#!/usr/bin/env python
|
|||
|
|
# -*- coding: utf-8 -*-
|
|||
|
|
"""
|
|||
|
|
人脸识别示例:特征提取 + 相似度比对
|
|||
|
|
"""
|
|||
|
|
|
|||
|
|
import cv2
|
|||
|
|
import numpy as np
|
|||
|
|
import sys
|
|||
|
|
import os
|
|||
|
|
|
|||
|
|
# 添加父目录到路径
|
|||
|
|
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
|||
|
|
|
|||
|
|
from face_feature_extractor import FaceFeatureExtractor
|
|||
|
|
|
|||
|
|
|
|||
|
|
class SimpleFaceRecognizer:
|
|||
|
|
"""简单的人脸识别器"""
|
|||
|
|
|
|||
|
|
def __init__(self, threshold=0.7):
|
|||
|
|
"""
|
|||
|
|
初始化识别器
|
|||
|
|
|
|||
|
|
Args:
|
|||
|
|
threshold: 相似度阈值,大于此值认为是同一人
|
|||
|
|
"""
|
|||
|
|
self.extractor = FaceFeatureExtractor()
|
|||
|
|
self.threshold = threshold
|
|||
|
|
self.database = {} # 存储已注册的人脸特征
|
|||
|
|
|
|||
|
|
def register(self, name, image):
|
|||
|
|
"""
|
|||
|
|
注册人脸
|
|||
|
|
|
|||
|
|
Args:
|
|||
|
|
name: 姓名
|
|||
|
|
image: 人脸图像
|
|||
|
|
|
|||
|
|
Returns:
|
|||
|
|
bool: 是否注册成功
|
|||
|
|
"""
|
|||
|
|
feature = self.extractor.extract_single_feature(image)
|
|||
|
|
|
|||
|
|
if feature is not None:
|
|||
|
|
self.database[name] = feature
|
|||
|
|
print(f"✓ {name} 注册成功")
|
|||
|
|
return True
|
|||
|
|
else:
|
|||
|
|
print(f"✗ {name} 注册失败(质量检查未通过)")
|
|||
|
|
return False
|
|||
|
|
|
|||
|
|
def recognize(self, image):
|
|||
|
|
"""
|
|||
|
|
识别人脸
|
|||
|
|
|
|||
|
|
Args:
|
|||
|
|
image: 待识别的人脸图像
|
|||
|
|
|
|||
|
|
Returns:
|
|||
|
|
tuple: (姓名, 相似度) 或 (None, 0.0)
|
|||
|
|
"""
|
|||
|
|
if not self.database:
|
|||
|
|
print("✗ 数据库为空,请先注册人脸")
|
|||
|
|
return None, 0.0
|
|||
|
|
|
|||
|
|
# 提取待识别人脸特征
|
|||
|
|
unknown_feature = self.extractor.extract_single_feature(image)
|
|||
|
|
|
|||
|
|
if unknown_feature is None:
|
|||
|
|
print("✗ 未检测到人脸或质量不合格")
|
|||
|
|
return None, 0.0
|
|||
|
|
|
|||
|
|
# 计算与数据库中所有人脸的相似度
|
|||
|
|
best_match = None
|
|||
|
|
best_similarity = 0.0
|
|||
|
|
|
|||
|
|
for name, known_feature in self.database.items():
|
|||
|
|
# 计算余弦相似度(特征已归一化,所以直接点乘)
|
|||
|
|
similarity = np.dot(unknown_feature, known_feature)
|
|||
|
|
|
|||
|
|
if similarity > best_similarity:
|
|||
|
|
best_similarity = similarity
|
|||
|
|
best_match = name
|
|||
|
|
|
|||
|
|
# 判断是否超过阈值
|
|||
|
|
if best_similarity >= self.threshold:
|
|||
|
|
return best_match, best_similarity
|
|||
|
|
else:
|
|||
|
|
return None, best_similarity
|
|||
|
|
|
|||
|
|
def get_database_info(self):
|
|||
|
|
"""获取数据库信息"""
|
|||
|
|
return {
|
|||
|
|
'total_persons': len(self.database),
|
|||
|
|
'persons': list(self.database.keys())
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
def main():
|
|||
|
|
"""主函数"""
|
|||
|
|
|
|||
|
|
print("=" * 60)
|
|||
|
|
print("人脸识别演示")
|
|||
|
|
print("=" * 60)
|
|||
|
|
|
|||
|
|
# 创建识别器
|
|||
|
|
recognizer = SimpleFaceRecognizer(threshold=0.7)
|
|||
|
|
|
|||
|
|
# 示例1: 注册人脸
|
|||
|
|
print("\n步骤1: 注册人脸到数据库")
|
|||
|
|
print("-" * 60)
|
|||
|
|
|
|||
|
|
# 这里需要替换为实际的图像路径
|
|||
|
|
registration_data = [
|
|||
|
|
("袁中群", "1.jpg"),
|
|||
|
|
("袁慧", "yh.jpg"),
|
|||
|
|
("曾其乐", "zql.jpg"),
|
|||
|
|
]
|
|||
|
|
|
|||
|
|
for name, image_path in registration_data:
|
|||
|
|
if os.path.exists(image_path):
|
|||
|
|
image = cv2.imread(image_path)
|
|||
|
|
if image is not None:
|
|||
|
|
recognizer.register(name, image)
|
|||
|
|
else:
|
|||
|
|
print(f"⚠ 图像文件不存在: {image_path}")
|
|||
|
|
|
|||
|
|
# 显示数据库信息
|
|||
|
|
db_info = recognizer.get_database_info()
|
|||
|
|
print(f"\n数据库状态:")
|
|||
|
|
print(f" 已注册人数: {db_info['total_persons']}")
|
|||
|
|
print(f" 人员列表: {', '.join(db_info['persons'])}")
|
|||
|
|
|
|||
|
|
# 示例2: 人脸识别
|
|||
|
|
print("\n步骤2: 识别人脸")
|
|||
|
|
print("-" * 60)
|
|||
|
|
|
|||
|
|
test_images = [
|
|||
|
|
"2.jpg",
|
|||
|
|
# "test_person2.jpg",
|
|||
|
|
# "unknown_person.jpg",
|
|||
|
|
]
|
|||
|
|
|
|||
|
|
for test_image_path in test_images:
|
|||
|
|
if not os.path.exists(test_image_path):
|
|||
|
|
print(f"⚠ 测试图像不存在: {test_image_path}")
|
|||
|
|
continue
|
|||
|
|
|
|||
|
|
test_image = cv2.imread(test_image_path)
|
|||
|
|
if test_image is None:
|
|||
|
|
print(f"✗ 无法读取图像: {test_image_path}")
|
|||
|
|
continue
|
|||
|
|
|
|||
|
|
print(f"\n识别图像: {test_image_path}")
|
|||
|
|
name, similarity = recognizer.recognize(test_image)
|
|||
|
|
|
|||
|
|
if name:
|
|||
|
|
print(f"✓ 识别结果: {name} (相似度: {similarity:.4f})")
|
|||
|
|
else:
|
|||
|
|
print(f"✗ 未识别到已注册人员 (最高相似度: {similarity:.4f})")
|
|||
|
|
|
|||
|
|
# 示例3: 批量识别
|
|||
|
|
print("\n步骤3: 批量处理")
|
|||
|
|
print("-" * 60)
|
|||
|
|
|
|||
|
|
batch_dir = "./test_faces/"
|
|||
|
|
if os.path.exists(batch_dir):
|
|||
|
|
results = []
|
|||
|
|
for filename in os.listdir(batch_dir):
|
|||
|
|
if filename.lower().endswith(('.jpg', '.jpeg', '.png')):
|
|||
|
|
image_path = os.path.join(batch_dir, filename)
|
|||
|
|
image = cv2.imread(image_path)
|
|||
|
|
if image is not None:
|
|||
|
|
name, similarity = recognizer.recognize(image)
|
|||
|
|
results.append({
|
|||
|
|
'filename': filename,
|
|||
|
|
'name': name,
|
|||
|
|
'similarity': similarity
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
# 输出批量结果
|
|||
|
|
print(f"批量处理完成,共处理 {len(results)} 张图像")
|
|||
|
|
for result in results:
|
|||
|
|
status = "✓" if result['name'] else "✗"
|
|||
|
|
name = result['name'] if result['name'] else "未知"
|
|||
|
|
print(f"{status} {result['filename']}: {name} ({result['similarity']:.4f})")
|
|||
|
|
else:
|
|||
|
|
print(f"⚠ 批量处理目录不存在: {batch_dir}")
|
|||
|
|
|
|||
|
|
|
|||
|
|
if __name__ == "__main__":
|
|||
|
|
main()
|