JETSON 人脸检测——Ultra-Light-Fast-Generic-Face-Detector-1MB
文章目录
Ultra-Light-Fast-Generic-Face-Detector-1MB (以下可简称 ultraface)介绍
可以参考这个博客:人脸检测之Ultra-Light-Fast-Generic-Face-Detector-1MB
里面有相关的原理,数据对比以及网络架构。
源码
参考这个链接:https://github.com/Linzaer/Ultra-Light-Fast-Generic-Face-Detector-1MB
这个是 Ultra-Light-Fast-Generic-Face-Detector-1MB 的官方代码。
环境搭建及相关的 C++ 部署
因为这次设备 JETSON-ORIN-NX 进行人脸检测主要是为了与后续的硬件融合。
因此主要是使用 C++ 语言。所以需要对源码进行相关的 C++ 部署。
在 Github 源码的 README.md 文件中可以知道** ultraface**:
- 提供NCNN C++推理代码
- 提供MNN C++推理代码、M
- NN Python推理代码
- FP32/INT8量化后模型
本文尝试过使用 MNN 进行 C++ 推理,但是错误太多,最终没有进行下去,因此在此不做展示。但是感兴趣的同学可以参考以下的链接自行尝试:
- C++ implemententation of Ultra-Light-Fast-Generic-Face-Detector-1MB with MNN
- Jetson Nano上安装MNN深度学习框架
- Ubuntu20.04环境下编译MNN并部署mnist
- linux上编译安装MNN
但是本文尝试使用 NCNN 进行C++ 部署,成功。因此下面会展示 NCNN 部署C++ 并且修改源码为可以对视频进行检测,然后获得结果的过程。
下载并编译 NCNN
在下载 ultraface 源码的时候,可以发现在这个路径:…/Ultra-Light-Fast-Generic-Face-Detector-1MB/ncnn/3rdparty/ncnn 文件夹下面是空的,什么都没有。这是因为需要下载 NCNN 的源码到这个文件夹中。
在下载这个源码并且编译之前,需要下载一些环境配置需要的东西。例如:opencv4、g++、cmake、protobuf
详细的安装步骤可以参考这个博客:ubuntu环境安装ncnn
前期准备安装完毕后,可以下载并配置 NCNN 了。
NCNN 源码链接: ncnn
git clone https://github.com/Tencent/ncnn
下载好源码的包后,将源码里面的文件复制到上面这个路径的文件夹里面。
然后进行编译即可:
cd ./Ultra-Light-Fast-Generic-Face-Detector-1MB/ncnn/3rdparty/ncnn
mkdir build && cd build
cmake ..
make -j4
这个编译过程还蛮简单的。比那个 MNN 简单多了。
编译 Ultra-Light-Fast-Generic-Face-Detector-1MB
因为在路径:…/Ultra-Light-Fast-Generic-Face-Detector-1MB/ncnn/3rdparty/ncnn 下已经将 NCNN 搭建好了,然后就开始进行 ultraface 的编译:
// 编译过程官网里面有:https://github.com/Linzaer/Ultra-Light-Fast-Generic-Face-Detector-1MB/tree/master/ncnn
cd Ultra-Light-Fast-Generic-Face-Detector-1MB/ncnn
mkdir build && cd build && cmake ..
make -j$(nproc)
编译完成后可以运行一下测试文件:
./main ../data/version-RFB/RFB-320.bin ../data/version-RFB/RFB-320.param ../data/test.jpg
其中 data 文件夹下面的 version-slim-320 和 version-RFB-320 是官方提供的已经转换好的 NCNN 模型。直接拿来用即可。
在官网链接后面的部分则是关于如何将预训练模型转换为 NCNN 模型的。需要自己训练网络的可以参考。
修改 main.cpp 进行视频读取和人脸检测
修改前的 main.cpp:
// UltraFaceTest
#include "UltraFace.hpp"
#include <iostream>
#include <opencv2/opencv.hpp>
int main(int argc, char **argv) {
if (argc <= 3) {
fprintf(stderr, "Usage: %s <ncnn bin> <ncnn param> [image files...]\n", argv[0]);
return 1;
}
std::string bin_path = argv[1];
std::string param_path = argv[2];
UltraFace ultraface(bin_path, param_path, 320, 240, 1, 0.7); // config model input
for (int i = 3; i < argc; i++) {
std::string image_file = argv[i];
std::cout << "Processing " << image_file << std::endl;
cv::Mat frame = cv::imread(image_file);
ncnn::Mat inmat = ncnn::Mat::from_pixels(frame.data, ncnn::Mat::PIXEL_BGR2RGB, frame.cols, frame.rows);
std::vector<FaceInfo> face_info;
ultraface.detect(inmat, face_info);
for (int i = 0; i < face_info.size(); i++) {
auto face = face_info[i];
cv::Point pt1(face.x1, face.y1);
cv::Point pt2(face.x2, face.y2);
cv::rectangle(frame, pt1, pt2, cv::Scalar(0, 255, 0), 2);
}
cv::imshow("UltraFace", frame);
cv::waitKey();
cv::imwrite("result.jpg", frame);
}
return 0;
}
修改后的 main.cpp:
// UltraFaceTest
#include <chrono>
#include "UltraFace.hpp"
#include <iostream>
#include <opencv2/opencv.hpp>
#include <opencv2/core.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/highgui.hpp>
int main(int argc, char **argv) {
if (argc <= 3) {
fprintf(stderr, "Usage: %s <ncnn bin> <ncnn param> [image files...]\n", argv[0]);
return 1;
}
std::string bin_path = argv[1];
std::string param_path = argv[2];
std::string path = argv[3];
UltraFace ultraface(bin_path, param_path, 320, 240, 1, 0.7); // config model input
cv::VideoCapture cap(path);
cv::Mat image;
auto start1 = std::chrono::steady_clock::now(); // end1-start1 表示代码运行的总时间,end-start 表示单次模型推导的时间
// cap.isOpened():检查视频是否成功打开
if (!cap.isOpened()) {
std::cout << "无法打开视频文件" << std::endl;
return -1;
}
double desired_fps = 20.0; // 设置期望的帧率
double delay_pre = 1000.0 / desired_fps; // 计算延迟时间
// cap.read():读取下一帧视频,并将其存储在 frame 变量中
while(cap.read(image)){
ncnn::Mat inputBlob = ncnn::Mat::from_pixels(image.data, ncnn::Mat::PIXEL_BGR2RGB, image.cols, image.rows);
std::vector<FaceInfo> face_info;
auto start = std::chrono::steady_clock::now();
ultraface.detect(inputBlob, face_info);
for (int i = 0; i < face_info.size(); i++) {
auto face = face_info[i];
cv::Point pt1(face.x1, face.y1);
cv::Point pt2(face.x2, face.y2);
cv::rectangle(image, pt1, pt2, cv::Scalar(0, 255, 0), 2);
}
auto end = std::chrono::steady_clock::now();
std::chrono::duration<double> elapsedSeconds = end - start;
double inferenceTime = elapsedSeconds.count();
std::cout << "Inference Time: " << inferenceTime << " seconds" << std::endl; // 输出单次模型推理的时间
cv::imshow("UltraFace", image);
double delay = delay_pre-inferenceTime*1000-5;
if (delay >=10 ){
cv::waitKey(delay);
}else {
cv::waitKey(10);
}
}
auto end1 = std::chrono::steady_clock::now();
std::chrono::duration<double> elapsedSeconds1 = end1 - start1;
double inferenceTime1 = elapsedSeconds1.count();
std::cout << "Inference Time: " << inferenceTime1 << " seconds" << std::endl; // 输出总体运行的时间
cap.release(); // 释放视频捕获对象
cv::destroyAllWindows(); // 关闭所有窗口
return 0;
}
然后在终端输入
cd Ultra-Light-Fast-Generic-Face-Detector-1MB/ncnn/build
make -j4
将修改好的 main.cpp 编译完成后即可下载人脸检测的视频并进行检测:
推荐的视频下载网站:视觉中国旗下网站(https://www.vcg.com/creative-video/)
下载好视频后,复制到 ncnn 的 data 文件夹下,然后重命名为 test.mp4。
运行下面的测试命令即可进行测试:
./main ../data/version-RFB/RFB-320.bin ../data/version-RFB/RFB-320.param ../data/test.mp4
测试结果如图所示:
CPU 资源占用等数据的获取
此时通过在终端中输入 top:
即可获得代码运行过程中占用资源的数据。
其中 CPU 占用量最大的就是当前的人脸检测代码。
如果想要减少 CPU 的占用,可以使用 version-slim-320 模型。
命令为:
./main ../data/version-slim/slim_320.bin ../data/version-slim/slim_320.param ../data/test.mp4