opencv处理图像(二)
接下来进入到程序线程设计部分
我们主线程负责图形渲染等操作,OpenGL的限制,opencv技术对传入图像加以处理,输出预期图像给主线程
QThread
我之前也是在想给opencv开一个专门的线程,但经过了解有几个弊端,第一资源浪费,县城遗址占用问题,分线程并不是一致工作。第二,需要手动管理线程生命周期,频繁的创建和释放影响性能。
实现试例
// 1. 继承 QThread 并重写 run()
class WorkerThread : public QThread {Q_OBJECT
protected:void run() override {while (!isInterruptionRequested()) {// OpenCV 处理逻辑cv::Mat frame = processFrame();emit resultReady(frame); // 通过信号传递结果}}
signals:void resultReady(cv::Mat frame);
};// 2. 在主线程中启动
WorkerThread *thread = new WorkerThread;
connect(thread, &WorkerThread::resultReady, this, &MainWindow::updateGL);
thread->start();// 3. 安全停止线程
thread->requestInterruption();
thread->quit();
thread->wait();
QThreadPool+QRannable线程池技术
线程池通过设置可复用线程,有任务就调度空闲线程运行,实现了线程的复用,线程数可根据计算机的核的数量选择
QT封装了线程池,提供了一个全局的线程池函数
globalInstance()
要用的时候把对象或者函数指针丢进去。
// 定义任务类
class ImageTask : public QRunnable {
public:ImageTask(cv::Mat input, QString method) : m_input(input), m_method(method) {// 任务完成后自动删除(默认不启用)setAutoDelete(true); }void run() override {cv::Mat result = processImage(m_input, m_method);// 发送结果到主线程(通过信号槽或 invokeMethod)QMetaObject::invokeMethod(m_receiver, "updateDisplay", Qt::QueuedConnection, Q_ARG(cv::Mat, result));}private:cv::Mat m_input;QString m_method;QObject *m_receiver; // 接收结果的对象(如主窗口)
};// 提交任务到线程池
cv::Mat inputImage = ...;
QString method = "Grayscale";
ImageTask *task = new ImageTask(inputImage, method);
QThreadPool::globalInstance()->start(task);
再一个就是深拷贝的问题,从主线程把图像深拷贝到分支线程有很多弊端,我考虑优化一下逻辑,比如opencv对图像进行一些识别操作的时候会先把他转换程一个灰度图,再高斯模糊canny边缘检测等等,一些可复用的图像可不可以在主程序存下来,要用的时候通过移动语义将所有权直接传到分支线程处理,避免了一些频繁深度拷贝的问题,这是我的一些思路,有在这方面有见解的大佬可以指点一二。
方案 | 适用性 | 场景匹配度 |
---|---|---|
QThread | 适合持续运行的任务(如实时视频流处理),线程生命周期长,需手动管理启停 | 低(任务离散触发) |
线程池 | 适合短暂、离散的任务(如点击按钮触发单次处理),自动复用线程,减少开销 | 高 |
核心流程
主线程(UI线程):
1. 用户点击按钮 → 提交处理任务到线程池
2. 等待处理结果 → 接收结果并更新OpenGL显示线程池(工作线程):
1. 接收待处理图像和参数(如高斯模糊、灰度化)
2. OpenCV处理 → 返回结果图像