diff --git a/example/special/face_system/README.md b/example/special/face_system/README.md new file mode 100644 index 0000000000000000000000000000000000000000..587436ea37e9f86f5c0f5aab75918b649522d571 --- /dev/null +++ b/example/special/face_system/README.md @@ -0,0 +1,52 @@ +

凌智视觉模块人脸识别系统部署指南

+ +发布版本:V0.0.0 + +日期:2024-11-28 + +文件密级:□绝密 □秘密 □内部资料 ■公开 + +--- + +**免责声明** + +本文档按**现状**提供,福州凌睿智捷电子有限公司(以下简称**本公司**)不对本文档中的任何陈述、信息和内容的准确性、可靠性、完整性、适销性、适用性及非侵权性提供任何明示或暗示的声明或保证。本文档仅作为使用指导的参考。 + +由于产品版本升级或其他原因,本文档可能在未经任何通知的情况下不定期更新或修改。 + +**读者对象** + +本教程适用于以下工程师: + +- 技术支持工程师 +- 软件开发工程师 + +**修订记录** + +| **日期** | **版本** | **作者** | **修改说明** | +|:-----------| -------- |--------| ------------ | +| 2024/11/28 | 0.0.0 | 郑必城、钟海滨 | 初始版本 | + +## 1 简介 + +基于 Lockzhiner Vision Module 的 LZ-Picodet 模型训练的人脸检测模型 LZ-Face,以及ArcFace人脸识别模型,实现了一个人脸识别系统。 + +## 2 运行前的准备 + +* 请确保你已经下载了 [凌智视觉模块人脸检测模型](https://gitee.com/LockzhinerAI/LockzhinerVisionModule/releases/download/v0.0.3/LZ-Face.rknn) +* 请确保你已经下载了 [凌智视觉模块人脸识别模型](https://gitee.com/LockzhinerAI/LockzhinerVisionModule/releases/download/v0.0.0/LZ-ArcFace.rknn) + +## 3 在凌智视觉模块上部署模型 + +训练完模型后,请参考以下教程在凌智视觉模块上部署检测模型例程: + + +* [凌智视觉模块 人脸识别系统 Python 部署指南](./python/README.md) + +## 4 各模型性能指标 + +以下测试数据为模型执行 Predict 函数运行 1000 次耗时的平均时间 + +| 人脸识别系统 | FPS(帧/s) | 精度(%) | +|:------------------:|:--------:|:----:| +| LZ-Face、LZ-Arcface | 23 | - | \ No newline at end of file diff --git a/example/special/face_system/python/README.md b/example/special/face_system/python/README.md new file mode 100644 index 0000000000000000000000000000000000000000..be081bb224e15a98400263c2f8dce9ded682535b --- /dev/null +++ b/example/special/face_system/python/README.md @@ -0,0 +1,202 @@ +

凌智视觉模块 人脸识别系统 Python 部署指南

