diff --git a/10.检测屏幕内容.py b/10.检测屏幕内容.py index 0dec891..11289db 100644 --- a/10.检测屏幕内容.py +++ b/10.检测屏幕内容.py @@ -8,7 +8,7 @@ import numpy as np # 加载训练好的模型 # best.pt: 最佳模型,适用于生产 # last.pt: 最后一轮训练的模型,适用于继续训练 -yolo = YOLO('runs/detect/train7/weights/best.pt') +yolo = YOLO('models/face/best.pt') # 指定屏幕范围 # x,y,width,height 全屏None diff --git a/16.人脸比对.py b/16.人脸比对.py new file mode 100644 index 0000000..b78e512 --- /dev/null +++ b/16.人脸比对.py @@ -0,0 +1,42 @@ +import insightface +from insightface.app import FaceAnalysis +import cv2 + +# 1. 创建人脸分析应用 +# 这会自动下载预训练模型(第一次运行时会下载,约 200MB) +app = FaceAnalysis(name='buffalo_l') # 'buffalo_l' 是当前最准的模型集合 +app.prepare(ctx_id=0, det_size=(640, 640)) # ctx_id=0 表示使用CPU, ctx_id=1/gpu_id 表示使用GPU + +# 2. 加载图片 +img1 = cv2.imread('./resources/face/01.png') +# img2 = cv2.imread('./resources/face/02.png') +img2 = cv2.imread('./resources/face/16.jpg') + +# 3. 进行人脸检测和特征提取 +faces1 = app.get(img1) +faces2 = app.get(img2) + +# 检查是否检测到人脸 +if len(faces1) == 0 or len(faces2) == 0: + print("未在图片中检测到人脸!") + exit() + +# 取每张图片中检测到的第一个人脸 +face1 = faces1[0] +face2 = faces2[0] + +# 4. 获取人脸特征向量(嵌入) +embedding1 = face1.embedding +embedding2 = face2.embedding + +# 5. 计算特征向量之间的相似度(使用余弦相似度) +from numpy.linalg import norm +cos_sim = embedding1 @ embedding2.T / (norm(embedding1) * norm(embedding2)) +print(f"人脸相似度(余弦): {cos_sim:.4f}") + +# 6. 根据阈值判断是否为同一个人 +threshold = 0.6 # 常用阈值,可根据场景调整(范围一般在0.2-0.8之间,值越大判断越严格) +if cos_sim > threshold: + print("判断为同一个人!") +else: + print("判断为不同人。") \ No newline at end of file diff --git a/17.人脸识别.py b/17.人脸识别.py new file mode 100644 index 0000000..41378e8 --- /dev/null +++ b/17.人脸识别.py @@ -0,0 +1,59 @@ +import insightface +from insightface.app import FaceAnalysis +import cv2 +import numpy as np +from numpy.linalg import norm + +# 初始化模型 +app = FaceAnalysis(name='buffalo_l') +app.prepare(ctx_id=0, det_size=(640, 640)) + +# 创建一个数据库来存储已知人脸的特征和姓名 +face_database = {} + +# --- 注册阶段:将已知人脸加入数据库 --- +def register_face(image_path, person_name): + img = cv2.imread(image_path) + faces = app.get(img) + if len(faces) != 1: + print(f"警告:在 {image_path} 中未检测到或检测到多张人脸,跳过。") + return + embedding = faces[0].embedding + face_database[person_name] = embedding + print(f"成功注册:{person_name}") + +# 注册多个人 +img1 = cv2.imread('./resources/face/01.png') + +register_face('./resources/face/01.png', '01') +register_face('./resources/face/02.png', '02') + +# --- 识别阶段:识别未知图片中的人 --- +def recognize_face(image_path): + img = cv2.imread(image_path) + faces = app.get(img) + if len(faces) == 0: + print("未检测到人脸。") + return + + for i, face in enumerate(faces): + unknown_embedding = face.embedding + max_sim = -1 + identity = "未知" + + # 与数据库中的每个人脸进行比对 + for name, known_embedding in face_database.items(): + cos_sim = unknown_embedding @ known_embedding.T / (norm(unknown_embedding) * norm(known_embedding)) + if cos_sim > max_sim: + max_sim = cos_sim + identity = name + + # 根据阈值决定最终身份 + threshold = 0.6 + if max_sim < threshold: + identity = "未知" + + print(f"人脸 {i+1}: 识别为 【{identity}】, 相似度:{max_sim:.4f}") + +# 识别一张新图片 +recognize_face('./resources/face/16.jpg') \ No newline at end of file diff --git a/18.人脸识别-保存数据库.py b/18.人脸识别-保存数据库.py new file mode 100644 index 0000000..d903f32 --- /dev/null +++ b/18.人脸识别-保存数据库.py @@ -0,0 +1,265 @@ +import insightface +from insightface.app import FaceAnalysis +import cv2 +import numpy as np +import sqlite3 +import os +from numpy.linalg import norm + +# 初始化InsightFace模型 +app = FaceAnalysis(name='buffalo_l') +app.prepare(ctx_id=0, det_size=(640, 640)) + + +class FaceDatabase: + def __init__(self, db_path='face_database.db'): + self.db_path = db_path + self.init_database() + + def init_database(self): + """初始化数据库""" + conn = sqlite3.connect(self.db_path) + cursor = conn.cursor() + cursor.execute(''' + CREATE TABLE IF NOT EXISTS faces ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + name TEXT UNIQUE NOT NULL, + embedding BLOB NOT NULL, + created_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP + ) + ''') + conn.commit() + conn.close() + print(f"数据库初始化完成: {self.db_path}") + + def add_face(self, name, embedding): + """添加人脸到数据库""" + conn = sqlite3.connect(self.db_path) + cursor = conn.cursor() + + # 将numpy数组转换为bytes + embedding_blob = embedding.tobytes() + + try: + cursor.execute( + 'INSERT INTO faces (name, embedding) VALUES (?, ?)', + (name, embedding_blob) + ) + conn.commit() + print(f"✅ 成功注册: {name}") + return True + except sqlite3.IntegrityError: + print(f"⚠️ 姓名已存在: {name}") + return False + finally: + conn.close() + + def get_all_faces(self): + """获取所有人脸数据""" + conn = sqlite3.connect(self.db_path) + cursor = conn.cursor() + + cursor.execute('SELECT name, embedding FROM faces') + results = cursor.fetchall() + conn.close() + + face_database = {} + for name, embedding_blob in results: + # 将bytes转换回numpy数组 + embedding = np.frombuffer(embedding_blob, dtype=np.float32) + face_database[name] = embedding + + print(f"📊 从数据库加载了 {len(face_database)} 个人脸特征") + return face_database + + def delete_face(self, name): + """删除人脸""" + conn = sqlite3.connect(self.db_path) + cursor = conn.cursor() + + cursor.execute('DELETE FROM faces WHERE name = ?', (name,)) + affected_rows = cursor.rowcount + conn.commit() + conn.close() + + if affected_rows > 0: + print(f"🗑️ 已删除: {name}") + return True + else: + print(f"❌ 未找到: {name}") + return False + + def face_exists(self, name): + """检查人脸是否存在""" + conn = sqlite3.connect(self.db_path) + cursor = conn.cursor() + + cursor.execute('SELECT 1 FROM faces WHERE name = ?', (name,)) + exists = cursor.fetchone() is not None + conn.close() + + return exists + + +# 创建全局数据库实例 +face_db = FaceDatabase() + + +def register_face(image_path, person_name): + """注册人脸""" + # 检查图片是否存在 + if not os.path.exists(image_path): + print(f"❌ 图片不存在: {image_path}") + return False + + # 读取图片 + img = cv2.imread(image_path) + if img is None: + print(f"❌ 无法读取图片: {image_path}") + return False + + # 使用InsightFace检测人脸 + faces = app.get(img) + + if len(faces) == 0: + print(f"❌ 在 {image_path} 中未检测到人脸") + return False + elif len(faces) > 1: + print(f"⚠️ 在 {image_path} 中检测到 {len(faces)} 张人脸,使用第一张") + + # 提取人脸特征 + embedding = faces[0].embedding + print(f"📐 提取到特征向量,维度: {embedding.shape}") + + # 保存到数据库 + return face_db.add_face(person_name, embedding) + + +def register_faces_from_folder(folder_path): + """从文件夹批量注册人脸""" + if not os.path.exists(folder_path): + print(f"❌ 文件夹不存在: {folder_path}") + return + + supported_formats = ('.jpg', '.jpeg', '.png', '.bmp', '.tiff') + registered_count = 0 + + for filename in os.listdir(folder_path): + if filename.lower().endswith(supported_formats): + # 使用文件名(不含扩展名)作为人名 + person_name = os.path.splitext(filename)[0] + image_path = os.path.join(folder_path, filename) + + if register_face(image_path, person_name): + registered_count += 1 + + print(f"🎉 批量注册完成,共注册 {registered_count} 个人脸") + + +def recognize_face(image_path, threshold=0.6): + """识别人脸""" + # 检查图片是否存在 + if not os.path.exists(image_path): + print(f"❌ 图片不存在: {image_path}") + return + + # 读取图片 + img = cv2.imread(image_path) + if img is None: + print(f"❌ 无法读取图片: {image_path}") + return + + # 从数据库加载所有人脸特征 + face_database = face_db.get_all_faces() + + if not face_database: + print("❌ 数据库中无人脸数据,请先注册人脸") + return + + # 使用InsightFace检测人脸 + faces = app.get(img) + + if len(faces) == 0: + print("❌ 未检测到人脸") + return + + print(f"🔍 检测到 {len(faces)} 张人脸,开始识别...") + + for i, face in enumerate(faces): + unknown_embedding = face.embedding + max_sim = -1 + identity = "未知" + best_match_name = None + + # 与数据库中的每个人脸进行比对 + for name, known_embedding in face_database.items(): + # 计算余弦相似度 + cos_sim = unknown_embedding @ known_embedding.T / (norm(unknown_embedding) * norm(known_embedding)) + + if cos_sim > max_sim: + max_sim = cos_sim + identity = name + best_match_name = name + + # 根据阈值决定最终身份 + if max_sim < threshold: + identity = "未知" + + # 输出结果 + status = "✅" if identity != "未知" else "❓" + print(f"{status} 人脸 {i + 1}: 识别为 【{identity}】, 相似度: {max_sim:.4f}") + + # 显示匹配详情 + if identity != "未知": + matched_embedding = face_database[best_match_name] + print(f" 匹配特征: {best_match_name}, 范数: {norm(matched_embedding):.4f}") + + +def list_registered_faces(): + """列出所有已注册的人脸""" + face_database = face_db.get_all_faces() + + if not face_database: + print("📭 数据库为空") + return + + print(f"\n📋 已注册的人脸 ({len(face_database)} 个):") + for i, name in enumerate(face_database.keys(), 1): + print(f" {i}. {name}") + + +def delete_face(person_name): + """删除指定人脸""" + return face_db.delete_face(person_name) + + +# 使用示例 +if __name__ == "__main__": + print("=" * 50) + print("🎭 InsightFace 人脸识别系统 (SQLite版本)") + print("=" * 50) + + # 1. 批量注册人脸 + print("\n1. 📁 批量注册人脸") + register_faces_from_folder('./resources/face') + + # 2. 单个注册 + print("\n2. 👤 单个注册") + register_face('./resources/face/01.png', '张三') + register_face('./resources/face/02.png', '李四') + + # 3. 查看已注册的人脸 + print("\n3. 📊 已注册人脸列表") + list_registered_faces() + + # 4. 识别人脸 + print("\n4. 🔍 人脸识别测试") + recognize_face('./resources/face/16.jpg', threshold=0.6) + + # 5. 删除测试 + # print("\n5. 🗑️ 删除人脸测试") + # delete_face('测试删除') + + print("\n" + "=" * 50) + print("✨ 程序执行完成") + print("=" * 50) \ No newline at end of file diff --git a/face_database.db b/face_database.db new file mode 100644 index 0000000..bc2c91a Binary files /dev/null and b/face_database.db differ diff --git a/requirements.txt b/requirements.txt index f563d58..0411fd4 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,4 +4,5 @@ numpy~=2.0.2 pyautogui~=0.9.54 moviepy~=2.2.1 torch~=2.8.0 -PyYAML~=6.0.2 \ No newline at end of file +PyYAML~=6.0.2 +insightface~=0.7.3 \ No newline at end of file diff --git a/resources/face/01.png b/resources/face/01.png new file mode 100644 index 0000000..776ff3e Binary files /dev/null and b/resources/face/01.png differ diff --git a/resources/face/02.png b/resources/face/02.png new file mode 100644 index 0000000..b60a705 Binary files /dev/null and b/resources/face/02.png differ diff --git a/resources/face/16.jpg b/resources/face/16.jpg new file mode 100644 index 0000000..4eed48b Binary files /dev/null and b/resources/face/16.jpg differ