詳解 QT 框架中快速應(yīng)用OpenCV 基于圖片 上篇
QT 框架中快速應(yīng)用OpenCV 是本文要結(jié)束的內(nèi)容,和MFC比較起來(lái),QT的信號(hào)槽機(jī)制比MFC的信號(hào)機(jī)制慢,但是因?yàn)槟芎芎玫膶?shí)現(xiàn)跨平臺(tái),所以我在這里總結(jié)一下可能對(duì)一些人有點(diǎn)用。OpenCV.China論壇上有一個(gè)帖子叫做《在MFC框架中快速應(yīng)用OpenCV》看了后就想結(jié)合QT寫(xiě)一下。
0搭建環(huán)境:OpenCV + QT 4.6
我的實(shí)驗(yàn)是基于VS2008來(lái)做的,QT官方雖然提供了VS2008-add-in的插件,我沒(méi)有用。直接下載器編譯好的庫(kù)文件進(jìn)行配置,OpenCV的在VS2008下面的配置方法Google一下到處都是,這里不再補(bǔ)充。首先需要做的是在VS2008里面你需要使QT下和OpenCV的程序能分別跑起來(lái)。對(duì)于QT在VS的配置其實(shí)挺簡(jiǎn)單,有頭文件和相應(yīng)的鏈接庫(kù),保證調(diào)用的時(shí)候路徑正確,一般就沒(méi)有問(wèn)題了。常用命令行make程序的人應(yīng)該會(huì)很清楚那些IDE只不過(guò)是層畫(huà)皮。
1.顯示圖像
QWidget是QObject下的***個(gè)子類(lèi),使用它顯示圖像會(huì)減少不必要的開(kāi)銷(xiāo)。首先定制一個(gè)自己需要的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;
- };
需要繪制一個(gè)圖像,我重載paintEvent(QpaintEvent *e),我在這里面使用QPainter進(jìn)行繪制。
- void myWidget::paintEvent(QPaintEvent *e)
- {
- QPainter painter(this);
- painter.drawImage(QPoint(5,5),*qImg);
- }
rawImage(QPoint(5,5),qImg);的作用是將qImg繪制在左上頂點(diǎn)位于QPoint(5,5)處。
這里面有可能兩個(gè)問(wèn)題,***個(gè)問(wèn)題是要顯示的圖片太小,創(chuàng)建的Widget太大,***顯示比較丑陋。這時(shí)可以在此函數(shù)里面獲得qImg的寬高,然后resize一下就好了。另外一個(gè)問(wèn)題是:繪制的時(shí)候使用的是QImage,不是IplImage類(lèi)型。關(guān)于這個(gè)問(wèn)題論壇上有人專(zhuān)門(mén)寫(xiě)了IplImage <-> QImage的轉(zhuǎn)換代碼,我在這里不重復(fù)那個(gè)做法,一是有人已經(jīng)做了,另外處于效率考慮,這里提供另一種方法。
通常同學(xué)們都是用cvLoadImage來(lái)讀圖片,保存在IplImage里面,在這里這個(gè)圖片我們保存在img里面,然后通過(guò)img傳進(jìn)QWidget,然后我new一個(gè)QImage
- qImg = new QImage(QSize(img->width,img->height),QImage::Format_RGB888);
我這里假設(shè)iplImg是RGB格式,且每個(gè)通道大小為8。然后創(chuàng)建一個(gè)IplImage 的文件頭
- iplImg = cvCreateImageHeader(cvSize(img.width(),img.height()),8,3);
此iplImage和QImage的不同之處在于QImage沒(méi)有直接提供創(chuàng)建文件頭的方法,可以通過(guò)如下方式創(chuàng)建只有文件頭數(shù)據(jù)的QImage
- qImg = new QImage(QSize(0,0),QImage::Format_RGB888);
另外兩者的圖像矩陣像素排列有點(diǎn)不同,比如IplImage中的BGR到了QImage中應(yīng)該是RGB,當(dāng)然單通道的灰度圖是一樣的,值得慶幸的是兩者的像素矩陣都是形狀相同的多維數(shù)組。這樣我們可以通過(guò)指針共享這部分?jǐn)?shù)據(jù),一種方法如下:
- iplImg->imageData = (char*)qImg.bits();
將iplImg的圖像矩陣指到qImg那里,以后我們只需要對(duì)IplImage運(yùn)用opencv里面的函數(shù)進(jìn)行處理,其實(shí)就直接在處理qImg里面的數(shù)據(jù)了。但是現(xiàn)在的圖像數(shù)據(jù)還在img里面,首先得把數(shù)據(jù)搞到手,然后放到iplImg和qImg的共享區(qū)中去,另外將顏色排列以QImage中的RGB順序?yàn)闃?biāo)準(zhǔn)。
- if (img->origin == IPL_ORIGIN_TL)
- {
- cvCopy(img,iplImg,0);
- }
- else
- {
- cvFlip(img,iplImg,0);
- }
- cvCvtColor(iplImg,iplImg,CV_BGR2RGB);
實(shí)際上只要做到這里圖片就能顯示了。如下圖所示
給出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);
- }
調(diào)用的代碼很簡(jiǎn)單:
- 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;
- }
小結(jié):關(guān)于詳解 QT 框架中快速應(yīng)用OpenCV 上篇內(nèi)容介紹完了,希望本文讀你有所幫助,想要深入了解請(qǐng)看:

















