1.前言
之前在rpi5 上折腾了pytorch的yolov5lite,一开始使用imx219摄像头,结果在最新的raspberry pi os 上遇到了opencv-python不兼容libcamera的问题,无法通过python的opencv调用摄像头;然后就又破费买了USB摄像头,成功在480*320分辨率下实现10fps的实时检测。然后跟着教程把模型文件转换成onnx,结果测试时帧率反而降低了,之后便不了了之。。。后来闲着没事翻看国外论坛,发现树莓派5 ncnn下的yolov8nano在640*640分辨率下最高可达20fps,这就有了这篇文章的折腾过程。最终实际测试除非调小输入尺寸,不然只有10~15fps。
这里给出原帖链接Qengineering/YoloV8-ncnn-Raspberry-Pi-4: YoloV8 for a bare Raspberry Pi 4 (github.com)
2.部署NCNN
以下全部内容都在树莓派官方系统raspberry pi os 64bit (bookworm)上部署。
# 检查更新
sudo apt-get update
sudo apt-get upgrade
# 安装依赖
sudo apt-get install cmake wget
sudo apt-get install build-essential gcc g++
sudo apt-get install libprotobuf-dev protobuf-compiler
# 下载ncnn项目文件
git clone --depth=1 https://github.com/Tencent/ncnn.git
cd ncnn
mkdir build
cd build
# 编译ncnn
cmake -D NCNN_DISABLE_RTTI=OFF -D NCNN_BUILD_TOOLS=ON \
-D CMAKE_TOOLCHAIN_FILE=../toolchains/aarch64-linux-gnu.toolchain.cmake ..
make -j4
make install
# 把文件移到/usr/local/目录
sudo mkdir /usr/local/lib/ncnn
sudo cp -r install/include/ncnn /usr/local/include/ncnn
sudo cp -r install/lib/libncnn.a /usr/local/lib/ncnn/libncnn.a
3.编译OpenCV
这一步耗时最长,花了我一个多小时,如果手上的树莓派内存不是8GB的,在进行这一步之前应先调制系统的交换空间大小(交换空间大小+可用内存需大于5.8GB),由于我的树莓派的内存是8GB的,故无需此操作。各版本opencv的编译自动化脚本见文章最上面,运行后一键编译+安装。
# 把下载的opencv编译脚本放到根目录
# 赋予权限
sudo chmod 755 OpenCV-4-9-0.sh
# 运行脚本
bash OpenCV-4-9-0.sh
4.打开项目并成功运行
opencv编译成功后,再通过wget下载yolov8项目文件
wget https://github.com/Qengineering/YoloV8-ncnn-Raspberry-Pi-4/archive/refs/heads/main.zip
解压后,使用code::blocks打开.cbp格式文件,如果没安装,输入如下命令:
sudo apt-get install codeblocks
然后将debug模式改成release,点击编译后运行,成功对测试图像进行检测。
最后修改yolov8main.cpp代码,测试下视频的检测。
#include "yoloV8.h"
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <iostream>
#include <stdio.h>
#include <vector>
YoloV8 yolov8;
int target_size = 640; //416; //320; must be divisible by 32.
int main(int argc, char** argv)
{
const char* videopath = "/path/to/video.mp4";
cv::VideoCapture cap(videopath);
if (!cap.isOpened())
{
fprintf(stderr, "Failed to open video file\n");
return -1;
}
yolov8.load(target_size);
cv::Mat frame;
std::vector<Object> objects;
while (cap.read(frame))
{
yolov8.detect(frame, objects);
yolov8.draw(frame, objects);
cv::imshow("Video", frame);
cv::waitKey(1);
objects.clear();
}
cap.release();
return 0;
}
结果如下,target_size设置为640,输入视频大小为1280*720 30fps,输出视频目测只有5~10fps,此时cpu占用75%左右;对比pytorch下原生yolov5 cpu 100%占用而只有0.3fps,已经是巨大提升了。
接下来是摄像头实时检测
#include "yoloV8.h"
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <iostream>
#include <stdio.h>
#include <vector>
#include <chrono>
YoloV8 yolov8;
int target_size = 640; //416; //320; must be divisible by 32.
int main()
{
// 设置摄像头分辨率
int desired_width = 800;
int desired_height = 600;
cv::VideoCapture cap(0); // Open the default camera (index 0)
if (!cap.isOpened()) // 检查摄像头是否打开
{
std::cerr << "Error: Failed to open camera" << std::endl;
return -1;
}
// 摄像头分辨率
cap.set(cv::CAP_PROP_FRAME_WIDTH, desired_width);
cap.set(cv::CAP_PROP_FRAME_HEIGHT, desired_height);
yolov8.load(target_size); // Load model (once)
cv::Mat frame;
double fps = 0;
while (true)
{
auto start = std::chrono::steady_clock::now();
cap >> frame;
if (frame.empty())
{
std::cerr << "Error: Failed to capture frame" << std::endl;
break;
}
std::vector<Object> objects;
yolov8.detect(frame, objects);
yolov8.draw(frame, objects);
// 计算FPS
auto end = std::chrono::steady_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count();
fps = 1000.0 / duration;
// 显示帧率
cv::putText(frame, "FPS: " + std::to_string(fps), cv::Point(10, 30), cv::FONT_HERSHEY_SIMPLEX, 1, cv::Scalar(0, 255, 0), 2);
cv::imshow("Camera", frame);
if (cv::waitKey(1) == 27) // ESC退出循环
break;
}
cap.release(); // 释放摄像头
cv::destroyAllWindows(); // 关闭窗口
return 0;
}
测试结果
target_size为640,摄像头分辨率为1280*720时帧率为6.5。
target_size为480,摄像头分辨率为800*600时帧率为10。
不知道什么原因,并没有达到所说的20fps