接下來進入到程序線程設計部分
我們主線程負責圖形渲染等操作,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處理 → 返回結果圖像
?