yolov5部署 单线程与多线程对比

单线程

部署代码可参考:

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是比较慢)。

其实这里获取主线程获取图像很快,主要是检测比较耗时;我感觉主线程获取的图像一直在排队等待被检测。

猜你喜欢

转载自blog.csdn.net/weixin_45824067/article/details/132239123
今日推荐