deepface_demo.py 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482
  1. #!/usr/bin/env python3
  2. """
  3. DeepFace人脸识别Demo
  4. 功能:
  5. 1. 摄像头实时人脸识别(输出名字、年龄、性别、情绪)
  6. 2. 照片人脸识别
  7. 3. 人脸注册到数据库
  8. """
  9. import cv2
  10. import numpy as np
  11. import os
  12. import time
  13. import argparse
  14. from deepface import DeepFace
  15. import pickle
  16. from pathlib import Path
  17. class DeepFaceDemo:
  18. """DeepFace人脸识别Demo类"""
  19. def __init__(self, db_path="face_database.pkl", detector_backend="opencv"):
  20. """
  21. 初始化DeepFace Demo
  22. Args:
  23. db_path: 人脸数据库保存路径
  24. detector_backend: 人脸检测后端(opencv, ssd, mtcnn, retinaface等)
  25. """
  26. self.db_path = db_path
  27. self.detector_backend = detector_backend
  28. self.face_database = {}
  29. self.load_database()
  30. print(f"DeepFace Demo初始化完成")
  31. print(f"检测后端: {detector_backend}")
  32. print(f"数据库路径: {db_path}")
  33. print(f"已加载 {len(self.face_database)} 张人脸")
  34. def load_database(self):
  35. """从文件加载人脸数据库"""
  36. if os.path.exists(self.db_path):
  37. try:
  38. with open(self.db_path, 'rb') as f:
  39. self.face_database = pickle.load(f)
  40. print(f"从 {self.db_path} 加载了 {len(self.face_database)} 张人脸")
  41. except Exception as e:
  42. print(f"加载数据库失败: {e}")
  43. self.face_database = {}
  44. else:
  45. print(f"未找到数据库文件 {self.db_path},将创建新数据库")
  46. self.face_database = {}
  47. def save_database(self):
  48. """保存人脸数据库到文件"""
  49. try:
  50. with open(self.db_path, 'wb') as f:
  51. pickle.dump(self.face_database, f)
  52. print(f"人脸数据库已保存到 {self.db_path}")
  53. return True
  54. except Exception as e:
  55. print(f"保存数据库失败: {e}")
  56. return False
  57. def analyze_face(self, image):
  58. """
  59. 分析人脸属性(年龄、性别、情绪、种族)
  60. Args:
  61. image: 图像(numpy数组或文件路径)
  62. Returns:
  63. dict: 包含年龄、性别、情绪等信息的字典
  64. """
  65. try:
  66. result = DeepFace.analyze(
  67. image,
  68. actions=['age', 'gender', 'emotion', 'race'],
  69. detector_backend=self.detector_backend,
  70. enforce_detection=False
  71. )
  72. return result
  73. except Exception as e:
  74. print(f"分析人脸时出错: {e}")
  75. return None
  76. def recognize_face(self, image, threshold=0.4):
  77. """
  78. 识别人脸,返回最匹配的名字
  79. Args:
  80. image: 图像(numpy数组或文件路径)
  81. threshold: 识别阈值
  82. Returns:
  83. tuple: (name, confidence) - 识别出的名字和置信度
  84. """
  85. if not self.face_database:
  86. return "Unknown", 0.0
  87. try:
  88. # 在数据库中查找匹配的人脸
  89. dfs = DeepFace.find(
  90. image,
  91. db_path="database",
  92. detector_backend=self.detector_backend,
  93. enforce_detection=False
  94. )
  95. if dfs is not None and len(dfs) > 0 and not dfs[0].empty:
  96. # 获取最佳匹配
  97. best_match = dfs[0].iloc[0]
  98. confidence = best_match['distance']
  99. # 从文件名中提取名字
  100. identity = best_match['identity']
  101. name = os.path.basename(os.path.dirname(identity))
  102. # 如果距离小于阈值,则认为是匹配
  103. if confidence < threshold:
  104. return name, confidence
  105. return "Unknown", 0.0
  106. except Exception as e:
  107. print(f"识别人脸时出错: {e}")
  108. return "Unknown", 0.0
  109. def register_face(self, image_path, name):
  110. """
  111. 注册人脸到数据库
  112. Args:
  113. image_path: 人脸图像路径
  114. name: 人脸名字
  115. Returns:
  116. bool: 注册成功返回True
  117. """
  118. try:
  119. # 创建数据库目录
  120. db_dir = Path("database") / name
  121. db_dir.mkdir(parents=True, exist_ok=True)
  122. # 复制图像到数据库
  123. img = cv2.imread(image_path)
  124. if img is None:
  125. print(f"无法读取图像: {image_path}")
  126. return False
  127. # 保存图像到数据库
  128. save_path = db_dir / f"{name}_{int(time.time())}.jpg"
  129. cv2.imwrite(str(save_path), img)
  130. # 更新内存数据库
  131. self.face_database[name] = str(save_path)
  132. print(f"成功注册人脸: {name} -> {save_path}")
  133. return True
  134. except Exception as e:
  135. print(f"注册人脸时出错: {e}")
  136. return False
  137. def register_face_from_frame(self, frame, name):
  138. """
  139. 从摄像头帧注册人脸
  140. Args:
  141. frame: 图像帧
  142. name: 人脸名字
  143. Returns:
  144. bool: 注册成功返回True
  145. """
  146. try:
  147. # 创建数据库目录
  148. db_dir = Path("database") / name
  149. db_dir.mkdir(parents=True, exist_ok=True)
  150. # 保存图像到数据库
  151. save_path = db_dir / f"{name}_{int(time.time())}.jpg"
  152. cv2.imwrite(str(save_path), frame)
  153. # 更新内存数据库
  154. self.face_database[name] = str(save_path)
  155. print(f"成功注册人脸: {name} -> {save_path}")
  156. return True
  157. except Exception as e:
  158. print(f"从帧注册人脸时出错: {e}")
  159. return False
  160. def process_image(self, image_path):
  161. """
  162. 处理单张图像,显示人脸分析结果
  163. Args:
  164. image_path: 图像路径
  165. """
  166. print(f"\n处理图像: {image_path}")
  167. # 读取图像
  168. img = cv2.imread(image_path)
  169. if img is None:
  170. print(f"无法读取图像: {image_path}")
  171. return
  172. # 分析人脸
  173. result = self.analyze_face(img)
  174. if result is None or len(result) == 0:
  175. print("未检测到人脸")
  176. return
  177. # 处理每个检测到的人脸
  178. for i, face_info in enumerate(result):
  179. print(f"\n人脸 {i + 1}:")
  180. print(f" 年龄: {face_info.get('age', 'N/A')}")
  181. print(f" 性别: {face_info.get('dominant_gender', 'N/A')}")
  182. print(f" 情绪: {face_info.get('dominant_emotion', 'N/A')}")
  183. print(f" 种族: {face_info.get('dominant_race', 'N/A')}")
  184. # 识别人脸
  185. name, confidence = self.recognize_face(img)
  186. print(f" 识别: {name} (置信度: {confidence:.3f})")
  187. # 绘制结果
  188. if 'region' in face_info:
  189. region = face_info['region']
  190. x, y, w, h = region['x'], region['y'], region['w'], region['h']
  191. # 绘制人脸框
  192. cv2.rectangle(img, (x, y), (x + w, y + h), (0, 255, 0), 2)
  193. # 准备显示文本
  194. text_lines = [
  195. f"{name}",
  196. f"Age: {face_info.get('age', 'N/A')}",
  197. f"Gender: {face_info.get('dominant_gender', 'N/A')}",
  198. f"Emotion: {face_info.get('dominant_emotion', 'N/A')}"
  199. ]
  200. # 绘制文本
  201. for j, line in enumerate(text_lines):
  202. cv2.putText(img, line, (x, y - 10 - j * 20),
  203. cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 1)
  204. # 显示结果
  205. cv2.imshow('Face Recognition Result', img)
  206. cv2.waitKey(0)
  207. cv2.destroyAllWindows()
  208. def run_camera(self, camera_id=0, enable_recognition=True):
  209. """
  210. 运行摄像头实时人脸识别
  211. Args:
  212. camera_id: 摄像头ID
  213. enable_recognition: 是否启用人脸识别(否则只显示分析结果)
  214. """
  215. print(f"\n打开摄像头 {camera_id}...")
  216. # 打开摄像头
  217. cap = cv2.VideoCapture(camera_id)
  218. if not cap.isOpened():
  219. print(f"无法打开摄像头 {camera_id}")
  220. return
  221. # 设置摄像头参数
  222. cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640)
  223. cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480)
  224. cap.set(cv2.CAP_PROP_FPS, 30)
  225. # 等待摄像头稳定
  226. time.sleep(1)
  227. print("开始实时人脸识别")
  228. print("按 'q' 键退出")
  229. print("按 's' 键保存当前帧")
  230. print("按 'r' 键注册当前人脸")
  231. frame_count = 0
  232. fps_start_time = time.time()
  233. while True:
  234. # 读取帧
  235. ret, frame = cap.read()
  236. if not ret:
  237. print("无法读取帧")
  238. break
  239. frame_count += 1
  240. # 计算FPS
  241. if frame_count % 30 == 0:
  242. fps = 30 / (time.time() - fps_start_time)
  243. fps_start_time = time.time()
  244. print(f"FPS: {fps:.1f}")
  245. # 分析人脸
  246. result = self.analyze_face(frame)
  247. if result is not None and len(result) > 0:
  248. for face_info in result:
  249. # 获取人脸区域
  250. if 'region' in face_info:
  251. region = face_info['region']
  252. x, y, w, h = region['x'], region['y'], region['w'], region['h']
  253. # 绘制人脸框
  254. cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 255, 0), 2)
  255. # 获取属性
  256. age = face_info.get('age', 'N/A')
  257. gender = face_info.get('dominant_gender', 'N/A')
  258. emotion = face_info.get('dominant_emotion', 'N/A')
  259. # 识别人脸(如果启用)
  260. if enable_recognition:
  261. name, confidence = self.recognize_face(frame)
  262. display_name = name
  263. else:
  264. display_name = "Unknown"
  265. # 准备显示文本
  266. text_lines = [
  267. f"{display_name}",
  268. f"Age: {age}",
  269. f"Gender: {gender}",
  270. f"Emotion: {emotion}"
  271. ]
  272. # 绘制文本
  273. for j, line in enumerate(text_lines):
  274. cv2.putText(frame, line, (x, y - 10 - j * 20),
  275. cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 1)
  276. # 显示帧
  277. cv2.imshow('DeepFace Real-time Recognition', frame)
  278. # 键盘控制
  279. key = cv2.waitKey(1) & 0xFF
  280. if key == ord('q'):
  281. print("退出...")
  282. break
  283. elif key == ord('s'):
  284. # 保存当前帧
  285. save_path = f"capture_{int(time.time())}.jpg"
  286. cv2.imwrite(save_path, frame)
  287. print(f"已保存帧到: {save_path}")
  288. elif key == ord('r'):
  289. # 注册当前人脸
  290. name = input("请输入要注册的名字: ")
  291. if name:
  292. if self.register_face_from_frame(frame, name):
  293. self.save_database()
  294. print(f"成功注册: {name}")
  295. # 释放资源
  296. cap.release()
  297. cv2.destroyAllWindows()
  298. # 保存数据库
  299. self.save_database()
  300. def register_from_camera(self, camera_id=0):
  301. """
  302. 从摄像头注册人脸
  303. Args:
  304. camera_id: 摄像头ID
  305. """
  306. print(f"\n打开摄像头 {camera_id} 进行人脸注册...")
  307. # 打开摄像头
  308. cap = cv2.VideoCapture(camera_id)
  309. if not cap.isOpened():
  310. print(f"无法打开摄像头 {camera_id}")
  311. return
  312. # 设置摄像头参数
  313. cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640)
  314. cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480)
  315. # 等待摄像头稳定
  316. time.sleep(1)
  317. print("按 'c' 键捕获人脸,按 'q' 键退出")
  318. while True:
  319. # 读取帧
  320. ret, frame = cap.read()
  321. if not ret:
  322. print("无法读取帧")
  323. break
  324. # 显示帧
  325. cv2.imshow('Register Face', frame)
  326. # 键盘控制
  327. key = cv2.waitKey(1) & 0xFF
  328. if key == ord('q'):
  329. print("退出...")
  330. break
  331. elif key == ord('c'):
  332. # 捕获并注册人脸
  333. name = input("请输入要注册的名字: ")
  334. if name:
  335. if self.register_face_from_frame(frame, name):
  336. self.save_database()
  337. print(f"成功注册: {name}")
  338. else:
  339. print("注册失败")
  340. # 释放资源
  341. cap.release()
  342. cv2.destroyAllWindows()
  343. def main():
  344. """主函数"""
  345. parser = argparse.ArgumentParser(description="DeepFace人脸识别Demo")
  346. parser.add_argument("--camera", type=int, default=None,
  347. help="使用摄像头进行实时识别(指定摄像头ID)")
  348. parser.add_argument("--image", type=str, default=None,
  349. help="处理单张图像")
  350. parser.add_argument("--register", type=str, default=None,
  351. help="注册人脸(图像路径)")
  352. parser.add_argument("--register-camera", type=int, default=None,
  353. help="从摄像头注册人脸(指定摄像头ID)")
  354. parser.add_argument("--name", type=str, default=None,
  355. help="注册时使用的名字")
  356. parser.add_argument("--db-path", type=str, default="face_database.pkl",
  357. help="人脸数据库路径")
  358. parser.add_argument("--detector", type=str, default="opencv",
  359. choices=["opencv", "ssd", "mtcnn", "retinaface", "mediapipe"],
  360. help="人脸检测后端")
  361. parser.add_argument("--no-recognition", action="store_true",
  362. help="禁用人脸识别(只显示分析结果)")
  363. args = parser.parse_args()
  364. # 创建DeepFace Demo实例
  365. demo = DeepFaceDemo(db_path=args.db_path, detector_backend=args.detector)
  366. # 根据参数执行不同操作
  367. if args.register:
  368. # 注册人脸
  369. if args.name is None:
  370. args.name = input("请输入要注册的名字: ")
  371. if demo.register_face(args.register, args.name):
  372. demo.save_database()
  373. print(f"成功注册: {args.name}")
  374. else:
  375. print("注册失败")
  376. elif args.register_camera is not None:
  377. # 从摄像头注册人脸
  378. if args.name is None:
  379. args.name = input("请输入要注册的名字: ")
  380. demo.register_from_camera(args.register_camera)
  381. elif args.camera is not None:
  382. # 运行摄像头实时识别
  383. enable_recognition = not args.no_recognition
  384. demo.run_camera(camera_id=args.camera, enable_recognition=enable_recognition)
  385. elif args.image:
  386. # 处理单张图像
  387. demo.process_image(args.image)
  388. else:
  389. # 默认运行摄像头
  390. print("未指定操作,运行摄像头实时识别...")
  391. demo.run_camera(camera_id=0)
  392. if __name__ == "__main__":
  393. main()