生活随笔
收集整理的這篇文章主要介紹了
Qt与OpenCV编程:在子线程打开摄像头用主线程显示
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
前言
1.在做圖像處理開發中,比例做目標跟蹤識別的時候,用OpenCV一直在處理攝像頭傳入的數據,有時候會出現界面卡死或者未響應的狀態,這是因為事件循環一直等待處理函數的返回而導致阻塞事件循環,這樣一來GUI線程所有的繪制和交互都被阻塞在事件隊列中,無法執行重繪等事件,整個程序就失去響應了。
2.在這種狀態下,為了保證程序的正常運行,最好的方法是把費時的數據處理函數放到別一個線程,處理完成之后再把結果返回給主線程。
在Qt界面中,主線程只要做界面的相關繪制就可以了。
3.在Qt里面,開多線程有幾種方法,其中一種是繼承QThread類之后重寫run函數,還有一種是把繼承于QObject的類轉移到一個Thread里,后面這種是Qt官方在Qt4.8之后推薦的用法。
4.我這里使用QThread打開一個攝像頭,之后用信號把每一幀圖像傳回主線程顯示。
代碼
CameraThread.h
#ifndef CAMERATHREAD_H
#define CAMERATHREAD_H
#include <QThread>
#include <QDebug>
#include <vector>
#include <QString>
#include <opencv2/opencv.hpp>class CameraThread : public QThread
{Q_OBJECT
public:void stop();explicit CameraThread(QObject
*parent
= 0);cv
::VideoCapture cv_cap
;int camera_index
;cv
::Mat cv_src
;protected:void run();private:volatile bool stopped
;signals
:void getImage(const cv
::Mat
&);public slots
:};#endif
CameraThread.cpp
#include "CameraThread.h"CameraThread
::CameraThread(QObject
*parent
) :QThread(parent
)
{stopped
= false;
}void CameraThread
::run()
{qDebug() << "Current thread:" << QThread
::currentThreadId();if (!cv_cap
.isOpened()){cv_cap
.open(0);}while (!stopped
){cv_cap
>> cv_src
;if(!cv_src
.data
){continue;}emit
getImage(cv_src
);cv_src
.release();}cv_cap
.release();
}void CameraThread
::stop()
{stopped
= true;
}
調用代碼:
Camera.cpp
#include "Camera.h"Camera
::Camera(QWidget
*parent
): QMainWindow(parent
)
{ui
.setupUi(this);scene
= new QGraphicsScene
;qRegisterMetaType
<cv
::Mat
>("cv::Mat");connect(ui
.actionCamera
, SIGNAL(triggered()), this, SLOT(openCamera()));connect(ui
.actionClose
, SIGNAL(triggered()), this, SLOT(closeCamera()));
}void Camera
::openCamera()
{thread
= new CameraThread();connect(thread
, SIGNAL(getImage(cv
::Mat
)), this, SLOT(getImage(cv
::Mat
)));thread
->start();
}void Camera
::closeCamera()
{if (thread
->isRunning()){thread
->stop(); thread
->destroyed();}ui
.DisplayLabel
->close();
}void Camera
::getImage(cv
::Mat image
)
{qt_image
= MatImageToQimage(image
);qt_pixmap
= QPixmap
::fromImage(qt_image
);ui
.DisplayLabel
->setPixmap(qt_pixmap
);displayImage(ui
.DisplayLabel
, qt_pixmap
);ui
.DisplayLabel
->show();
}
void Camera
::displayImage(QLabel
*label
, QPixmap
&pixmap
)
{label
->setAlignment(Qt
::AlignLeft
);QSize imageSize
= pixmap
.size();QSize labelSize
= label
->size();double widthRatio
= 1.0*imageSize
.width() / labelSize
.width();double heightRatio
= 1.0*imageSize
.height() / labelSize
.height();if (widthRatio
> heightRatio
){pixmap
= pixmap
.scaledToWidth(labelSize
.width());}else{pixmap
= pixmap
.scaledToHeight(labelSize
.height());}label
->setScaledContents(true);label
->setPixmap(pixmap
);
}
QImage Camera
::MatImageToQimage(const cv
::Mat
&src
)
{if (src
.type() == CV_8UC1
){QImage
qImage(src
.cols
, src
.rows
, QImage
::Format_Indexed8
);qImage
.setColorCount(256);for (int i
= 0; i
< 256; i
++){qImage
.setColor(i
, qRgb(i
, i
, i
));}uchar
*pSrc
= src
.data
;for (int row
= 0; row
< src
.rows
; row
++){uchar
*pDest
= qImage
.scanLine(row
);memcmp(pDest
, pSrc
, src
.cols
);pSrc
+= src
.step
;}return qImage
;}else if (src
.type() == CV_8UC3
){const uchar
*pSrc
= (const uchar
*)src
.data
;QImage
qImage(pSrc
, src
.cols
, src
.rows
, src
.step
, QImage
::Format_RGB888
);return qImage
.rgbSwapped();}else if (src
.type() == CV_8UC4
){const uchar
*pSrc
= (const uchar
*)src
.data
;QImage
qImage(pSrc
, src
.cols
, src
.rows
, src
.step
, QImage
::Format_ARGB32
);return qImage
.copy();}else{return QImage();}
}
總結
以上是生活随笔為你收集整理的Qt与OpenCV编程:在子线程打开摄像头用主线程显示的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。