yolov5目标检测多线程Qt界面

上一篇文章:yolov5目标检测多线程C++部署

V1 基本功能实现

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_NAMESPACEclass Infer1 : public QThread
{Q_OBJECTpublic 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_OBJECTpublic 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_OBJECTpublic: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
...

界面效果:
在这里插入图片描述

可以看到,上面的程序实现了两个模型的多线程推理,但由于不同模型推理速度有差异,导致画面显示不同步。另外,把读取视频帧的实现写入主线程时,一旦视频帧读取结束则无法处理后面的帧,导致显示卡死。

V2 修正画面不同步问题

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_NAMESPACEclass Capture : public QThread
{Q_OBJECTpublic:void set_video(QString video){cap.open(video.toStdString());}private:void run();private:cv::VideoCapture cap;
};class Infer1 : public QThread
{Q_OBJECTpublic 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_OBJECTpublic 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_OBJECTpublic: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();
}

界面显示:
在这里插入图片描述

V3 修正视频播放完成界面显示问题

和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_NAMESPACEclass Capture : public QThread
{Q_OBJECTpublic:void set_video(QString video){cap.open(video.toStdString());}private:void run();private:cv::VideoCapture cap;signals:void stop();
};class Infer1 : public QThread
{Q_OBJECTprivate: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_OBJECTprivate: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_OBJECTpublic: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();
}

V4 通过Qt自带QThread、QMutex、QWaitCondition实现

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_NAMESPACEclass Capture : public QThread
{Q_OBJECTpublic:void set_video(QString video){cap.open(video.toStdString());}private:void run();private:cv::VideoCapture cap;signals:void stop();
};class Infer1 : public QThread
{Q_OBJECTpublic: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_OBJECTpublic: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_OBJECTpublic: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();
}

V5 通过std::mutex、std::condition_variable、std::promise实现

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_NAMESPACEclass Capture : public QThread
{Q_OBJECTpublic: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_OBJECTpublic: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_OBJECTpublic: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_OBJECTpublic: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();
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/63945.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

前后端分离------后端创建笔记(02)

本文章转载于【SpringBootVue】全网最简单但实用的前后端分离项目实战笔记 - 前端_大菜007的博客-CSDN博客 仅用于学习和讨论&#xff0c;如有侵权请联系 源码&#xff1a;https://gitee.com/green_vegetables/x-admin-project.git 素材&#xff1a;https://pan.baidu.com/s/…

银河麒麟安装php7.1.33

银河麒麟V10兼容CentOS 8 安装过程与CentOS类似。 TencentOS3.1安装PHPNginxredis测试系统_乐大师的博客-CSDN博客 可以参考之前我写的文章。 不过有2个细节不同&#xff0c;下面说下。 问题1&#xff1a;编译错误提示“error:off_t undefined” 解决方法&#xff1a; 编…

LeetCode 1572. 矩阵对角线元素的和

【LetMeFly】1572.矩阵对角线元素的和 力扣题目链接&#xff1a;https://leetcode.cn/problems/matrix-diagonal-sum/ 给你一个正方形矩阵 mat&#xff0c;请你返回矩阵对角线元素的和。 请你返回在矩阵主对角线上的元素和副对角线上且不在主对角线上元素的和。 示例 1&…

中介者模式(C++)

定义 用一个中介对象来封装(封装变化)一系列的对象交互。中介者使各对象不需要显式的相互引用(编译时依赖->运行时依赖)&#xff0c;从而使其耦合松散(管理变化)&#xff0c;而且可以独立地改变它们之间的交互。 应用场景 在软件构建过程中&#xff0c;经常会出现多个对象…

SpringBoot MDC全局链路解决方案

需求 在访问量较大的分布式系统中&#xff0c;时时刻刻在打印着巨量的日志&#xff0c;当我们需要排查问题时&#xff0c;需要从巨量的日志信息中找到本次排查内容的日志是相对复杂的&#xff0c;那么&#xff0c;如何才能使日志看起来逻辑清晰呢&#xff1f;如果每一次请求都…

Centos7.6 安装mysql过程全记录

在centos 7.6上 离线安装mysql 的步骤&#xff0c;可参考下文&#xff1a; 一、查看当前MySQL的安装情况并卸载 1. 查看当前MySQL的安装情况 查找之前是否安装了MySQL rpm -qa|grep -i mysql 2.卸载mysql 如果已经安装mysql&#xff0c;则需要先停止MySQL&#xff0c;再删除…

Fiddler

基础 Fiddler 相当于一个 “代理”,浏览器访问浏览器页面时&#xff0c;就会把HTTP请求先发给Fiddler&#xff0c;Fiddler 再把请求转发给浏览器的服务器&#xff0c;当浏览器服务器返回数据时&#xff0c;Fiddler拿到返回数据&#xff0c;再把数据交给浏览器。 主界面 删除…

【24择校指南】南京大学计算机考研考情分析

南京大学(A) 考研难度&#xff08;☆☆☆☆☆&#xff09; 内容&#xff1a;23考情概况&#xff08;拟录取和复试分数人数统计&#xff09;、院校概况、23初试科目、23复试详情、参考书目、各科目考情分析、各专业考情分析。 正文2178字&#xff0c;预计阅读&#xff1a;6分…

《嵌入式 - 嵌入式大杂烩》SVC和PendSV异常详解

1 操作模式 在讨论PendSV和SVC异常前,需要先了解Cortex-M的模式和两个特权等级。 Figure 1 1 操作模式和特权等级 两种模式为handler模式和线程(thread)模式,这两种模式是为了区别正在执行代码的类型;handler模式为异常处理例程的代码;线程模式为普通应用程序的代码。 两…

机器学习深度学习——RNN的从零开始实现与简洁实现

&#x1f468;‍&#x1f393;作者简介&#xff1a;一位即将上大四&#xff0c;正专攻机器学习的保研er &#x1f30c;上期文章&#xff1a;机器学习&&深度学习——循环神经网络RNN &#x1f4da;订阅专栏&#xff1a;机器学习&&深度学习 希望文章对你们有所帮…

计算机网络 网络层 IPv4地址

A类地址第一位固定0 B类10 其下同理

生产执行MES系统:提升企业灵活性和响应速度的关键利器

在竞争激烈的市场环境下&#xff0c;企业需要不断提高其灵活性和响应速度&#xff0c;以适应快速变化的需求和市场动态。生产执行MES&#xff08;Manufacturing Execution System&#xff09;系统作为信息技术的重要应用&#xff0c;为企业提供了强大的工具和平台&#xff0c;能…