From a96c78673f38f2d9ac3ad538dc5686a7d2553f0c Mon Sep 17 00:00:00 2001 From: Liu-Kui111 <2072827579@qq.com> Date: Sun, 14 Dec 2025 20:54:44 +0800 Subject: [PATCH 1/2] =?UTF-8?q?=E6=8F=90=E4=BA=A4=E9=80=89=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/AI_Drone_Face_Recognition_Human_Tracking/README.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 src/AI_Drone_Face_Recognition_Human_Tracking/README.md diff --git a/src/AI_Drone_Face_Recognition_Human_Tracking/README.md b/src/AI_Drone_Face_Recognition_Human_Tracking/README.md new file mode 100644 index 0000000000..bdca2970c7 --- /dev/null +++ b/src/AI_Drone_Face_Recognition_Human_Tracking/README.md @@ -0,0 +1 @@ +该项目是一个基于人工智能的无人机控制系统,能够用YOLOv8检测图像中的人物,用OpenCV检测人脸,用DeepFace识别人,并能飞近用户从视频流中选定的目标。 \ No newline at end of file From e57010ea6a277e5d4dffbe63eec50e3615a86c56 Mon Sep 17 00:00:00 2001 From: Liu-Kui111 <2072827579@qq.com> Date: Mon, 15 Dec 2025 09:57:24 +0800 Subject: [PATCH 2/2] =?UTF-8?q?=E6=89=93=E5=BC=80=E6=91=84=E5=83=8F?= =?UTF-8?q?=E5=A4=B4=EF=BC=8C=E5=BD=95=E5=85=A5=E5=B9=B6=E4=BF=9D=E5=AD=98?= =?UTF-8?q?=E4=BA=BA=E8=84=B8=E5=8F=8A=E5=90=8D=E5=AD=97=EF=BC=8C=E6=94=BE?= =?UTF-8?q?=E5=85=A5=E6=95=B0=E6=8D=AE=E9=9B=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../utils.py.py | 160 ++++++++++++++++++ 1 file changed, 160 insertions(+) create mode 100644 src/AI_Drone_Face_Recognition_Human_Tracking/utils.py.py diff --git a/src/AI_Drone_Face_Recognition_Human_Tracking/utils.py.py b/src/AI_Drone_Face_Recognition_Human_Tracking/utils.py.py new file mode 100644 index 0000000000..e7962cbefe --- /dev/null +++ b/src/AI_Drone_Face_Recognition_Human_Tracking/utils.py.py @@ -0,0 +1,160 @@ +import os +import cv2 +from deepface import DeepFace +import numpy as np + + +class FaceDB: + """人脸数据库管理类""" + + def __init__(self, face_dir="faces"): + self.face_dir = face_dir + self.face_data = {} # 存储{人名: 人脸特征} + self._load_face_database() + + def _load_face_database(self): + """加载人脸库中的所有人脸特征""" + if not os.path.exists(self.face_dir): + os.makedirs(self.face_dir) + print(f"创建人脸库目录: {self.face_dir}") + + self.face_data.clear() # 清空旧数据 + for img_name in os.listdir(self.face_dir): + if img_name.endswith((".jpg", ".png")): + person_name = os.path.splitext(img_name)[0] + img_path = os.path.join(self.face_dir, img_name) + try: + # 提取人脸特征(Facenet模型) + embedding = DeepFace.represent( + img_path, + model_name="Facenet", + enforce_detection=True + )[0]["embedding"] + self.face_data[person_name] = embedding + print(f"✅ 成功加载人脸: {person_name}") + except Exception as e: + print(f"❌ 加载{img_name}失败: {str(e)[:50]}...") + + def recognize_face(self, frame, threshold=0.6): + """识别人脸,返回匹配的人名或None""" + try: + # 提取当前帧人脸特征 + frame_embedding = DeepFace.represent( + frame, + model_name="Facenet", + enforce_detection=True + )[0]["embedding"] + + # 对比人脸库(计算欧式距离) + min_distance = float("inf") + matched_name = None + for name, embedding in self.face_data.items(): + distance = np.linalg.norm(np.array(frame_embedding) - np.array(embedding)) + if distance < min_distance and distance < threshold: + min_distance = distance + matched_name = name + return matched_name, min_distance # 新增返回距离,方便调试 + except Exception as e: + print(f"❌ 人脸识别失败: {str(e)[:50]}...") + return None, float("inf") + + def add_face(self, frame, person_name): + """添加人脸到数据库""" + # 先检测人脸,确保有效 + try: + # 验证帧中有人脸 + DeepFace.extract_faces(frame, enforce_detection=True) + # 保存人脸图片 + img_path = os.path.join(self.face_dir, f"{person_name}.jpg") + cv2.imwrite(img_path, frame) + # 重新加载数据库 + self._load_face_database() + print(f"✅ 已添加[{person_name}]到人脸库,路径: {img_path}") + return True + except Exception as e: + print(f"❌ 添加人脸失败: {str(e)[:50]}...") + return False + + def list_faces(self): + """列出人脸库中所有已注册的人名""" + return list(self.face_data.keys()) + + +def draw_detection_box(frame, bbox, label, color=(0, 255, 0)): + """绘制检测框和标签""" + x1, y1, x2, y2 = map(int, bbox) + cv2.rectangle(frame, (x1, y1), (x2, y2), color, 2) + cv2.putText( + frame, label, (x1, y1 - 10), + cv2.FONT_HERSHEY_SIMPLEX, 0.6, color, 2 + ) + return frame + + +# ===================== 独立运行测试逻辑 ===================== +if __name__ == "__main__": + # 初始化人脸库 + face_db = FaceDB(face_dir="faces") + print(f"\n当前人脸库已注册: {face_db.list_faces()}\n") + + # 打开摄像头 + cap = cv2.VideoCapture(0) + if not cap.isOpened(): + print("❌ 无法打开摄像头,请检查设备!") + exit(1) + + # 设置摄像头分辨率 + cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640) + cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480) + + print("=" * 50) + print("🎯 FaceDB 测试工具(独立运行模式)") + print("按键说明:") + print(" a → 添加当前帧人脸到数据库") + print(" r → 识别当前帧人脸") + print(" l → 列出已注册人脸") + print(" q → 退出程序") + print("=" * 50) + + while True: + # 读取摄像头帧 + ret, frame = cap.read() + if not ret: + print("❌ 无法读取摄像头画面!") + break + + # 显示实时画面 + cv2.imshow("FaceDB Test (utils.py)", frame) + + # 按键处理 + key = cv2.waitKey(1) & 0xFF + if key == ord('q'): + print("🔚 退出测试程序...") + break + + elif key == ord('a'): + # 添加人脸 + person_name = input("\n请输入要添加的人名: ").strip() + if not person_name: + print("❌ 人名不能为空!") + continue + face_db.add_face(frame, person_name) + + elif key == ord('r'): + # 识别人脸 + print("\n🔍 正在识别人脸...") + name, distance = face_db.recognize_face(frame) + if name: + print(f"✅ 识别成功!匹配到: {name} (距离: {distance:.4f})") + else: + print(f"❌ 未识别到匹配人脸(最小距离: {distance:.4f})") + + elif key == ord('l'): + # 列出已注册人脸 + faces = face_db.list_faces() + print(f"\n📋 人脸库已注册名单: {faces if faces else '空'}") + + # 释放资源 + cap.release() + cv2.destroyAllWindows() + print("\n✅ 资源已释放,程序结束") \ No newline at end of file