QT 框架中快速應用OpenCV 是本文要結束的內容,和MFC比較起來,QT的信號槽機制比MFC的信號機制慢,但是因為能很好的實現跨平台,所以我在這裡總結一下可能對一些人有點用。
0搭建環境:OpenCV + QT 4.6
我的實驗是基於VS2008來做的,QT官方雖然提供了VS2008-add-in的插件,我沒有用。直接下載器編譯好的庫文件進行配置,OpenCV的在VS2008下面的配置方法Google一下到處都是,這裡不再補充。首先需要做的是在VS2008裡面你需要使QT下和OpenCV的程序能分別跑起來。對於QT在VS的配置其實挺簡單,有頭文件和相應的鏈接庫,保證調用的時候路徑正確,一般就沒有問題了。常用命令行make程序的人應該會很清楚那些IDE只不過是層畫皮。
1.顯示圖像
QWidget是QObject下的第一個子類,使用它顯示圖像會減少不必要的開銷。首先定制一個自己需要的QWidget:
- class myWidget : public QWidget
- {
- Q_OBJECT
- public:
- myWidget(const IplImage *img,QWidget *parent = 0);
- ~myWidget();
- protected:
- void paintEvent(QPaintEvent *e);
- private:
- IplImage* iplImg;
- QImage *qImg;
- };
需要繪制一個圖像,我重載paintEvent(QpaintEvent *e),我在這裡面使用QPainter進行繪制。
- void myWidget::paintEvent(QPaintEvent *e)
- {
- QPainter painter(this);
- painter.drawImage(QPoint(5,5),*qImg);
- }
rawImage(QPoint(5,5),qImg);的作用是將qImg繪制在左上頂點位於QPoint(5,5)處。
這裡面有可能兩個問題,第一個問題是要顯示的圖片太小,創建的Widget太大,最後顯示比較丑陋。這時可以在此函數裡面獲得qImg的寬高,然後resize一下就好了。另外一個問題是:繪制的時候使用的是QImage,不是IplImage類型。關於這個問題論壇上有人專門寫了IplImage <-> QImage的轉換代碼,我在這裡不重復那個做法,一是有人已經做了,另外處於效率考慮,這裡提供另一種方法。
通常同學們都是用cvLoadImage來讀圖片,保存在IplImage裡面,在這裡這個圖片我們保存在img裡面,然後通過img傳進QWidget,然後我new一個QImage
- qImg = new QImage(QSize(img->width,img->height),QImage::Format_RGB888);
我這裡假設iplImg是RGB格式,且每個通道大小為8。然後創建一個IplImage 的文件頭
- iplImg = cvCreateImageHeader(cvSize(img.width(),img.height()),8,3);
此iplImage和QImage的不同之處在於QImage沒有直接提供創建文件頭的方法,可以通過如下方式創建只有文件頭數據的QImage
- qImg = new QImage(QSize(0,0),QImage::Format_RGB888);
另外兩者的圖像矩陣像素排列有點不同,比如IplImage中的BGR到了QImage中應該是RGB,當然單通道的灰度圖是一樣的,值得慶幸的是兩者的像素矩陣都是形狀相同的多維數組。這樣我們可以通過指針共享這部分數據,一種方法如下:
- iplImg->imageData = (char*)qImg.bits();
將iplImg的圖像矩陣指到qImg那裡,以後我們只需要對IplImage運用opencv裡面的函數進行處理,其實就直接在處理qImg裡面的數據了。但是現在的圖像數據還在img裡面,首先得把數據搞到手,然後放到iplImg和qImg的共享區中去,另外將顏色排列以QImage中的RGB順序為標准。
- if (img->origin == IPL_ORIGIN_TL)
- {
- cvCopy(img,iplImg,0);
- }
- else
- {
- cvFlip(img,iplImg,0);
- }
- cvCvtColor(iplImg,iplImg,CV_BGR2RGB);
實際上只要做到這裡圖片就能顯示了。如下圖所示
給出myWidget.cpp完整代碼
- #include "myWidget.h"
- #include <QtGui\QPainter>
- #include <QtCore\QPoint>
- myWidget::myWidget(const IplImage *img,QWidget *parent /* = 0 */) : QWidget(parent)
- {
- qImg = new QImage(QSize(img->width,img->height),
- QImage::Format_RGB888);
- iplImg = cvCreateImageHeader(cvSize(img->width,img->height),
- 8,3);
- iplImg->imageData = (char*)qImg->bits();
- if (img->origin == IPL_ORIGIN_TL)
- {
- cvCopy(img,iplImg,0);
- }
- else
- {
- cvFlip(img,iplImg,0);
- }
- cvCvtColor(iplImg,iplImg,CV_BGR2RGB);
- this->resize(img->width,img->height);
- }
- myWidget::~myWidget()
- {
- cvReleaseImage(&iplImg);
- delete qImg;
- }
- void myWidget::paintEvent(QPaintEvent *e)
- {
- QPainter painter(this);
- painter.drawImage(QPoint(0,0),*qImg);
- }
調用的代碼很簡單:
- int main(int argc,char* argv[])
- {
- QApplication app(argc,argv);
- IplImage *img = cvLoadImage("460.jpg",1);
- if (img)
- {
- myWidget *mw = new myWidget(img);
- mw->show();
- }
- int re = app.exec();
- cvReleaseImage(&img);
- return re;
- }
小結:關於詳解 QT 框架中快速應用OpenCV 上篇內容介紹完了 見 http://www.linuxidc.com/Linux/2013-04/83226.htm ,希望本文讀你有所幫助,想要深入了解請看:
詳解 QT 框架中快速應用OpenCV 基於視頻播放 下篇 http://www.linuxidc.com/Linux/2013-04/83226p2.htm。