+ +发布版本:V0.0.0 + +日期:2024-11-28 + +文件密级:□绝密 □秘密 □内部资料 ■公开 + +--- + +**免责声明** + +本文档按**现状**提供,福州凌睿智捷电子有限公司(以下简称**本公司**)不对本文档中的任何陈述、信息和内容的准确性、可靠性、完整性、适销性、适用性及非侵权性提供任何明示或暗示的声明或保证。本文档仅作为使用指导的参考。 + +由于产品版本升级或其他原因,本文档可能在未经任何通知的情况下不定期更新或修改。 + +**读者对象** + +本教程适用于以下工程师: + +- 技术支持工程师 +- 软件开发工程师 + +**修订记录** + +| **日期** | **版本** | **作者** | **修改说明** | +|:-----------| -------- |---------| ------------ | +| 2024/11/28 | 0.0.0 | 郑必城、钟海滨 | 初始版本 | + +## 1 简介 + +接下来让我们基于 Python 来部署 ArcFace 人脸识别模型。在开始本章节前: + +* 请确保你已经下载了 [凌智视觉模块人脸检测模型](https://gitee.com/LockzhinerAI/LockzhinerVisionModule/releases/download/v0.0.3/LZ-Face.rknn) +* 请确保你已经下载了 [凌智视觉模块人脸识别模型](https://gitee.com/LockzhinerAI/LockzhinerVisionModule/releases/download/v0.0.0/LZ-ArcFace.rknn) +- 请确保你已经按照 [开发环境搭建指南](../../../../docs/introductory_tutorial/python_development_environment.md) 正确配置了开发环境。 + +## 2 Python API 文档 + +```python +from ...LockzhinerVisionModule_wapper import vision + + +class FaceRecognitionSystem: + def __init__(self): + """ + FaceRecognitionSystem 类 - 用于人脸识别系统的封装 + 该类封装了 InsightFace 框架下的 ArcFace 人脸识别模型以及PaddleDet + 框架下的目标检测模型,提供了初始化和预测的方法 + """ + + self.model = vision.FaceRecognitionSystem() + + def initialize( + self, + face_det_model_path, + face_rec_model_path, + face_det_param_path="", + face_rec_param_path="", + ): + """ + 初始化模型 + - 加载预训练的 PaddlePaddle 模型 + - 加载预训练的 ArcFace 模型 + Args: + face_det_model_path, 人脸检测模型文件的路径 + face_rec_model_path, 人脸识别模型文件的路径 + face_det_param_path="", 默认为空,不需填写 + face_rec_param_path="", 默认为空,不需填写 + + Returns: + bool: 初始化是否成功。 + """ + return self.model.initialize( + face_det_model_path, + face_rec_model_path, + face_det_param_path, + face_rec_param_path,) + + def buildDatabase(self, database_root, crop_root=""): + """ + 构建人脸识别数据库 + + Args: + database_root 用户人脸存储路径 + crop_root="" 裁剪图片存储路径(DEBUG时可开启) + Returns: + bool: 数据库构建是否成功。 + """ + return self.model.buildDatabase(database_root, crop_root) + + def predict(self, input_mat): + """ + 进行预测 - 使用加载的人脸检测模型和人脸是被模型进行预测 + Args: + input_mat (cv2.Mat): 输入的图像数据,通常是一个 cv2.Mat 变量。 + + Returns: + FaceFeatureResult: 识别到的用户,余弦相似度分数,检测到的目标框 + """ + return self.model.predict(input_mat) + +``` + +## 3 项目介绍 + +为了方便大家入手,我们做了一个简易的人脸识别例程。该程序可以使用摄像头进行端到端推理。 + +```python +import sys +import time + +from lockzhiner_vision_module.cv2 import VideoCapture, imread, imwrite +from lockzhiner_vision_module.vision import FaceRecognitionSystem, visualize +from lockzhiner_vision_module.edit import Edit + + +# 主程序入口 +if __name__ == '__main__': + # 获取命令行参数 + args = sys.argv + # 确保提供了足够的参数 + if len(args) != 5: + print("Need model path. Example: python face_system.py LZ-Face.rknn LZ-ArcFace.rknn baseDataset_root crop_root") + exit(1) + + # 初始化面部识别系统 + face_system = FaceRecognitionSystem() + # 验证面部识别系统的初始化是否成功 + if face_system.initialize(args[1], args[2]) is False: + print("Failed to initialize face_system model") + exit(1) + # 构建面部数据库 + face_system.buildDatabase(args[3],args[4]) + + # 初始化图像编辑处理对象 + edit = Edit() + # 开始并接受连接,准备进行图像编辑处理 + edit.start_and_accept_connection() + # 初始化视频捕捉对象 + video_capture = VideoCapture() + # 验证摄像头是否成功打开 + if video_capture.open(0) is False: + print("Failed to open capture") + exit(1) + # 主循环,用于持续捕捉和处理视频帧 + while True: + read_index = 0 + total_time_ms = 0 + for i in range(100): + # 从摄像头读取帧 + ret, input_mat = video_capture.read() + # 如果读取失败,则继续循环直到成功读取 + if ret is False: + continue + # 预测调用predict方法 + start_time = time.time() + results = face_system.predict(input_mat) + end_time = time.time() + total_time_ms += end_time - start_time + read_index += 1 + # 可视化处理结果 + vis_mat = visualize(input_mat, results) + # 打印处理后的图像 + edit.print(vis_mat) + print(f"FPS is {1.0 / (total_time_ms / read_index)}") + +``` + +## 4 上传并测试 Python 程序 + +参考 [连接设备指南](../../../../docs/introductory_tutorial/connect_device_using_ssh.md) 正确连接 Lockzhiner Vision Module 设备。 + +![](../../../../docs/introductory_tutorial/images/connect_device_using_ssh/ssh_success.png) + +请使用 Electerm Sftp 依次上传以下文件: + +- 进入存放 **test_arc_face[face_system.py](face_system.py).py** 脚本文件的目录,将 **[face_system.py](face_system.py).py** 上传到 Lockzhiner Vision Module +- 进入存放 **LZ-ArcFace.rknn(也可能是其他模型)** 模型存放的目录(模型存放在训练模型后下载的 output 文件夹内),将 **LZ-ArcFace.rknn** 上传到 Lockzhiner Vision Module +- 进入存放 **LZ-Face.rknn(也可能是其他模型)** 模型存放的目录(模型存放在训练模型后下载的 output 文件夹内),将 **LZ-Face.rknn** 上传到 Lockzhiner Vision Module +- 上传构建人脸数据库的文件夹 + - 文件夹结构: + - 主目录 + - 人脸数据库文件夹(即为用户名) + - 人脸图片 +上传文件 +![](./images/connect.png) +文件夹结构示意图 +![](./images/img.png) + + +请使用 Electerm Ssh 并在命令行中执行以下命令: + +```bash +python face_system.py LZ-Face.rknn LZ-ArcFace.rknn baseDataset_root crop_root +``` + +运行程序后,屏幕上开始打印数据库构建的相关信息,并在一段时间后输出 + +![alt text](./images/build_database.png) +![alt text](./images/fps.png) + diff --git a/example/special/face_system/python/face_system.py b/example/special/face_system/python/face_system.py new file mode 100644 index 0000000000000000000000000000000000000000..8c5b2def46b465a609443b9e961d27262428e592 --- /dev/null +++ b/example/special/face_system/python/face_system.py @@ -0,0 +1,57 @@ +import sys +import time + +from lockzhiner_vision_module.cv2 import VideoCapture, imread, imwrite +from lockzhiner_vision_module.vision import FaceRecognitionSystem, visualize +from lockzhiner_vision_module.edit import Edit + + +# 主程序入口 +if __name__ == '__main__': + # 获取命令行参数 + args = sys.argv + # 确保提供了足够的参数 + if len(args) != 5: + print("Need model path. Example: python face_system.py LZ-Face.rknn LZ-ArcFace.rknn baseDataset_root crop_root") + exit(1) + + # 初始化面部识别系统 + face_system = FaceRecognitionSystem() + # 验证面部识别系统的初始化是否成功 + if face_system.initialize(args[1], args[2]) is False: + print("Failed to initialize face_system model") + exit(1) + # 构建面部数据库 + face_system.buildDatabase(args[3],args[4]) + + # 初始化图像编辑处理对象 + edit = Edit() + # 开始并接受连接,准备进行图像编辑处理 + edit.start_and_accept_connection() + # 初始化视频捕捉对象 + video_capture = VideoCapture() + # 验证摄像头是否成功打开 + if video_capture.open(0) is False: + print("Failed to open capture") + exit(1) + # 主循环,用于持续捕捉和处理视频帧 + while True: + read_index = 0 + total_time_ms = 0 + for i in range(100): + # 从摄像头读取帧 + ret, input_mat = video_capture.read() + # 如果读取失败,则继续循环直到成功读取 + if ret is False: + continue + # 预测调用predict方法 + start_time = time.time() + results = face_system.predict(input_mat) + end_time = time.time() + total_time_ms += end_time - start_time + read_index += 1 + # 可视化处理结果 + vis_mat = visualize(input_mat, results) + # 打印处理后的图像 + edit.print(vis_mat) + print(f"FPS is {1.0 / (total_time_ms / read_index)}") \ No newline at end of file diff --git a/example/special/face_system/python/images/build_database.png b/example/special/face_system/python/images/build_database.png new file mode 100644 index 0000000000000000000000000000000000000000..817bc3c45e115ef927164c4f97acc3e7e0684d93 Binary files /dev/null and b/example/special/face_system/python/images/build_database.png differ diff --git a/example/special/face_system/python/images/connect.png b/example/special/face_system/python/images/connect.png new file mode 100644 index 0000000000000000000000000000000000000000..dca991881cd5b5813ef5a9e108251c55169fbe88 Binary files /dev/null and b/example/special/face_system/python/images/connect.png differ diff --git a/example/special/face_system/python/images/fps.png b/example/special/face_system/python/images/fps.png new file mode 100644 index 0000000000000000000000000000000000000000..889f2d5f848c37c14ea4dddc76152f317d57cf9d Binary files /dev/null and b/example/special/face_system/python/images/fps.png differ diff --git a/example/special/face_system/python/images/img.png b/example/special/face_system/python/images/img.png new file mode 100644 index 0000000000000000000000000000000000000000..69cbca641ad96fc8ba9d91972ee2d55f86618d21 Binary files /dev/null and b/example/special/face_system/python/images/img.png differ diff --git a/example/special/face_system/python/test_face_system.py b/example/special/face_system/python/test_face_system.py new file mode 100644 index 0000000000000000000000000000000000000000..9c1ff03bc0be5caed08f33090c95661116291c56 --- /dev/null +++ b/example/special/face_system/python/test_face_system.py @@ -0,0 +1,127 @@ +import os +import sys +from lockzhiner_vision_module.cv2 import VideoCapture,imread,imwrite +from lockzhiner_vision_module.vision import PaddleDet, ArcFace, visualize, cosine_similarity +from lockzhiner_vision_module.edit import Edit +import time +import sys + +def predict_face(det_model, rec_model, face_mat): + if face_mat.empty(): + return None, None + + det_results = det_model.predict(face_mat) + result_size = len(det_results) + if result_size != 1: + print(f"Failed to find face. The size of faces is {result_size}, but need 1.") + return None, None + + det_result = det_results[0] + face_roi = det_result.box + # print( + # f"(x,y,w,h,score): [{face_roi.x},{face_roi.y},{face_roi.width},{face_roi.height},{det_result.score}]" + # ) + crop_mat = input_mat.crop(face_roi) + if crop_mat.empty(): + return None, None + + rec_result = rec_model.predict(crop_mat) + return det_results, rec_result + + +if __name__ == '__main__': + args = sys.argv + if len(args) != 3: + print("Need model path. Example: python face_system.py LZ-Face.rknn LZ-ArcFace.rknn") + exit(1) + + face_det = PaddleDet() + if face_det.initialize(args[1]) is False: + print("Failed to initialize face_det model") + exit(1) + + face_rec = ArcFace() + if face_rec.initialize(args[2]) is False: + print("Failed to initialize face_rec model") + exit(1) + + # 原始数据路径 + base_dataset_path = 'BaseDataset' + # 裁剪后的数据路径 + crop_dataset_path = 'CropDataset' + + # 如果裁剪文件夹不存在,则创建 + if not os.path.exists(crop_dataset_path): + os.makedirs(crop_dataset_path) + # 构建数据库 + # 临时存储特征向量的字典 + + # c++的字典使用,map(std::string,vectoor,rec.result) + + face_dict = {} + # 遍历BaseDataset中的每个文件夹 + for user_folder in os.listdir(base_dataset_path): + user_path = os.path.join(base_dataset_path, user_folder) + if os.path.isdir(user_path) is False: + continue + + # 创建对应用户的裁剪文件夹 + user_crop_path = os.path.join(crop_dataset_path, user_folder) + if not os.path.exists(user_crop_path): + os.makedirs(user_crop_path) + # 初始化用户的特征向量列表 + face_dict[user_folder] = [] + for img_name in os.listdir(user_path): + img_path = os.path.join(user_path, img_name) + print(img_path) + + # 读取图片并检测图片是否为空 + input_mat = imread(img_path) + if input_mat.empty(): + print(f"{img_path} is empty.") + continue + + _, feature_result = predict_face(face_det, face_rec, input_mat) + if feature_result is None: + print(f"Failed to find face in {img_path}.") + continue + face_dict[user_folder].append(feature_result) + + edit = Edit() + edit.start_and_accept_connection() + + video_capture = VideoCapture() + if video_capture.open(0) is False: + print("Failed to open capture") + exit(1) + + while True: + ret, input_mat = video_capture.read() + if ret is False: + continue +# 预测 + result_0, result_1 = predict_face(face_det, face_rec, input_mat) + if result_0 is None or result_1 is None: + print(f"Failed to find face on video.") + continue + vis_mat = visualize(input_mat, result_0) + edit.print(vis_mat) + + max_name = "None" + max_similarity = 0.0 + for name, feature_results in face_dict.items(): + for feature_result in feature_results: + similarity = cosine_similarity(result_1, feature_result) + if max_similarity < similarity: + max_similarity = similarity + max_name = name + print(f"User: {max_name}, score: {max_similarity}") + + + + + + + + +