QT与openCV,与PCL结合!
原文鏈接:http://mobile.51cto.com/symbian-271123.htm
? ?
? ?對于使用主框架的QT程序,實現Qimage的轉換可借鑒下面程序段:
void MainWindow::on_openButton_clicked() {//第3個參數表示查找文件時從哪個目錄開始,如果為"."的話,表示從該工程目錄開始查找,最后那個參數的過濾器的名字之間//要用空格,否則識別不出來QString img_name = QFileDialog::getOpenFileName( this, tr("Open Image"), ".",tr("Image Files(*.png *.jpg *.jpeg *.bmp)"));//toAscii()返回8位描述的string,為QByteArray,data()表示返回QByteArray的指針,QByteArray為字節指針Mat src = imread( img_name.toAscii().data() );cvtColor( src, src, CV_BGR2RGB );QImage img = QImage( (const unsigned char*)(src.data), src.cols, src.rows, QImage::Format_RGB888 ); // namedWindow( "Image_Show", WINDOW_AUTOSIZE ); // imshow( "Image_Show", src );ui->label->setPixmap( QPixmap::fromImage(img) );// ui->label->resize( ui->label->pixmap()->size() );} (2):詳解QT 快速應用OPENCV ,圖片示例:基于widget!!!原文鏈接:http://mobile.51cto.com/symbian-271260.htm
QT 框架中快速應用OpenCV?是本文要結束的內容,和MFC比較起來,QT的信號槽機制比MFC的信號機制慢,但是因為能很好的實現跨平臺,所以我在這里總結一下可能對一些人有點用。OpenCV.China論壇上有一個帖子叫做《在MFC框架中快速應用OpenCV》看了后就想結合QT寫一下。
0搭建環境:OpenCV + QT 4.6
我的實驗是基于VS2008來做的,QT官方雖然提供了VS2008-add-in的插件,我沒有用。直接下載器編譯好的庫文件進行配置,OpenCV的在VS2008下面的配置方法Google一下到處都是,這里不再補充。首先需要做的是在VS2008里面你需要使QT下和OpenCV的程序能分別跑起來。對于QT在VS的配置其實挺簡單,有頭文件和相應的鏈接庫,保證調用的時候路徑正確,一般就沒有問題了。常用命令行make程序的人應該會很清楚那些IDE只不過是層畫皮。
.pro配置:
[cpp] view plaincopyINCLUDEPATH += d:\opencv\build\include\ INCLUDEPATH += d:\opencv\build\include\opencv\ INCLUDEPATH += d:\opencv\build\include\opencv2\ CONFIG(debug,debug|release) { LIBS += -Ld:\opencv\build\x86\vc10\lib \ -lopencv_core243d \ -lopencv_highgui243d \ -lopencv_imgproc243d \ -lopencv_features2d243d \ -lopencv_calib3d243d } else { LIBS += -Ld:\opencv\build\x86\vc10\lib \ -lopencv_core243 \ -lopencv_highgui243 \ -lopencv_imgproc243 \ -lopencv_features2d243 \ -lopencv_calib3d243 } 1.顯示圖像
QWidget是QObject下的第一個子類,使用它顯示圖像會減少不必要的開銷。首先定制一個自己需要的QWidget:
需要繪制一個圖像,我重載paintEvent(QpaintEvent *e),我在這里面使用QPainter進行繪制。
rawImage(QPoint(5,5),qImg);的作用是將qImg繪制在左上頂點位于QPoint(5,5)處。
這里面有可能兩個問題,第一個問題是要顯示的圖片太小,創建的Widget太大,最后顯示比較丑陋。這時可以在此函數里面獲得qImg的寬高,然后resize一下就好了。另外一個問題是:繪制的時候使用的是QImage,不是IplImage類型。關于這個問題論壇上有人專門寫了IplImage <-> QImage的轉換代碼,我在這里不重復那個做法,一是有人已經做了,另外處于效率考慮,這里提供另一種方法。
通常同學們都是用cvLoadImage來讀圖片,保存在IplImage里面,在這里這個圖片我們保存在img里面,然后通過img傳進QWidget,然后我new一個QImage
我這里假設iplImg是RGB格式,且每個通道大小為8。然后創建一個IplImage 的文件頭
此iplImage和QImage的不同之處在于QImage沒有直接提供創建文件頭的方法,可以通過如下方式創建只有文件頭數據的QImage
另外兩者的圖像矩陣像素排列有點不同,比如IplImage中的BGR到了QImage中應該是RGB,當然單通道的灰度圖是一樣的,值得慶幸的是兩者的像素矩陣都是形狀相同的多維數組。這樣我們可以通過指針共享這部分數據,一種方法如下:
將iplImg的圖像矩陣指到qImg那里,以后我們只需要對IplImage運用opencv里面的函數進行處理,其實就直接在處理qImg里面的數據了。但是現在的圖像數據還在img里面,首先得把數據搞到手,然后放到iplImg和qImg的共享區中去,另外將顏色排列以QImage中的RGB順序為標準。
實際上只要做到這里圖片就能顯示了。如下圖所示
給出myWidget.cpp完整代碼
調用的代碼很簡單:
小結:關于詳解?QT 框架中快速應用OpenCV?上篇內容介紹完了
(3):利用Qt與OpenCV簡單實現攝像頭圖像捕捉
原文鏈接:http://blog.const.net.cn/a/8763.htm
為了pro工程文件看起來簡單點,創建一個pri文件,包含opencv相關信息。分別為VS2008、Mingw和Linux設置OpenCV頭文件和庫的路徑。OPENCVPATH_MSVC=D:/Qt/OpenCV-2.1....
為了pro工程文件看起來簡單點,創建一個 pri 文件,包含 opencv相關信息。
分別為 VS2008、Mingw和Linux設置OpenCV頭文件和庫的路徑。
OPENCVPATH_MSVC = D:/Qt/OpenCV-2.1.0-vs2008win32-msvc*{INCLUDEPATH += $${OPENCVPATH_MSVC}/includeCONFIG(debug, debug|release) {LIBS+=-L$${OPENCVPATH_MSVC}/lib/debug -lcxcore210d -lhighgui210d} else {LIBS += -L$${OPENCVPATH_MSVC}/lib/release -lcxcore210 -lhighgui210} }OPENCVPATH_MINGW = D:/Qt/OpenCV-2.1.0-mingw win32-g++{INCLUDEPATH += $${OPENCVPATH_MINGW}/includeLIBS += -L$${OPENCVPATH_MINGW}/lib -lcxcore210 -lhighgui210 }unix:LIBS += -lcv -lhighgui讀取類
創建一個視頻捕捉類,提供start和stop槽來控制攝像頭打開和關閉,通過定時器定時捕捉圖像,并通過信號將圖片傳出。
//cameradevice.h #ifndef CAMERADEVICE_H #define CAMERADEVICE_H#include <QtCore/QObject>QT_BEGIN_NAMESPACE class QTimer; class QImage; QT_END_NAMESPACEnamespace cv{ class VideoCapture; class Mat; }class CameraDevice : public QObject { Q_OBJECT public: explicit CameraDevice(QObject *parent = 0); ~CameraDevice();signals: void imageReady(const QImage& image);public slots: bool start(); bool stop();private slots: void onTimeout();private: QImage imageFromMat(const cv::Mat& frame); cv::VideoCapture * m_capture; QTimer * m_timer; };#endif // CAMERADEVICE_H //cameradevice.cpp #include <QtCore/QTimer> #include <QtGui/QImage> #include "opencv/cv.h" #include "opencv/highgui.h" #include "cameradevice.h"CameraDevice::CameraDevice(QObject *parent) : QObject(parent) { m_capture = new cv::VideoCapture; m_timer = new QTimer(this); connect(m_timer, SIGNAL(timeout()), this, SLOT(onTimeout())); }CameraDevice::~CameraDevice() { delete m_capture; m_capture = NULL; }bool CameraDevice::start() { if (m_capture->isOpened()) { return true; } m_capture->open(CV_CAP_ANY); if (m_capture->isOpened()) { m_timer->start(40); } return m_capture->isOpened(); }bool CameraDevice::stop() { if (m_capture->isOpened()) { m_capture->release(); } return true; }void CameraDevice::onTimeout() { if (!m_capture->isOpened()) { return; } static cv::Mat frame; *m_capture >> frame; if (frame.cols) { emit imageReady(imageFromMat(frame)); } }QImage CameraDevice::imageFromMat(const cv::Mat &frame) { const unsigned char* src = frame.ptr(); QImage image(frame.cols, frame.rows, QImage::Format_RGB32); unsigned char * des = image.bits(); unsigned long count = frame.cols * frame.rows; for (unsigned long i = 0; i < count; ++i) { *des++ = *src++; *des++ = *src++; *des++ = *src++; *des++ = 0xff; } return image; }界面類
對話框類就簡單了,只需要一個 label 來顯示圖像,兩個按鈕來控制開啟與關閉即可
//dialog.h #ifndef DIALOG_H #define DIALOG_H#include <QtGui/QDialog>namespace Ui { class Dialog; }class CameraDevice;class Dialog : public QDialog { Q_OBJECTpublic: explicit Dialog(QWidget *parent = 0); ~Dialog();private slots: void onImageArrival(const QImage & image);private: Ui::Dialog *ui; CameraDevice * m_camera; };#endif // DIALOG_H[喝小酒的網摘]http://blog.const.net.cn/a/8763.htm //dialog.cpp #include "dialog.h" #include "ui_dialog.h" #include "cameradevice.h"Dialog::Dialog(QWidget *parent) : QDialog(parent), ui(new Ui::Dialog), m_camera(new CameraDevice(this)) { ui->setupUi(this); connect(m_camera, SIGNAL(imageReady(QImage)), this, SLOT(onImageArrival(QImage))); connect(ui->startButton, SIGNAL(clicked()), m_camera, SLOT(start())); connect(ui->stopButton, SIGNAL(clicked()), m_camera, SLOT(stop())); }Dialog::~Dialog() { delete ui; }void Dialog::onImageArrival(const QImage &image) { ui->view->setPixmap(QPixmap::fromImage(image)); }主程序
//main.cpp #include <QtGui/QApplication> #include "dialog.h"int main(int argc, char *argv[]) { QApplication a(argc, argv); Dialog w; w.show(); return a.exec(); }問題
用一個定時器來做似乎存在些問題,反復打開關閉,在windows下可發現資源泄漏。不清楚是什么原因。
簡單調整幾行代碼,改為多線程程序后,該問題似乎消失了。
- 改動主要在對話框類中:
改為多線程后,可將捕捉類中的定時器的時間設為 0
(4):QThread的使用方法
昨天不小心看到Qt開發人員( Bradley T. Hughes)Blog中的一片文章?you are-doing-it-wrong?。 結果看得頭昏腦脹:好歹也自學了近1年的Qt,也一直很小心、很認真地閱讀Qt和manual和例子等資料,卻被突然告知,QThread的正確使用方法 是一種自己從沒見過,而且Qt manual、example、書籍中都沒有提到過的一種方法。到底怎么了...?[喝小酒的網摘]http://blog.const.net.cn/a/8760.htm
莫非manual、exmaple以及資料中的介紹都是錯的??
認真看看其他的人的評論,總算理清了一點頭緒。所有事情源于 QThread 的事件循環!
QThread 的兩種使用方法
1. 不使用事件循環。這是官方的 Manual 、example 以及相關書籍中都介紹的一種的方法。
a. 子類化 QThread
b. 重載 run 函數,run函數內有一個 while 或 for 的死循環
c. 設置一個標記為來控制死循環的退出。
2. 使用事件循環。(博客?you are-doing-it-wrong?批駁的就是這種情況下的 一種用法。)
a. 子類化 QThread,
b. 重載 run 使其調用 QThread::exec()?
c. 并為該類定義信號和槽,這樣一來,由于槽函數并不會在新開的 thread 運行,很多人為了解決這個問題在構造函數中調用?moveToThread(this);?
而爭論和不解正是這樣的一條語句造成的。
Bradley T. Hughes 給出說明是:?QThread 應該被看做是操作系統線程的接口或控制點,而不應該包含需要在新線程中運行的代碼。需要運行的代碼應該放到一個QObject的子類中,然后將該子類的對象moveToThread到新線程中。
另外:
在Qt4.3(包括)之前,run 是虛函數,必須子類化QThread來實現run函數。
而從Qt4.4開始,qthreads-no-longer-abstract??? ,run 默認調用 QThread::exec() 。這樣一來不需要子類化 QThread 了,只需要子類化一個 QObject 就夠了,這正是被 Bradley T. Hughes推薦的方法。
終于看懂了,但
不管怎么說,都應該是 QThread 當初的設計導致的這種問題,而所有文檔和例子中都沒有提到該如何使用Qthread 進一步加劇了對QThread的這種誤用。
相關鏈接:
http://labs.qt.nokia.com/blogs/2010/06/17/youre-doing-it-wrong/
http://labs.qt.nokia.com/blogs/2006/12/04/threading-without-the-headache/
http://labs.qt.nokia.com/blogs/2007/07/05/qthreads-no-longer-abstract/
http://gitorious.org/qthreadhowto/qthreadhowto/trees/master
http://blog.exys.org/entries/2010/QThread_affinity.html
http://thesmithfam.org/blog/2010/02/07/talking-to-qt-threads/[喝小酒的網摘]http://blog.const.net.cn/a/8760.htm
(5):使用opencv和QT實現攝像頭采集
在網上收羅了很多資料,QT沒有專門操作攝像頭的類,這個得自己寫。網上也有很多關務openCV和V4l的一些介紹,由于我項目要在window下開發,所以就選擇了openCV。由于以前沒有用過openCV,所以就只看了關于openCVS攝像頭操作的這部分,其他的還沒時間去看。
openCV :?http://sourceforge.net/projects/opencvlibrary/files/opencv-win/2.1/ ?
剛開始下載的是2.3.1的,安裝后發現沒有lib庫所以后面選擇了2.1的
openCV中文學習 pdf ?:
現在,開始詳細的介紹如何在QT中實時的采集攝像頭數據。
打開QTcreator (我用的是QT 2.3的 中文版)
新建一個widget工程
在界面上放兩個label 分別用來顯示攝像頭采集到的數據和照的照片。
編輯camaraget.h 文件
[cpp]?view plaincopy? #ifndef CAMARAGET_H #define CAMARAGET_H #include <QWidget> #include <QImage> #include <QTimer> // 設置采集數據的間隔時間 #include <highgui.h> //包含opencv庫頭文件 #include <cv.h> namespace Ui { class camaraGet; } class camaraGet : public QWidget { Q_OBJECT public: explicit camaraGet(QWidget *parent = 0); ~camaraGet(); private slots: void openCamara(); // 打開攝像頭 void readFarme(); // 讀取當前幀信息 void closeCamara(); // 關閉攝像頭。 void takingPictures(); // 拍照 private: Ui::camaraGet *ui; QTimer *timer; QImage *imag; CvCapture *cam;// 視頻獲取結構, 用來作為視頻獲取函數的一個參數 IplImage *frame;//申請IplImage類型指針,就是申請內存空間來存放每一幀圖像 }; #endif // CAMARAGET_H編輯 camaraget .cpp [cpp]?view plaincopy? #include "camaraget.h" #include "ui_camaraget.h" camaraGet::camaraGet(QWidget *parent) : QWidget(parent), ui(new Ui::camaraGet) { ui->setupUi(this); cam = NULL; timer = new QTimer(this); imag = new QImage(); // 初始化 /*信號和槽*/ connect(timer, SIGNAL(timeout()), this, SLOT(readFarme())); // 時間到,讀取當前攝像頭信息 connect(ui->open, SIGNAL(clicked()), this, SLOT(openCamara())); connect(ui->pic, SIGNAL(clicked()), this, SLOT(takingPictures())); connect(ui->closeCam, SIGNAL(clicked()), this, SLOT(closeCamara())); } /****************************** ********* 打開攝像頭 *********** *******************************/ void camaraGet::openCamara() { cam = cvCreateCameraCapture(0);//打開攝像頭,從攝像頭中獲取視頻 timer->start(33); // 開始計時,超時則發出timeout()信號 } /********************************* ********* 讀取攝像頭信息 *********** **********************************/ void camaraGet::readFarme() { frame = cvQueryFrame(cam);// 從攝像頭中抓取并返回每一幀 // 將抓取到的幀,轉換為QImage格式。QImage::Format_RGB888不同的攝像頭用不同的格式。 QImage image((const uchar*)frame->imageData, frame->width, frame->height, QImage::Format_RGB888); ui->label->setPixmap(QPixmap::fromImage(image)); // 將圖片顯示到label上 } /************************* ********* 拍照 *********** **************************/ void camaraGet::takingPictures() { frame = cvQueryFrame(cam);// 從攝像頭中抓取并返回每一幀 // 將抓取到的幀,轉換為QImage格式。QImage::Format_RGB888不同的攝像頭用不同的格式。 QImage image((const uchar*)frame->imageData, frame->width, frame->height, QImage::Format_RGB888); ui->label_2->setPixmap(QPixmap::fromImage(image)); // 將圖片顯示到label上 } /******************************* ***關閉攝像頭,釋放資源,必須釋放*** ********************************/ void camaraGet::closeCamara() { timer->stop(); // 停止讀取數據。 cvReleaseCapture(&cam);//釋放內存; } camaraGet::~camaraGet() { delete ui; }
好了,全部代碼都OK了(當然,創建工程時,會生成main.cpp,不必去改動它),但現在你點運行,依然會產生錯誤,為什么呢?因為還沒有把openCV的庫包含進去。
在*.pro 文件中 加入:
INCLUDEPATH+=C:\OpenCV2.1\include\opencv
LIBS += C:\OpenCV2.1\lib\highgui210.lib \ C:\OpenCV2.1\lib\cxcore210.lib \ C:\OpenCV2.1\lib\cv210.lib OK,大功告成,運行后,在widget中點擊打開攝像頭,就可以看到自己了。運行后的效果:
后來我發現這個效果不怎么好,就改了一下:改了以后的運行效果也貼出來:
就改了一句:
[cpp]?view plaincopy?
(6):求道勿遠,求心勿近 的一個博客:Qt Opencv 在Linux下攝像頭簡單示例v1.0
?? 原文鏈接:http://blog.chinaunix.net/uid-24641004-id-3459705.html
下面寫的文章也許網上也有類似的,但是大多數都沒有給出思路及背景,讓初學者每次都只能學到一點皮毛,不少知識需要大量搜索零碎地拼湊起來。題外話,雖然現在是碎片化信息時代,但正是這樣信息整合能力也顯得非常重要,為讀者提供高質量的文章是我以后的目標。我以后會注意分析應用背景及些過程的解析。
不想看下面筆者對編譯環境的理解的,可以直接在本頁Ctrl+F查找“編譯過程”看,因為下面有很大段筆者心酸的回憶,嘻嘻。
資源介紹
opencv是一個非常優秀的圖形圖像處理類庫,里面的類或者結構體,封裝了很多實用的圖像處理算法,調用其提供的API,等于使用一些復雜的圖像處理算法,真是解放生產力啊。這里筆者用的是linux版本的opencv2.2源碼,幾十M,穩定版本夠用即可,沒必要時刻追著新版本。不過在linux上的opencv各種版本都是如筆者那樣編譯即可用。
思考一下,為什么我們要下源碼來編譯?不是像windows上的直接發布一個壓縮包即可用么?我們這次編譯為是得到什么?其實很簡單,opencv里有專門處理攝像頭的API,我們要用它,就得有它的頭文件及動態庫(或靜態庫)。而我們拿到源碼往往不是為了去研究其代碼(如果是做這算法方面的研究便是例外了),而是拿到“本地”編譯。至于為何,筆者認為是大家內核版本版本的不統一,編譯器版本也不統一導致這樣做的的。如果使用Ubuntu之類的,很簡單,一個apt-get什么都不用管,因為Ubuntu提供了適應你的內核版本編譯器編譯的庫。知道的同學希望指教一下。
下載請移步:http://www.opencv.org.cn/index.php/Download
虛擬機上的攝像頭,一般都是用USB連接,如果是筆記本自帶的,也是把虛擬機里的connect上即可。連接外設的方法:在虛擬機頂欄菜單,VM->Removable?Devices->XX?WebCam->connect??&&?show?in?status?Bar(前者把設備從win環境解除,連接到虛擬機環境,后者是顯示在虛擬機右下角的狀態欄)。
具體看下圖:
???QT,版本其實與opencv版本沒有什么關系,因為代碼編譯出來,最終都是翻譯成機器碼,QT源碼是C++寫的,OPENCV源碼也是C/C++寫的,編譯器認識他們即可。筆者一起也是擔心版本問題,網上的文章往往都是寫著qt4.7.2+opencv2.0XXX,或者qtcreator2.0+opencv2.3.1在Ubuntu11上編譯成功之類的文章,我那時就很擔心,又要確定QT版本,又要確定opencv版本,還得確定linux版本嗎?linux怎么那么復雜啊?就是他們的標題及其內容都沒有明確指出他們方法的通用性。筆者在這里就說明一下:這文章在linux上的適用,QT版本(4.6,4.7,5.0等無論什么版本都可以,whatever),opencv版本(1.0,2.0,2.2,2.3,2.4,whatever都可以),linux(各種發行版本(內核是2.6以上的),只要別用2.4的內核就好。)
編譯過程:
攝像頭在虛擬機上(當然,從物理上說你還是得有攝像頭才行)安裝上面的圖看一下即可。下面主要是opencv的編譯:主要參考opencv中文論壇的文章
具體代碼:
先講最終要實現什么,很簡單,一個窗口,里面有一個label顯示攝像頭的圖像。
然后講講原理:每隔一段時間我們就去攝像頭抓取一幀圖像,然后放到ui->label上面,如果取的時間快,就造成“視頻”的感覺了。(可以想到,其實攝像頭拍照也是很簡單,我們就把其中一幀取出來即可。)
新建一個工程,繼承QDialog(用什么窗體都可以),在UI上拖出一個label放在中間,
拉到適當大小。
在工程xxx.pro里面添加必要的庫及頭文件的路徑:
?
INCLUDEPATH +=/usr/local/include/opencvLIBS +=/usr/local/lib/libcv.so\/usr/local/lib/libhighgui.so\/usr/local/lib/libcxcore.so\//dialog.h#ifndef DIALOG_H#define DIALOG_H#include <QDialog>#include <cv.h>#include <highgui.h>#include <QTimer>#include <QPixmap>namespace Ui {class Dialog;}class Dialog :public QDialog{Q_OBJECTpublic:explicit Dialog(QWidget*parent= 0);~Dialog();private:Ui::Dialog*ui;CvCapture *capture;//highgui 里提供的一個專門處理攝像頭圖像的結構體IplImage *frame;//攝像頭每次抓取的圖像為一幀,使用該指針指向一幀圖像的內存空間QTimer *timer;//定時器用于定時取幀,上面說的隔一段時間就去取就是用這個實現。private slots:void getFrame();//實現定時從攝像頭取圖并顯示在label上的功能。};#endif // DIALOG_H//dialog.cpp#include "dialog.h"#include "ui_dialog.h"#include <QDebug>Dialog::Dialog(QWidget*parent):QDialog(parent),ui(new Ui::Dialog){ui->setupUi(this);timer = new QTimer(this);capture = cvCaptureFromCAM(0);//cvCaptureFromCAM其實是一個宏,就是cvCreateCameraCapture的別名,0代表第一個攝像頭。-1代表默認攝像頭。if(capture==NULL){qDebug()<<"error!";}timer->start(50);//1000為1秒,50毫秒去取一幀connect(timer,SIGNAL(timeout()),this,SLOT(getFrame()));//超時就去取}void Dialog::getFrame(){frame = cvQueryFrame(capture);//從攝像頭取幀QImage image = QImage((const uchar*)frame->imageData, frame->width, frame->height, QImage::Format_RGB888).rgbSwapped();//簡單地轉換一下為Image對象,rgbSwapped是為了顯示效果色彩好一些。ui->label->setPixmap(QPixmap::fromImage(image));}Dialog::~Dialog(){timer->stop();//停止取幀cvReleaseCapture(&capture);//釋放資源是個好習慣delete ui;}本文參考資料:
源碼編譯:
http://www.opencv.org.cn/index.php/%E6%BA%90%E7%A0%81%E7%BC%96%E8%AF%91
QT中使用OPENCV庫
http://www.opencv.org.cn/index.php/%E5%9C%A8Qt%E4%B8%AD%E4%BD%BF%E7%94%A8OpenCV%E5%BA%93
Debian/Ubuntu
http://www.opencv.org.cn/index.php/Debian%E4%B8%8B%E5%AE%89%E8%A3%85
總結
以上是生活随笔為你收集整理的QT与openCV,与PCL结合!的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: PCL:PCL与MFC 冲突总结
- 下一篇: 结合Kubernetes解读微服务的12