单线程
部署代码可参考:
Yolov5 ONNX Runtime 的 C++部署_爱钓鱼的歪猴的博客-CSDN博客
main.cpp
#include "detector.h"
#include <chrono>
using namespace std;
// 识别线程
void *detect_thread_entry(void *para){
}
int main(int argc, char *argv[])
{
auto start1 = std::chrono::system_clock::now();
Detector detector;
bool isGPU=false;
Utils utils;
const vector<string> classNames=utils.loadNames("/home/lrj/work/file/coco.names");
if(classNames.empty()){
cerr<<"Error: Empty class names file"<<endl;
return -1;
}
cv::Mat image;
vector<Detection> result;
cv::VideoCapture capture(2);
if (!capture.isOpened())
return 1;
auto end1 = std::chrono::system_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end1 - start1);
cout << " " << endl;
printf("init time use: %ld ms", duration);
while(1){
auto start2 = std::chrono::system_clock::now();
capture >> image;
try{
detector.YOLODetector(isGPU,cv::Size(640,640));
cout<<"Model was initialized......"<<endl;
int ret = detector.detect(image,0.4,0.4, result);
}catch(const exception& e){
cerr<<e.what()<<endl;
return -1;
}
utils.visualizeDetection(image,result,classNames);
auto end2 = std::chrono::system_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end2 - start2);
string text = "time use: " + std::to_string(duration.count()) + "ms";
cv::putText(image, text, cv::Point(30, 30), cv::FONT_HERSHEY_SIMPLEX, 0.5, cv::Scalar(255,0,0),2);
imshow("result", image);
if(cv::waitKey(1) == 'q') break;
}
return 0;
}
这里是单线程,每帧获取耗时200ms左右,也就是fps大概为5;
多线程
#include "detector.h"
#include <chrono>
#include <pthread.h>
#include <unistd.h>
#include "utils.h"
using namespace std;
struct ThreadParams {
vector<Detection> result_;
};
cv::Mat algorithm_image = cv::Mat::zeros(480,640,CV_8UC3);
//pthread_cond_t img_cond = PTHREAD_COND_INITIALIZER;
pthread_mutex_t img_lock;
pthread_mutex_t result_lock;
Utils utils;
const vector<string> classNames=utils.loadNames("/home/lrj/work/file/coco.names");
//识别线程
void *detect_thread_entry(void *para){
// 初始化
Detector detector;
bool isGPU=false;
detector.YOLODetector(isGPU,cv::Size(640,640));
cout<<"Model was initialized......"<<endl;
ThreadParams *pThreadParams = (ThreadParams *) para;
// vector<Detection> result = pThreadParams->result_;
cv::Mat image;
while(1){
auto start = std::chrono::system_clock::now();
// 阻塞等待图像可用
if(algorithm_image.empty()){
cerr << "Error: Failed to retrieve image frame" << endl;
usleep(5);
continue;
}
pthread_mutex_lock(&img_lock); // 加锁
image = algorithm_image.clone(); // 复制图片
pthread_mutex_unlock(&img_lock); // 解锁
pthread_mutex_lock(&result_lock); // 加锁
int ret = detector.detect(image,0.4,0.4, pThreadParams->result_); // 检测
pthread_mutex_unlock(&result_lock); // 解锁
auto end = std::chrono::system_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
string text = "yolov5n detect time use: " + std::to_string(duration.count()) + "ms";
cout << text + "\n" + "\n" << endl;
if(pThreadParams->result_.size() <=0){
usleep(1000);
continue;
}
}
return NULL;
}
int main(int argc, char *argv[])
{
if(classNames.empty()){
cerr<<"Error: Empty class names file"<<endl;
return -1;
}
ThreadParams threadParams;
threadParams.result_ = std::vector<Detection> ();
pthread_t mTid;
// 1.打开摄像头
cv::VideoCapture camera(2);
if (!camera.isOpened())
return -1;
int width = camera.get(cv::CAP_PROP_FRAME_WIDTH);
int height = camera.get(cv::CAP_PROP_FRAME_HEIGHT);
int fps = camera.get(cv::CAP_PROP_FPS);
cout << width << " ||" <<height << fps << endl;
// 跳过前10帧
int skip = 10;
while(skip--){
camera >> algorithm_image;
}
// 2创建识别线程,以及图像互斥锁
pthread_mutex_init(&img_lock, NULL);
pthread_mutex_init(&result_lock, NULL);
pthread_create(&mTid, NULL, detect_thread_entry,(void*)&threadParams);
// 3.(取流 + 显示)循环
cv::Mat img;
while(1){
// 4.1 取流
pthread_mutex_lock(&img_lock);
camera >> algorithm_image;
img = algorithm_image.clone();
// pthread_cond_signal(&img_cond); // 通知识别线程图像可用
pthread_mutex_unlock(&img_lock);
// 4.2 显示
pthread_mutex_lock(&result_lock); // 加锁
utils.visualizeDetection(img,threadParams.result_,classNames);
pthread_mutex_unlock(&result_lock); // 解锁
cv::imshow("result", img);
if(cv::waitKey(1) == 'q') break;
// usleep(150*1000);
}
// pthread_join(mTid, NULL); // 等待识别线程的结束
pthread_mutex_destroy(&img_lock);
pthread_mutex_destroy(&result_lock);
return 0;
}
这里主线程(main函数)负责获取图像及展示图像;识别线程负责yolov5检测,每帧耗时170ms左右(CPU是比较慢)。
其实这里获取主线程获取图像很快,主要是检测比较耗时;我感觉主线程获取的图像一直在排队等待被检测。