深度学习----用Arcface在pycharm上做人脸识别(完整代码)_python arcface
小博最近学习了一下人脸识别,用opencv,ssd都跑了一遍,感觉都不是很理想。那个ssd配环境配的头疼,以至于小博果断放弃,更换新赛道。发现用这个Arcface做人脸识别还是蛮不错的,没有很多环境的问题。
一、性能对比(关键指标)
二、环境配置
1.安装依赖库
首先,确保你已经安装了 Python 和相关的深度学习框架(如 PyTorch 或 TensorFlow)。这里我们以 PyTorch 为例。并且已经创建好了相关的虚拟环境,在pycharm中配置好并激活了。这里小博用的是conda环境。打开配置好的虚拟环境终端:
# 安装必要的库pip install torch torchvision numpy opencv-python insightface scikit-learn
上面安装的insightface如果你使用的是 GPU 环境,建议安装支持 GPU 的版本:
pip install insightface-gpu
注意:运行不畅可能是子模块缺失,可以尝试重新安装 insightface
:
pip uninstall insightfacepip install insightface
或者直接从 GitHub 克隆源码安装:
git clone https://github.com/deepinsight/insightface.gitcd insightfacepip install -e .
三、代码实现
1.代码
import cv2import numpy as npfrom insightface.app import FaceAnalysisimport osimport pickleimport warningsfrom sklearn.neighbors import NearestNeighborsimport time# 忽略 NumPy 的 FutureWarningwarnings.filterwarnings(\"ignore\", category=FutureWarning)# 初始化 FaceAnalysis 应用def initialize_face_analysis(): try: import onnxruntime providers = onnxruntime.get_available_providers() if \'CUDAExecutionProvider\' in providers: print(\"GPU 可用,使用 GPU 加速。\") ctx_id = 0 # 使用 GPU else: print(\"GPU 不可用,回退到 CPU。\") ctx_id = -1 # 使用 CPU except ImportError: print(\"onnxruntime-gpu 未安装,回退到 CPU。\") ctx_id = -1 app = FaceAnalysis(name=\'buffalo_l\') app.prepare(ctx_id=ctx_id, det_size=(640, 640)) return app# 计算余弦相似度def cosine_similarity(a, b): return np.dot(a, b) / (np.linalg.norm(a) * np.linalg.norm(b))# 加载或创建人脸数据库def load_or_create_database(database_path): os.makedirs(os.path.dirname(database_path), exist_ok=True) # 确保目录存在 if os.path.exists(database_path): with open(database_path, \"rb\") as f: database = pickle.load(f) else: database = {} return database# 保存人脸数据库def save_database(database, database_path): with open(database_path, \"wb\") as f: pickle.dump(database, f)# 添加新人脸数据def add_face_to_database(app, database, name, image_path=None, camera_capture=False): if camera_capture: cap = cv2.VideoCapture(0) if not cap.isOpened(): print(\"无法打开摄像头,请检查设备。\") return print(\"按 \'s\' 键保存人脸,按 \'q\' 键退出。\") while True: ret, frame = cap.read() if not ret: print(\"无法捕获图像,请检查摄像头。\") break cv2.imshow(\"Capture Face\", frame) key = cv2.waitKey(1) & 0xFF # 缩短等待时间为 1 毫秒 if key == ord(\'s\'): faces = app.get(frame) if len(faces) == 0: print(\"未检测到人脸,请调整摄像头角度或光线条件。\") continue elif len(faces) > 1: print(\"检测到多张人脸,请确保画面中只有一张人脸。\") continue embedding = faces[0].embedding database[name] = embedding print(f\"人脸 \'{name}\' 已保存。\") break elif key == ord(\'q\'): print(\"未保存人脸。\") break cap.release() cv2.destroyAllWindows() else: image_path = image_path.strip().strip(\'\"\') # 去除多余空格和引号 print(f\"尝试加载图片路径: {image_path}\") # 调试信息 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 faces = app.get(img) if len(faces) == 0: print(\"未检测到人脸,请检查图像质量。\") elif len(faces) > 1: print(\"检测到多张人脸,请确保图像中只有一张人脸。\") else: embedding = faces[0].embedding database[name] = embedding print(f\"人脸 \'{name}\' 已保存。\")# 构建最近邻模型def build_nn_model(database): embeddings = np.array(list(database.values())) names = list(database.keys()) nn_model = NearestNeighbors(n_neighbors=1, metric=\"cosine\") nn_model.fit(embeddings) return nn_model, names# 查找最相似的人脸def find_best_match(nn_model, names, embedding, threshold=0.6): distances, indices = nn_model.kneighbors([embedding]) if distances[0][0] < threshold: return names[indices[0][0]], 1 - distances[0][0] return None, 0# 实时人脸识别def realtime_face_recognition(app, database, threshold=0.6): nn_model, names = build_nn_model(database) cap = cv2.VideoCapture(0) if not cap.isOpened(): print(\"无法打开摄像头,请检查设备。\") return print(\"实时人脸识别已启动,按 \'q\' 键退出。\") while True: ret, frame = cap.read() if not ret: print(\"无法捕获图像,请检查摄像头。\") break faces = app.get(frame) for face in faces: bbox = face.bbox.astype(int) embedding = face.embedding best_match, best_similarity = find_best_match(nn_model, names, embedding, threshold) label = f\"{best_match} ({best_similarity:.2f})\" if best_match else \"Unknown\" cv2.rectangle(frame, (bbox[0], bbox[1]), (bbox[2], bbox[3]), (0, 255, 0), 2) cv2.putText(frame, label, (bbox[0], bbox[1] - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.9, (0, 255, 0), 2) cv2.imshow(\"Real-time Face Recognition\", frame) key = cv2.waitKey(1) & 0xFF # 缩短等待时间为 1 毫秒 if key == ord(\'q\'): print(\"退出实时人脸识别模式。\") break cap.release() cv2.destroyAllWindows()# 主函数def main(): app = initialize_face_analysis() database_path = \"D:/Arcface/dd/face_database.pkl\" database = load_or_create_database(database_path) train_mode = input(\"是否进入训练模式?(y/n): \").lower() if train_mode == \'y\': name = input(\"请输入人名: \") source = input(\"通过图片 (i) 还是摄像头 (c) 添加人脸?(i/c): \").lower() if source == \'i\': image_path = input(\"请输入图片路径: \") add_face_to_database(app, database, name, image_path=image_path) elif source == \'c\': add_face_to_database(app, database, name, camera_capture=True) else: print(\"无效的选择。\") save_database(database, database_path) realtime_face_recognition(app, database)if __name__ == \"__main__\": main()
2.运行效果
小博运行了两个人,每个人训练了两张图片,效果如下:
3.关于database_path的说明
database_path
是存储人脸数据库的文件路径。它是一个 .pkl
文件,用于保存所有已录入的人脸特征向量及其对应的人名。每次运行程序时,程序会从该文件加载现有的数据库(如果文件存在),并在训练模式下将新录入的人脸数据添加到数据库中。
4.database_path的作用
database_path
是一个文件路径,指向存储人脸数据库的 .pkl
文件。这个文件的内容是一个 Python 字典,结构如下:
{ \"bill\": [embedding_vector_for_bill], #人脸特征向量(512维) \"alice\": [embedding_vector_for_alice], \"bob\": [embedding_vector_for_bob]}
- 键(Key) :人名(如
\"bill\"
、\"alice\"
)。 - 值(Value) :对应的人脸特征向量(一个长度固定的 NumPy 数组)。
每次录入新人脸时,程序会将新人脸的特征向量添加到字典中,并覆盖原有的 .pkl
文件。
5.示例:录入多个人脸
(1)保持database_pathb
假设你已经录入了第一个人(bill
),现在想录入第二个人(alice
),要保持 database_path
不变,在代码中,database_path
被定义为:
database_path = \"D:/Arcface/dd/face_database.pkl\"
改成你自己的路径:默认与你的 Python 脚本在同一目录下。
如果你想将数据保存到其他目录(例如 data/
文件夹),可以修改 database_path
变量:
# 修改主函数中的路径def main(): database_path = \"data/face_database.pkl\" # 新路径 database = load_or_create_database(database_path) ...
确保目标目录存在(如data/),否则会报错。
(2)加载现有数据库
程序启动时,会调用 load_or_create_database
函数加载现有的数据库文件:
def load_or_create_database(database_path): os.makedirs(os.path.dirname(database_path), exist_ok=True) # 确保目录存在 if os.path.exists(database_path): with open(database_path, \"rb\") as f: database = pickle.load(f) else: database = {} return database
如果 face_database.pkl
文件存在,程序会加载其中的内容。
如果文件不存在,程序会创建一个空字典。
(3)添加新人脸
当你录入第二个人(alice
)时,程序会将 alice
的人脸特征向量添加到字典中:
database[\"alice\"] = embedding
(4)保存更新后的数据库
程序会在退出训练模式时调用 save_database
函数,将更新后的字典保存回 face_database.pkl
文件:
def save_database(database, database_path): with open(database_path, \"wb\") as f: pickle.dump(database, f)
(5)如何验证数据库内容
如果你想查看数据库文件的内容,可以使用以下代码:
import pickle# 加载数据库文件database_path = \"D:/Arcface/dd/face_database.pkl\"with open(database_path, \"rb\") as f: database = pickle.load(f)# 打印数据库内容print(\"当前数据库内容:\")for name, embedding in database.items(): print(f\"人名: {name}, 特征向量长度: {len(embedding)}\")
输出示例:
当前数据库内容:人名: bill, 特征向量长度: 512人名: alice, 特征向量长度: 512人名: bob, 特征向量长度: 512
四、注意事项
运行实例:
是否进入训练模式?(y/n): y请输入人名: zly通过图片 (i) 还是摄像头 (c) 添加人脸?(i/c): i请输入图片路径: D:/face photo/zly/OIP-C (3).jpg人脸 \'zly\' 已保存。实时人脸识别已启动,按 \'q\' 键退出。
1.路径输入
如果选择 \'i\' ,要注意输如路径,不要额外添加双引号。列如,直接输入:
D:/face photo/zly/OIP-C (3).jpg
或者使用原始字符串(在路径前加 r
)以避免转义字符问题:
r\"D:\\face photo\\zly\\OIP-C (3).jpg\"
2.图片注意
(1)质量要求
清晰度
- 高分辨率 :图片应具有较高的分辨率(建议至少 640x480 或更高),以确保人脸细节清晰可见。
- 避免模糊 :图片不应有运动模糊或失焦现象。
光照条件
- 均匀光照 :避免过亮或过暗的区域,确保人脸部分光线均匀。
- 避免阴影 :人脸不应被帽子、头发或其他物体遮挡产生阴影。
角度
- 正面视角 :尽量选择正脸图片,避免大角度的侧脸或俯仰角。
- 头部姿态 :头部应保持自然直立,避免过度倾斜或旋转。
(2)图片内容要求
单一主体
- 单人图片 :每张图片中应只包含一个人脸。如果图片中有多张人脸,程序默认仅提取第一张人脸特征,可能导致错误。
- 无干扰物 :避免背景中有其他人脸或其他干扰物。
面部特征完整
- 无遮挡 :人脸不应被口罩、墨镜、帽子等遮挡。
- 五官可见 :眼睛、鼻子、嘴巴等关键部位应清晰可见。
表情
- 自然表情 :尽量选择中性表情的图片,避免夸张的表情(如大笑、皱眉)影响特征提取。
(3)图片格式要求
支持的格式
- 确保图片格式为常见的图像格式,例如
.jpg
,.jpeg
,.png
。 - 不支持的格式(如
.bmp
,.gif
)需要提前转换。
文件命名
- 文件名可以随意命名,但应避免特殊字符(如
*
,?
,:
等),以免读取时出错。
文件大小
- 图片文件大小不宜过大(建议单张图片不超过 5MB),否则可能影响加载速度。
3.键的输入
输入\'s\'保存或\'q\'退出键时,确保键盘输入焦点在 OpenCV 窗口(弹出的镜头窗口),不要像小博一样,傻傻的一直在运行的命令行窗口输入哦。
欢迎大家留言评论,小博会及时回复!!