| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482 |
- #!/usr/bin/env python3
- """
- DeepFace人脸识别Demo
- 功能:
- 1. 摄像头实时人脸识别(输出名字、年龄、性别、情绪)
- 2. 照片人脸识别
- 3. 人脸注册到数据库
- """
- import cv2
- import numpy as np
- import os
- import time
- import argparse
- from deepface import DeepFace
- import pickle
- from pathlib import Path
- class DeepFaceDemo:
- """DeepFace人脸识别Demo类"""
-
- def __init__(self, db_path="face_database.pkl", detector_backend="opencv"):
- """
- 初始化DeepFace Demo
-
- Args:
- db_path: 人脸数据库保存路径
- detector_backend: 人脸检测后端(opencv, ssd, mtcnn, retinaface等)
- """
- self.db_path = db_path
- self.detector_backend = detector_backend
- self.face_database = {}
- self.load_database()
-
- print(f"DeepFace Demo初始化完成")
- print(f"检测后端: {detector_backend}")
- print(f"数据库路径: {db_path}")
- print(f"已加载 {len(self.face_database)} 张人脸")
-
- def load_database(self):
- """从文件加载人脸数据库"""
- if os.path.exists(self.db_path):
- try:
- with open(self.db_path, 'rb') as f:
- self.face_database = pickle.load(f)
- print(f"从 {self.db_path} 加载了 {len(self.face_database)} 张人脸")
- except Exception as e:
- print(f"加载数据库失败: {e}")
- self.face_database = {}
- else:
- print(f"未找到数据库文件 {self.db_path},将创建新数据库")
- self.face_database = {}
-
- def save_database(self):
- """保存人脸数据库到文件"""
- try:
- with open(self.db_path, 'wb') as f:
- pickle.dump(self.face_database, f)
- print(f"人脸数据库已保存到 {self.db_path}")
- return True
- except Exception as e:
- print(f"保存数据库失败: {e}")
- return False
-
- def analyze_face(self, image):
- """
- 分析人脸属性(年龄、性别、情绪、种族)
-
- Args:
- image: 图像(numpy数组或文件路径)
-
- Returns:
- dict: 包含年龄、性别、情绪等信息的字典
- """
- try:
- result = DeepFace.analyze(
- image,
- actions=['age', 'gender', 'emotion', 'race'],
- detector_backend=self.detector_backend,
- enforce_detection=False
- )
- return result
- except Exception as e:
- print(f"分析人脸时出错: {e}")
- return None
-
- def recognize_face(self, image, threshold=0.4):
- """
- 识别人脸,返回最匹配的名字
-
- Args:
- image: 图像(numpy数组或文件路径)
- threshold: 识别阈值
-
- Returns:
- tuple: (name, confidence) - 识别出的名字和置信度
- """
- if not self.face_database:
- return "Unknown", 0.0
-
- try:
- # 在数据库中查找匹配的人脸
- dfs = DeepFace.find(
- image,
- db_path="database",
- detector_backend=self.detector_backend,
- enforce_detection=False
- )
-
- if dfs is not None and len(dfs) > 0 and not dfs[0].empty:
- # 获取最佳匹配
- best_match = dfs[0].iloc[0]
- confidence = best_match['distance']
-
- # 从文件名中提取名字
- identity = best_match['identity']
- name = os.path.basename(os.path.dirname(identity))
-
- # 如果距离小于阈值,则认为是匹配
- if confidence < threshold:
- return name, confidence
-
- return "Unknown", 0.0
-
- except Exception as e:
- print(f"识别人脸时出错: {e}")
- return "Unknown", 0.0
-
- def register_face(self, image_path, name):
- """
- 注册人脸到数据库
-
- Args:
- image_path: 人脸图像路径
- name: 人脸名字
-
- Returns:
- bool: 注册成功返回True
- """
- try:
- # 创建数据库目录
- db_dir = Path("database") / name
- db_dir.mkdir(parents=True, exist_ok=True)
-
- # 复制图像到数据库
- img = cv2.imread(image_path)
- if img is None:
- print(f"无法读取图像: {image_path}")
- return False
-
- # 保存图像到数据库
- save_path = db_dir / f"{name}_{int(time.time())}.jpg"
- cv2.imwrite(str(save_path), img)
-
- # 更新内存数据库
- self.face_database[name] = str(save_path)
-
- print(f"成功注册人脸: {name} -> {save_path}")
- return True
-
- except Exception as e:
- print(f"注册人脸时出错: {e}")
- return False
-
- def register_face_from_frame(self, frame, name):
- """
- 从摄像头帧注册人脸
-
- Args:
- frame: 图像帧
- name: 人脸名字
-
- Returns:
- bool: 注册成功返回True
- """
- try:
- # 创建数据库目录
- db_dir = Path("database") / name
- db_dir.mkdir(parents=True, exist_ok=True)
-
- # 保存图像到数据库
- save_path = db_dir / f"{name}_{int(time.time())}.jpg"
- cv2.imwrite(str(save_path), frame)
-
- # 更新内存数据库
- self.face_database[name] = str(save_path)
-
- print(f"成功注册人脸: {name} -> {save_path}")
- return True
-
- except Exception as e:
- print(f"从帧注册人脸时出错: {e}")
- return False
-
- def process_image(self, image_path):
- """
- 处理单张图像,显示人脸分析结果
-
- Args:
- image_path: 图像路径
- """
- print(f"\n处理图像: {image_path}")
-
- # 读取图像
- img = cv2.imread(image_path)
- if img is None:
- print(f"无法读取图像: {image_path}")
- return
-
- # 分析人脸
- result = self.analyze_face(img)
-
- if result is None or len(result) == 0:
- print("未检测到人脸")
- return
-
- # 处理每个检测到的人脸
- for i, face_info in enumerate(result):
- print(f"\n人脸 {i + 1}:")
- print(f" 年龄: {face_info.get('age', 'N/A')}")
- print(f" 性别: {face_info.get('dominant_gender', 'N/A')}")
- print(f" 情绪: {face_info.get('dominant_emotion', 'N/A')}")
- print(f" 种族: {face_info.get('dominant_race', 'N/A')}")
-
- # 识别人脸
- name, confidence = self.recognize_face(img)
- print(f" 识别: {name} (置信度: {confidence:.3f})")
-
- # 绘制结果
- if 'region' in face_info:
- region = face_info['region']
- x, y, w, h = region['x'], region['y'], region['w'], region['h']
-
- # 绘制人脸框
- cv2.rectangle(img, (x, y), (x + w, y + h), (0, 255, 0), 2)
-
- # 准备显示文本
- text_lines = [
- f"{name}",
- f"Age: {face_info.get('age', 'N/A')}",
- f"Gender: {face_info.get('dominant_gender', 'N/A')}",
- f"Emotion: {face_info.get('dominant_emotion', 'N/A')}"
- ]
-
- # 绘制文本
- for j, line in enumerate(text_lines):
- cv2.putText(img, line, (x, y - 10 - j * 20),
- cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 1)
-
- # 显示结果
- cv2.imshow('Face Recognition Result', img)
- cv2.waitKey(0)
- cv2.destroyAllWindows()
-
- def run_camera(self, camera_id=0, enable_recognition=True):
- """
- 运行摄像头实时人脸识别
-
- Args:
- camera_id: 摄像头ID
- enable_recognition: 是否启用人脸识别(否则只显示分析结果)
- """
- print(f"\n打开摄像头 {camera_id}...")
-
- # 打开摄像头
- cap = cv2.VideoCapture(camera_id)
- if not cap.isOpened():
- print(f"无法打开摄像头 {camera_id}")
- return
-
- # 设置摄像头参数
- cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640)
- cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480)
- cap.set(cv2.CAP_PROP_FPS, 30)
-
- # 等待摄像头稳定
- time.sleep(1)
-
- print("开始实时人脸识别")
- print("按 'q' 键退出")
- print("按 's' 键保存当前帧")
- print("按 'r' 键注册当前人脸")
-
- frame_count = 0
- fps_start_time = time.time()
-
- while True:
- # 读取帧
- ret, frame = cap.read()
- if not ret:
- print("无法读取帧")
- break
-
- frame_count += 1
-
- # 计算FPS
- if frame_count % 30 == 0:
- fps = 30 / (time.time() - fps_start_time)
- fps_start_time = time.time()
- print(f"FPS: {fps:.1f}")
-
- # 分析人脸
- result = self.analyze_face(frame)
-
- if result is not None and len(result) > 0:
- for face_info in result:
- # 获取人脸区域
- if 'region' in face_info:
- region = face_info['region']
- x, y, w, h = region['x'], region['y'], region['w'], region['h']
-
- # 绘制人脸框
- cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 255, 0), 2)
-
- # 获取属性
- age = face_info.get('age', 'N/A')
- gender = face_info.get('dominant_gender', 'N/A')
- emotion = face_info.get('dominant_emotion', 'N/A')
-
- # 识别人脸(如果启用)
- if enable_recognition:
- name, confidence = self.recognize_face(frame)
- display_name = name
- else:
- display_name = "Unknown"
-
- # 准备显示文本
- text_lines = [
- f"{display_name}",
- f"Age: {age}",
- f"Gender: {gender}",
- f"Emotion: {emotion}"
- ]
-
- # 绘制文本
- for j, line in enumerate(text_lines):
- cv2.putText(frame, line, (x, y - 10 - j * 20),
- cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 1)
-
- # 显示帧
- cv2.imshow('DeepFace Real-time Recognition', frame)
-
- # 键盘控制
- key = cv2.waitKey(1) & 0xFF
- if key == ord('q'):
- print("退出...")
- break
- elif key == ord('s'):
- # 保存当前帧
- save_path = f"capture_{int(time.time())}.jpg"
- cv2.imwrite(save_path, frame)
- print(f"已保存帧到: {save_path}")
- elif key == ord('r'):
- # 注册当前人脸
- name = input("请输入要注册的名字: ")
- if name:
- if self.register_face_from_frame(frame, name):
- self.save_database()
- print(f"成功注册: {name}")
-
- # 释放资源
- cap.release()
- cv2.destroyAllWindows()
-
- # 保存数据库
- self.save_database()
-
- def register_from_camera(self, camera_id=0):
- """
- 从摄像头注册人脸
-
- Args:
- camera_id: 摄像头ID
- """
- print(f"\n打开摄像头 {camera_id} 进行人脸注册...")
-
- # 打开摄像头
- cap = cv2.VideoCapture(camera_id)
- if not cap.isOpened():
- print(f"无法打开摄像头 {camera_id}")
- return
-
- # 设置摄像头参数
- cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640)
- cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480)
-
- # 等待摄像头稳定
- time.sleep(1)
-
- print("按 'c' 键捕获人脸,按 'q' 键退出")
-
- while True:
- # 读取帧
- ret, frame = cap.read()
- if not ret:
- print("无法读取帧")
- break
-
- # 显示帧
- cv2.imshow('Register Face', frame)
-
- # 键盘控制
- key = cv2.waitKey(1) & 0xFF
- if key == ord('q'):
- print("退出...")
- break
- elif key == ord('c'):
- # 捕获并注册人脸
- name = input("请输入要注册的名字: ")
- if name:
- if self.register_face_from_frame(frame, name):
- self.save_database()
- print(f"成功注册: {name}")
- else:
- print("注册失败")
-
- # 释放资源
- cap.release()
- cv2.destroyAllWindows()
- def main():
- """主函数"""
- parser = argparse.ArgumentParser(description="DeepFace人脸识别Demo")
- parser.add_argument("--camera", type=int, default=None,
- help="使用摄像头进行实时识别(指定摄像头ID)")
- parser.add_argument("--image", type=str, default=None,
- help="处理单张图像")
- parser.add_argument("--register", type=str, default=None,
- help="注册人脸(图像路径)")
- parser.add_argument("--register-camera", type=int, default=None,
- help="从摄像头注册人脸(指定摄像头ID)")
- parser.add_argument("--name", type=str, default=None,
- help="注册时使用的名字")
- parser.add_argument("--db-path", type=str, default="face_database.pkl",
- help="人脸数据库路径")
- parser.add_argument("--detector", type=str, default="opencv",
- choices=["opencv", "ssd", "mtcnn", "retinaface", "mediapipe"],
- help="人脸检测后端")
- parser.add_argument("--no-recognition", action="store_true",
- help="禁用人脸识别(只显示分析结果)")
-
- args = parser.parse_args()
-
- # 创建DeepFace Demo实例
- demo = DeepFaceDemo(db_path=args.db_path, detector_backend=args.detector)
-
- # 根据参数执行不同操作
- if args.register:
- # 注册人脸
- if args.name is None:
- args.name = input("请输入要注册的名字: ")
- if demo.register_face(args.register, args.name):
- demo.save_database()
- print(f"成功注册: {args.name}")
- else:
- print("注册失败")
-
- elif args.register_camera is not None:
- # 从摄像头注册人脸
- if args.name is None:
- args.name = input("请输入要注册的名字: ")
- demo.register_from_camera(args.register_camera)
-
- elif args.camera is not None:
- # 运行摄像头实时识别
- enable_recognition = not args.no_recognition
- demo.run_camera(camera_id=args.camera, enable_recognition=enable_recognition)
-
- elif args.image:
- # 处理单张图像
- demo.process_image(args.image)
-
- else:
- # 默认运行摄像头
- print("未指定操作,运行摄像头实时识别...")
- demo.run_camera(camera_id=0)
- if __name__ == "__main__":
- main()
|