赞
踩
上一篇文章:yolov5目标检测多线程C++部署
mainwindow.h
#pragma once #include <iostream> #include <QMainWindow> #include <QFileDialog> #include <QThread> #include <opencv2/opencv.hpp> #include "yolov5.h" #include "blockingconcurrentqueue.h" QT_BEGIN_NAMESPACE namespace Ui { class MainWindow; } using namespace moodycamel; QT_END_NAMESPACE class Infer1 : public QThread { Q_OBJECT public slots: void receive_image(){}; private: void run(); private: cv::Mat input_image; cv::Mat blob; cv::Mat output_image; std::vector<cv::Mat> network_outputs; signals: void send_image(); }; class Infer2 : public QThread { Q_OBJECT public slots: void receive_image(){}; private: void run(); private: cv::Mat input_image; cv::Mat blob; cv::Mat output_image; std::vector<cv::Mat> network_outputs; signals: void send_image(); }; class MainWindow : public QMainWindow { Q_OBJECT public: MainWindow(QWidget *parent = nullptr); ~MainWindow(); private slots: void on_pushButton_open_video_clicked(); void receive_image(); private: Ui::MainWindow *ui; Infer1 *infer1; Infer2 *infer2; signals: void send_image(); };
mainwindow.cpp
#include "mainwindow.h" #include "ui_mainwindow.h" bool stop = false; BlockingConcurrentQueue<cv::Mat> bcq_capture1, bcq_infer1; BlockingConcurrentQueue<cv::Mat> bcq_capture2, bcq_infer2; void print_time(int id) { auto now = std::chrono::system_clock::now(); uint64_t dis_millseconds = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch()).count() - std::chrono::duration_cast<std::chrono::seconds>(now.time_since_epoch()).count() * 1000; time_t tt = std::chrono::system_clock::to_time_t(now); auto time_tm = localtime(&tt); char time[100] = { 0 }; sprintf(time, "%d-%02d-%02d %02d:%02d:%02d %03d", time_tm->tm_year + 1900, time_tm->tm_mon + 1, time_tm->tm_mday, time_tm->tm_hour, time_tm->tm_min, time_tm->tm_sec, (int)dis_millseconds); std::cout << "infer" << std::to_string(id) << " 当前时间为:" << time << std::endl; } void Infer1::run() { cv::dnn::Net net = cv::dnn::readNet("yolov5n-w640h352.onnx"); while (true) { if(stop) break; if(bcq_capture1.try_dequeue(input_image)) { pre_process(input_image, blob); process(blob, net, network_outputs); post_process(input_image, output_image, network_outputs); bcq_infer1.enqueue(output_image); emit send_image(); print_time(1); } } } void Infer2::run() { cv::dnn::Net net = cv::dnn::readNet("yolov5s-w640h352.onnx"); while (true) { if(stop) break; if(bcq_capture2.try_dequeue(input_image)) { pre_process(input_image, blob); process(blob, net, network_outputs); post_process(input_image, output_image, network_outputs); bcq_infer2.enqueue(output_image); emit send_image(); print_time(2); } } } MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , ui(new Ui::MainWindow) { ui->setupUi(this); infer1 = new Infer1; infer2 = new Infer2; connect(infer1, &Infer1::send_image, this, &MainWindow::receive_image); connect(infer2, &Infer2::send_image, this, &MainWindow::receive_image); } MainWindow::~MainWindow() { delete ui; } void MainWindow::receive_image() { cv::Mat output_image; if(bcq_infer1.try_dequeue(output_image)) { QImage image = QImage((const uchar*)output_image.data, output_image.cols, output_image.rows, QImage::Format_RGB888).rgbSwapped(); ui->label_1->clear(); ui->label_1->setPixmap(QPixmap::fromImage(image)); ui->label_1->show(); } if(bcq_infer2.try_dequeue(output_image)) { QImage image = QImage((const uchar*)output_image.data, output_image.cols, output_image.rows, QImage::Format_RGB888).rgbSwapped(); ui->label_2->clear(); ui->label_2->setPixmap(QPixmap::fromImage(image)); ui->label_2->show(); } } void MainWindow::on_pushButton_open_video_clicked() { QString qstr = QFileDialog::getOpenFileName(this, tr("Open Video"), "", tr("(*.mp4 *.avi *.mkv)")); if(qstr.isEmpty()) return; infer1->start(); infer2->start(); cv::VideoCapture cap; cap.open(qstr.toStdString()); while (cv::waitKey(1) < 0) { cv::Mat frame; cap.read(frame); if (frame.empty()) { stop = true; break; } bcq_capture1.enqueue(frame); bcq_capture2.enqueue(frame); } }
这里引入的第三方库moodycamel::ConcurrentQueue是一个用C++11实现的多生产者、多消费者无锁队列。
程序输出:
infer1 当前时间为:2023-08-12 13:17:14 402 infer2 当前时间为:2023-08-12 13:17:14 424 infer1 当前时间为:2023-08-12 13:17:14 448 infer2 当前时间为:2023-08-12 13:17:14 480 infer1 当前时间为:2023-08-12 13:17:14 494 infer2 当前时间为:2023-08-12 13:17:14 532 infer1 当前时间为:2023-08-12 13:17:14 544 infer2 当前时间为:2023-08-12 13:17:14 586 infer1 当前时间为:2023-08-12 13:17:14 590 infer1 当前时间为:2023-08-12 13:17:14 637 infer2 当前时间为:2023-08-12 13:17:14 645 infer1 当前时间为:2023-08-12 13:17:14 678 infer2 当前时间为:2023-08-12 13:17:14 702 infer1 当前时间为:2023-08-12 13:17:14 719 infer2 当前时间为:2023-08-12 13:17:14 758 infer1 当前时间为:2023-08-12 13:17:14 760 infer1 当前时间为:2023-08-12 13:17:14 808 infer2 当前时间为:2023-08-12 13:17:14 817 infer1 当前时间为:2023-08-12 13:17:14 852 infer2 当前时间为:2023-08-12 13:17:14 881 ...
界面效果:
可以看到,上面的程序实现了两个模型的多线程推理,但由于不同模型推理速度有差异,导致画面显示不同步。另外,把读取视频帧的实现写入主线程时,一旦视频帧读取结束则无法处理后面的帧,导致显示卡死。
mainwindow.h
#pragma once #include <iostream> #include <QMainWindow> #include <QFileDialog> #include <QThread> #include <opencv2/opencv.hpp> #include "yolov5.h" #include "blockingconcurrentqueue.h" QT_BEGIN_NAMESPACE namespace Ui { class MainWindow; } using namespace moodycamel; QT_END_NAMESPACE class Capture : public QThread { Q_OBJECT public: void set_video(QString video) { cap.open(video.toStdString()); } private: void run(); private: cv::VideoCapture cap; }; class Infer1 : public QThread { Q_OBJECT public slots: void receive_image(){}; private: void run(); private: cv::Mat input_image; cv::Mat blob; cv::Mat output_image; std::vector<cv::Mat> network_outputs; signals: void send_image(); }; class Infer2 : public QThread { Q_OBJECT public slots: void receive_image(){}; private: void run(); private: cv::Mat input_image; cv::Mat blob; cv::Mat output_image; std::vector<cv::Mat> network_outputs; signals: void send_image(); }; class MainWindow : public QMainWindow { Q_OBJECT public: MainWindow(QWidget *parent = nullptr); ~MainWindow(); private slots: void on_pushButton_open_video_clicked(); void receive_image(); private: Ui::MainWindow *ui; QString video; Capture *capture; Infer1 *infer1; Infer2 *infer2; signals: void send_image(); };
mainwindow.cpp
#include "mainwindow.h" #include "ui_mainwindow.h" bool stop = false; BlockingConcurrentQueue<cv::Mat> bcq_capture1, bcq_infer1; BlockingConcurrentQueue<cv::Mat> bcq_capture2, bcq_infer2; void print_time(int id) { auto now = std::chrono::system_clock::now(); uint64_t dis_millseconds = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch()).count() - std::chrono::duration_cast<std::chrono::seconds>(now.time_since_epoch()).count() * 1000; time_t tt = std::chrono::system_clock::to_time_t(now); auto time_tm = localtime(&tt); char time[100] = { 0 }; sprintf(time, "%d-%02d-%02d %02d:%02d:%02d %03d", time_tm->tm_year + 1900, time_tm->tm_mon + 1, time_tm->tm_mday, time_tm->tm_hour, time_tm->tm_min, time_tm->tm_sec, (int)dis_millseconds); std::cout << "infer" << std::to_string(id) << " 当前时间为:" << time << std::endl; } void Capture::run() { while (cv::waitKey(50) < 0) { cv::Mat frame; cap.read(frame); if (frame.empty()) { stop = true; break; } bcq_capture1.enqueue(frame); bcq_capture2.enqueue(frame); } } void Infer1::run() { cv::dnn::Net net = cv::dnn::readNet("yolov5n-w640h352.onnx"); while (true) { if(stop) break; if(bcq_capture1.try_dequeue(input_image)) { pre_process(input_image, blob); process(blob, net, network_outputs); post_process(input_image, output_image, network_outputs); bcq_infer1.enqueue(output_image); emit send_image(); print_time(1); } } } void Infer2::run() { cv::dnn::Net net = cv::dnn::readNet("yolov5s-w640h352.onnx"); while (true) { if(stop) break; if(bcq_capture2.try_dequeue(input_image)) { pre_process(input_image, blob); process(blob, net, network_outputs); post_process(input_image, output_image, network_outputs); bcq_infer2.enqueue(output_image); emit send_image(); print_time(2); } } } MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , ui(new Ui::MainWindow) { ui->setupUi(this); capture = new Capture; infer1 = new Infer1; infer2 = new Infer2; connect(infer1, &Infer1::send_image, this, &MainWindow::receive_image); connect(infer2, &Infer2::send_image, this, &MainWindow::receive_image); } MainWindow::~MainWindow() { delete ui; } void MainWindow::receive_image() { cv::Mat output_image; if(bcq_infer1.try_dequeue(output_image)) { QImage image = QImage((const uchar*)output_image.data, output_image.cols, output_image.rows, QImage::Format_RGB888).rgbSwapped(); ui->label_1->clear(); ui->label_1->setPixmap(QPixmap::fromImage(image)); ui->label_1->show(); } if(bcq_infer2.try_dequeue(output_image)) { QImage image = QImage((const uchar*)output_image.data, output_image.cols, output_image.rows, QImage::Format_RGB888).rgbSwapped(); ui->label_2->clear(); ui->label_2->setPixmap(QPixmap::fromImage(image)); ui->label_2->show(); } } void MainWindow::on_pushButton_open_video_clicked() { video = QFileDialog::getOpenFileName(this, tr("Open Video"), "", tr("(*.mp4 *.avi *.mkv)")); if(video.isEmpty()) return; capture->set_video(video); capture->start(); infer1->start(); infer2->start(); }
界面显示:
和V2比较,V3的改动不大,仅增加在视频播放完成时发出信号调用清除界面显示的功能。
mainwindow.h
#pragma once #include <iostream> #include <QMainWindow> #include <QFileDialog> #include <QThread> #include <opencv2/opencv.hpp> #include "yolov5.h" #include "blockingconcurrentqueue.h" QT_BEGIN_NAMESPACE namespace Ui { class MainWindow; } using namespace moodycamel; QT_END_NAMESPACE class Capture : public QThread { Q_OBJECT public: void set_video(QString video) { cap.open(video.toStdString()); } private: void run(); private: cv::VideoCapture cap; signals: void stop(); }; class Infer1 : public QThread { Q_OBJECT private: void run(); private: cv::Mat input_image; cv::Mat blob; cv::Mat output_image; std::vector<cv::Mat> network_outputs; signals: void send_image(); }; class Infer2 : public QThread { Q_OBJECT private: void run(); private: cv::Mat input_image; cv::Mat blob; cv::Mat output_image; std::vector<cv::Mat> network_outputs; signals: void send_image(); }; class MainWindow : public QMainWindow { Q_OBJECT public: MainWindow(QWidget *parent = nullptr); ~MainWindow(); private slots: void on_pushButton_open_video_clicked(); void receive_image(); void clear_image(); private: Ui::MainWindow *ui; QString video; Capture *capture; Infer1 *infer1; Infer2 *infer2; };
mainwindow.cpp
#include "mainwindow.h" #include "ui_mainwindow.h" bool flag = false; BlockingConcurrentQueue<cv::Mat> bcq_capture1, bcq_infer1; BlockingConcurrentQueue<cv::Mat> bcq_capture2, bcq_infer2; void print_time(int id) { auto now = std::chrono::system_clock::now(); uint64_t dis_millseconds = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch()).count() - std::chrono::duration_cast<std::chrono::seconds>(now.time_since_epoch()).count() * 1000; time_t tt = std::chrono::system_clock::to_time_t(now); auto time_tm = localtime(&tt); char time[100] = { 0 }; sprintf(time, "%d-%02d-%02d %02d:%02d:%02d %03d", time_tm->tm_year + 1900, time_tm->tm_mon + 1, time_tm->tm_mday, time_tm->tm_hour, time_tm->tm_min, time_tm->tm_sec, (int)dis_millseconds); std::cout << "infer" << std::to_string(id) << " 当前时间为:" << time << std::endl; } void Capture::run() { while (cv::waitKey(50) < 0) { cv::Mat frame; cap.read(frame); if (frame.empty()) { flag = true; emit stop(); break; } bcq_capture1.enqueue(frame); bcq_capture2.enqueue(frame); } } void Infer1::run() { cv::dnn::Net net = cv::dnn::readNet("yolov5n-w640h352.onnx"); while (true) { if(flag) break; if(bcq_capture1.try_dequeue(input_image)) { pre_process(input_image, blob); process(blob, net, network_outputs); post_process(input_image, output_image, network_outputs); bcq_infer1.enqueue(output_image); emit send_image(); print_time(1); } std::this_thread::yield(); } } void Infer2::run() { cv::dnn::Net net = cv::dnn::readNet("yolov5s-w640h352.onnx"); while (true) { if(flag) break; if(bcq_capture2.try_dequeue(input_image)) { pre_process(input_image, blob); process(blob, net, network_outputs); post_process(input_image, output_image, network_outputs); bcq_infer2.enqueue(output_image); emit send_image(); print_time(2); } std::this_thread::yield(); } } MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , ui(new Ui::MainWindow) { ui->setupUi(this); capture = new Capture; infer1 = new Infer1; infer2 = new Infer2; connect(infer1, &Infer1::send_image, this, &MainWindow::receive_image); connect(infer2, &Infer2::send_image, this, &MainWindow::receive_image); connect(capture, &Capture::stop, this, &MainWindow::clear_image); } MainWindow::~MainWindow() { delete ui; } void MainWindow::on_pushButton_open_video_clicked() { video = QFileDialog::getOpenFileName(this, tr("Open Video"), "", tr("(*.mp4 *.avi *.mkv)")); if(video.isEmpty()) return; capture->set_video(video); capture->start(); infer1->start(); infer2->start(); } void MainWindow::receive_image() { cv::Mat output_image; if(bcq_infer1.try_dequeue(output_image)) { QImage image = QImage((const uchar*)output_image.data, output_image.cols, output_image.rows, QImage::Format_RGB888).rgbSwapped(); ui->label_1->clear(); ui->label_1->setPixmap(QPixmap::fromImage(image)); ui->label_1->show(); } if(bcq_infer2.try_dequeue(output_image)) { QImage image = QImage((const uchar*)output_image.data, output_image.cols, output_image.rows, QImage::Format_RGB888).rgbSwapped(); ui->label_2->clear(); ui->label_2->setPixmap(QPixmap::fromImage(image)); ui->label_2->show(); } } void MainWindow::clear_image() { ui->label_1->clear(); ui->label_2->clear(); }
mainwindow.h
#pragma once #include <iostream> #include <QMainWindow> #include <QFileDialog> #include <QThread> #include <QMutex> #include <QWaitCondition> #include <opencv2/opencv.hpp> #include "yolov5.h" QT_BEGIN_NAMESPACE namespace Ui { class MainWindow; } QT_END_NAMESPACE class Capture : public QThread { Q_OBJECT public: void set_video(QString video) { cap.open(video.toStdString()); } private: void run(); private: cv::VideoCapture cap; signals: void stop(); }; class Infer1 : public QThread { Q_OBJECT public: void set_model(QString model) { net = cv::dnn::readNet(model.toStdString()); } private: void run(); private: cv::dnn::Net net; cv::Mat input_image; cv::Mat blob; cv::Mat output_image; std::vector<cv::Mat> network_outputs; signals: void send_image(); void stop(); }; class Infer2 : public QThread { Q_OBJECT public: void set_model(QString model) { net = cv::dnn::readNet(model.toStdString()); } private: void run(); private: cv::dnn::Net net; cv::Mat input_image; cv::Mat blob; cv::Mat output_image; std::vector<cv::Mat> network_outputs; signals: void send_image(); void stop(); }; class MainWindow : public QMainWindow { Q_OBJECT public: MainWindow(QWidget *parent = nullptr); ~MainWindow(); private slots: void on_pushButton_open_video_clicked(); void receive_image(); void clear_image(); private: Ui::MainWindow *ui; QString video; Capture *capture; Infer1 *infer1; Infer2 *infer2; };
mainwindow.cpp
#include "mainwindow.h" #include "ui_mainwindow.h" bool video_end = false; QMutex mutex1, mutex2; QWaitCondition qwc1, qwc2; cv::Mat g_frame1, g_frame2; cv::Mat g_result1, g_result2; void print_time(int id) { auto now = std::chrono::system_clock::now(); uint64_t dis_millseconds = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch()).count() - std::chrono::duration_cast<std::chrono::seconds>(now.time_since_epoch()).count() * 1000; time_t tt = std::chrono::system_clock::to_time_t(now); auto time_tm = localtime(&tt); char time[100] = { 0 }; sprintf(time, "%d-%02d-%02d %02d:%02d:%02d %03d", time_tm->tm_year + 1900, time_tm->tm_mon + 1, time_tm->tm_mday, time_tm->tm_hour, time_tm->tm_min, time_tm->tm_sec, (int)dis_millseconds); std::cout << "infer" << std::to_string(id) << " 当前时间为:" << time << std::endl; } void Capture::run() { while (cv::waitKey(1) < 0) { cv::Mat frame; cap.read(frame); if (frame.empty()) { video_end = true; cap.release(); emit stop(); break; } g_frame1 = frame; qwc1.wakeAll(); g_frame2 = frame; qwc2.wakeAll(); } } void Infer1::run() { while (true) { if(video_end) { emit stop(); break; } mutex1.lock(); qwc1.wait(&mutex1); input_image = g_frame1; pre_process(input_image, blob); process(blob, net, network_outputs); post_process(input_image, output_image, network_outputs); g_result1 = output_image; emit send_image(); mutex1.unlock(); print_time(1); } } void Infer2::run() { while (true) { if(video_end) { emit stop(); break; } mutex2.lock(); qwc2.wait(&mutex2); input_image = g_frame2; pre_process(input_image, blob); process(blob, net, network_outputs); post_process(input_image, output_image, network_outputs); g_result2 = output_image; emit send_image(); mutex2.unlock(); print_time(2); } } MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , ui(new Ui::MainWindow) { ui->setupUi(this); capture = new Capture; infer1 = new Infer1; infer2 = new Infer2; connect(capture, &Capture::stop, this, &MainWindow::clear_image); connect(infer1, &Infer1::send_image, this, &MainWindow::receive_image); connect(infer1, &Infer1::stop, this, &MainWindow::clear_image); connect(infer2, &Infer2::send_image, this, &MainWindow::receive_image); connect(infer2, &Infer2::stop, this, &MainWindow::clear_image); } MainWindow::~MainWindow() { delete ui; } void MainWindow::on_pushButton_open_video_clicked() { video = QFileDialog::getOpenFileName(this, tr("Open Video"), "", tr("(*.mp4 *.avi *.mkv)")); if(video.isEmpty()) return; video_end = false; capture->set_video(video); infer1->set_model("yolov5n-w640h352.onnx"); infer2->set_model("yolov5s-w640h352.onnx"); capture->start(); infer1->start(); infer2->start(); } void MainWindow::receive_image() { QImage image1 = QImage((const uchar*)g_result1.data, g_result1.cols, g_result1.rows, QImage::Format_RGB888).rgbSwapped(); ui->label_1->clear(); ui->label_1->setPixmap(QPixmap::fromImage(image1)); ui->label_1->show(); QImage image2 = QImage((const uchar*)g_result2.data, g_result2.cols, g_result2.rows, QImage::Format_RGB888).rgbSwapped(); ui->label_2->clear(); ui->label_2->setPixmap(QPixmap::fromImage(image2)); ui->label_2->show(); } void MainWindow::clear_image() { ui->label_1->clear(); ui->label_2->clear(); capture->quit(); infer1->quit(); infer2->quit(); }
mainwindow.h
#pragma once #include <iostream> #include <string> #include <queue> #include <thread> #include <mutex> #include <condition_variable> #include <future> #include <ctime> #include <windows.h> #include <QMainWindow> #include <QFileDialog> #include <QThread> #include <QMutex> #include <QWaitCondition> #include <opencv2/opencv.hpp> #include "yolov5.h" QT_BEGIN_NAMESPACE namespace Ui { class MainWindow; } QT_END_NAMESPACE class Capture : public QThread { Q_OBJECT public: void set_capture(QString video) { cap.open(video.toStdString()); } private: void run(); private: cv::VideoCapture cap; signals: void show(); void stop(); }; class Infer1 : public QThread { Q_OBJECT public: void set_model(QString model) { net = cv::dnn::readNet(model.toStdString()); } private: void run(); private: cv::dnn::Net net; cv::Mat input_image; cv::Mat blob; cv::Mat output_image; std::vector<cv::Mat> network_outputs; }; class Infer2 : public QThread { Q_OBJECT public: void set_model(QString model) { net = cv::dnn::readNet(model.toStdString()); } private: void run(); private: cv::dnn::Net net; cv::Mat input_image; cv::Mat blob; cv::Mat output_image; std::vector<cv::Mat> network_outputs; }; class MainWindow : public QMainWindow { Q_OBJECT public: MainWindow(QWidget *parent = nullptr); ~MainWindow(); private slots: void receive_image(); void clear_image(); void on_pushButton_open_video_clicked(); private: Ui::MainWindow *ui; QString video; Capture *capture; Infer1 *infer1; Infer2 *infer2; };
mainwindow.cpp
#include "mainwindow.h" #include "ui_mainwindow.h" struct Job { cv::Mat input_image; std::shared_ptr<std::promise<cv::Mat>> output_image; }; std::queue<Job> jobs1, jobs2; std::mutex lock1, lock2; std::condition_variable cv1, cv2; cv::Mat result1, result2; const int limit = 10; bool video_end = false; void print_time(int id) { auto now = std::chrono::system_clock::now(); uint64_t dis_millseconds = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch()).count() - std::chrono::duration_cast<std::chrono::seconds>(now.time_since_epoch()).count() * 1000; time_t tt = std::chrono::system_clock::to_time_t(now); auto time_tm = localtime(&tt); char time[100] = { 0 }; sprintf(time, "%d-%02d-%02d %02d:%02d:%02d %03d", time_tm->tm_year + 1900, time_tm->tm_mon + 1, time_tm->tm_mday, time_tm->tm_hour, time_tm->tm_min, time_tm->tm_sec, (int)dis_millseconds); std::cout << "infer" << std::to_string(id) << ": 当前时间为:" << time << std::endl; } void Capture::run() { while (cv::waitKey(1) < 0) { Job job1, job2; cv::Mat frame; cap.read(frame); if (frame.empty()) { video_end = true; emit stop(); break; } { std::unique_lock<std::mutex> l1(lock1); cv1.wait(l1, [&]() { return jobs1.size()<limit; }); job1.input_image = frame; job1.output_image.reset(new std::promise<cv::Mat>()); jobs1.push(job1); } { std::unique_lock<std::mutex> l2(lock2); cv1.wait(l2, [&]() { return jobs2.size() < limit; }); job2.input_image = frame; job2.output_image.reset(new std::promise<cv::Mat>()); jobs2.push(job2); } result1 = job1.output_image->get_future().get(); result2 = job2.output_image->get_future().get(); emit show(); } } void Infer1::run() { while (true) { if (video_end) break; //不加线程无法退出 if (!jobs1.empty()) { std::lock_guard<std::mutex> l1(lock1); auto job = jobs1.front(); jobs1.pop(); cv1.notify_all(); cv::Mat input_image = job.input_image, blob, output_image; pre_process(input_image, blob); std::vector<cv::Mat> network_outputs; process(blob, net, network_outputs); post_process(input_image, output_image, network_outputs); job.output_image->set_value(output_image); print_time(0); } std::this_thread::yield(); //不加线程无法退出 } } void Infer2::run() { cv::dnn::Net net = cv::dnn::readNet("yolov5s-w640h352.onnx"); while (true) { if (video_end) break; if (!jobs2.empty()) { std::lock_guard<std::mutex> l2(lock2); auto job = jobs2.front(); jobs2.pop(); cv2.notify_all(); cv::Mat input_image = job.input_image, blob, output_image; pre_process(input_image, blob); std::vector<cv::Mat> network_outputs; process(blob, net, network_outputs); post_process(input_image, output_image, network_outputs); job.output_image->set_value(output_image); print_time(1); } std::this_thread::yield(); } } MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , ui(new Ui::MainWindow) { ui->setupUi(this); capture = new Capture; infer1 = new Infer1; infer2 = new Infer2; connect(capture, &Capture::stop, this, &MainWindow::clear_image); connect(capture, &Capture::show, this, &MainWindow::receive_image); } MainWindow::~MainWindow() { delete ui; } void MainWindow::receive_image() { QImage image1 = QImage((const uchar*)result1.data, result1.cols, result1.rows, QImage::Format_RGB888).rgbSwapped(); ui->label_1->clear(); ui->label_1->setPixmap(QPixmap::fromImage(image1)); ui->label_1->show(); QImage image2 = QImage((const uchar*)result2.data, result2.cols, result2.rows, QImage::Format_RGB888).rgbSwapped(); ui->label_2->clear(); ui->label_2->setPixmap(QPixmap::fromImage(image2)); ui->label_2->show(); } void MainWindow::clear_image() { ui->label_1->clear(); ui->label_2->clear(); capture->quit(); infer1->quit(); infer2->quit(); } void MainWindow::on_pushButton_open_video_clicked() { video = QFileDialog::getOpenFileName(this, tr("Open Video"), "", tr("(*.mp4 *.avi *.mkv *mpg *wmv)")); if(video.isEmpty()) return; video_end = false; capture->set_capture(video); infer1->set_model("yolov5n-w640h352.onnx"); infer2->set_model("yolov5s-w640h352.onnx"); capture->start(); infer1->start(); infer2->start(); }
完整工程下载链接:yolov5目标检测多线程Qt界面
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。