QT框架中快速应用OpenCV
2012-05-03 15:08
387 查看
http://www.cnblogs.com/khler/archive/2010/07/04/1770886.html
和MFC比较起来,QT的信号槽机制比MFC的信号机制慢,但是因为能很好的实现跨平台,所以我在这里总结一下可能对一些人有点用。OpenCV.China论坛上有一个帖子叫做《在MFC框架中快速应用OpenCV》看了后就想结合QT写一下。
0.搭建环境:OpenCV+QT4.6
我的实验是基于VS2008来做的,QT官方虽然提供了VS2008-add-in的插件,我没有用。直接下载器编译好的库文件进行配置,OpenCV的在VS2008下面的配置方法Google一下到处都是,这里不再补充。首先需要做的是在VS2008里面你需要使QT下和OpenCV的程序能分别跑起来。对于QT在VS的配置其实挺简单,有头文件和相应的链接库,保证调用的时候路径正确,一般就没有问题了。常用命令行make程序的人应该会很清楚那些IDE只不过是层画皮。
1.显示图像
QWidget是QObject下的第一个子类,使用它显示图像会减少不必要的开销。首先定制一个自己需要的QWidget:
需要绘制一个图像,我重载paintEvent(QpaintEvent*e),我在这里面使用QPainter进行绘制。
drawImage(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完整代码
调用的代码很简单:
2.播放视频
有些时候我们需要的是处理视频文件,比如AVI,当然也不过是图像序列。在由于QT运行时的多线程机制导致sleep函数不好使,可以通过其提供的QTimer来控制视频文件的播放。在给出例子之前要罗嗦两句QT的信号/槽机制。MFC里面的消息映射固然很快,但是让一个涉其未深的人阅读起来会觉得很晦涩,QT通过signal/slot机制实现了消息交换。用signal唤起slot,比如点击了button的clicked()事件是一个signal,当这个事件发生之后可以唤起其他的操作,只要你将clicked消息和那个实际操作的槽连接起来了。
opencv里面有函数可以方便的读取视频帧,如果使用Widget播放视频,如何控制帧率是一个很巧妙的地方,我使用一个QTimer控制时间(可以理解为帧率),并周期性的唤起读取视频帧的操作,然后在这个操作里面对widget进行重绘,或者模仿前面的方法,用一个QImage当作共享区域,让用来paintEvent用来显示。
有了上面显示图像的基础,我改一下上面的代码,给出一个例子:
myWidget.h
myWidget.cpp
主函数里面调用
由于接不截图都看不出来,所以就不截图。
后一个程序因为涉及到slots,所以添加了一个Q_OBJECT宏,编译之前需要将myWidget.h程序moc一下
比如:
mocmyWidget.h–omoc_myWidget.cpp
这样会在目录下生成一个.cpp文件,make的时候加到源文件里一起make,或者编译的时候添加到源文件列表中去。
知道如何使用QT来显示图像和播放视频之后,在上述代码里面插入处理图像的代码就很简单了。显示图像的时候在构造函数里面就可以插入处理代码,当然也可以在paintEvent函数里面进行处理,播放视频的时候可以在nextFrame函数里面进行处理,有些预处理可以在构造函数里面完成。
相比于MFC的代码,QT的代码结构看上去,很明显,更加优美。
原文:http://bugway.appspot.com/?p=469802
和MFC比较起来,QT的信号槽机制比MFC的信号机制慢,但是因为能很好的实现跨平台,所以我在这里总结一下可能对一些人有点用。
0.搭建环境:OpenCV+QT4.6
我的实验是基于VS2008来做的,QT官方虽然提供了VS2008-add-in的插件,我没有用。直接下载器编译好的
1.显示图像
QWidget是QObject下的第一个子类,使用它显示图像会减少不必要的开销。首先定制一个自己需要的QWidget:
classmyWidget:publicQWidget { Q_OBJECT public: myWidget(constIplImage*img,QWidget*parent=0); ~myWidget(); protected: voidpaintEvent(QPaintEvent*e); private: IplImage*iplImg; QImage*qImg; };
需要绘制一个图像,我重载paintEvent(QpaintEvent*e),我在这里面使用QPainter进行绘制。
voidmyWidget::paintEvent(QPaintEvent*e)
{
QPainterpainter(this);
painter.drawImage(QPoint(5,5),*qImg);
}
drawImage(QPoint(5,5),qImg);的作用是将qImg绘制在左上顶点位于QPoint(5,5)处。
这里面有可能两个问题,第一个问题是要显示的图片太小,创建的Widget太大,最后显示比较丑陋。这时可以在此函数里面获得qImg的宽高,然后resize一下就好了。另外一个问题是:绘制的时候使用的是QImage,不是IplImage类型。关于这个问题论坛上有人专门写了IplImage<->QImage的转换代码,我在这里不重复那个做法,一是有人已经做了,另外处于效率考虑,这里提供另一种方法。
通常同学们都是用cvLoadImage来读图片,保存在IplImage里面,在这里这个图片我们保存在img里面,然后通过img传进QWidget,然后我new一个QImage
qImg=newQImage(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=newQImage(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(constIplImage*img,QWidget*parent/*=0*/):QWidget(parent)
{
qImg=newQImage(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);
deleteqImg;
}
voidmyWidget::paintEvent(QPaintEvent*e)
{
QPainterpainter(this);
painter.drawImage(QPoint(0,0),*qImg);
}
调用的代码很简单:
intmain(intargc,char*argv[])
{
QApplicationapp(argc,argv);
IplImage*img=cvLoadImage("460.jpg",1);
if(img)
{
myWidget*mw=newmyWidget(img);
mw->show();
}
intre=app.exec();
cvReleaseImage(&img);
returnre;
}
2.播放视频
有些时候我们需要的是处理视频文件,比如AVI,当然也不过是图像序列。在由于QT运行时的多线程机制导致sleep函数不好使,可以通过其提供的QTimer来控制视频文件的播放。在给出例子之前要罗嗦两句QT的信号/槽机制。MFC里面的消息映射固然很快,但是让一个涉其未深的人阅读起来会觉得很晦涩,QT通过signal/slot机制实现了消息交换。用signal唤起slot,比如点击了button的clicked()事件是一个signal,当这个事件发生之后可以唤起其他的操作,只要你将clicked消息和那个实际操作的槽连接起来了。
opencv里面有函数可以方便的读取视频帧,如果使用Widget播放视频,如何控制帧率是一个很巧妙的地方,我使用一个QTimer控制时间(可以理解为帧率),并周期性的唤起读取视频帧的操作,然后在这个操作里面对widget进行重绘,或者模仿前面的方法,用一个QImage当作共享区域,让用来paintEvent用来显示。
有了上面显示图像的基础,我改一下上面的代码,给出一个例子:
myWidget.h
#ifndefMYWIDGET_H
#defineMYWIDGET_H
#include<QtGui\QWidget>
#include<QtGui\QPaintEvent>
#include<QtGui\QImage>
#include<QtCore\QTimer>
#include<cv.h>
#include<highgui.h>
classmyWidget:publicQWidget
{
Q_OBJECT
public:
myWidget(constchar*filename,QWidget*parent=0);
~myWidget();
protected:
voidpaintEvent(QPaintEvent*e);
privateslots:
voidnextFrame();
private:
CvCapture*capture;
IplImage*iplImg;
IplImage*frame;
QImage*qImg;
QTimer*timer;
};
#endif
myWidget.cpp
#include"myWidget.h"
#include<QtGui\QPainter>
#include<QtCore\QPoint>
myWidget::myWidget(constchar*filename,QWidget*parent/*=0*/):QWidget(parent)
{
capture=cvCaptureFromFile(filename);
if(capture)
{
frame=cvQueryFrame(capture);
if(frame)
this->resize(frame->width,frame->height);
qImg=newQImage(QSize(frame->width,frame->height),
QImage::Format_RGB888);
iplImg=cvCreateImageHeader(cvSize(frame->width,frame->height),
8,3);
iplImg->imageData=(char*)qImg->bits();
timer=newQTimer(this);
timer->setInterval(30);
connect(timer,SIGNAL(timeout()),this,SLOT(nextFrame()));
timer->start();
}
}
myWidget::~myWidget()
{
cvReleaseImage(&iplImg);
cvReleaseCapture(&capture);
deleteqImg;
deletetimer;
}
voidmyWidget::paintEvent(QPaintEvent*e)
{
QPainterpainter(this);
painter.drawImage(QPoint(0,0),*qImg);
}
voidmyWidget::nextFrame()
{
frame=cvQueryFrame(capture);
if(frame)
{
if(frame->origin==IPL_ORIGIN_TL)
{
cvCopy(frame,iplImg,0);
}
else
{
cvFlip(frame,iplImg,0);
}
cvCvtColor(iplImg,iplImg,CV_BGR2RGB);
this->update();
}
}
主函数里面调用
intmain(intargc,char*argv[])
{
QApplicationapp(argc,argv);
char*filename="test.avi";
myWidget*mw=newmyWidget(filename);
mw->show();
intre=app.exec();
returnre;
}
由于接不截图都看不出来,所以就不截图。
后一个程序因为涉及到slots,所以添加了一个Q_OBJECT宏,编译之前需要将myWidget.h程序moc一下
比如:
mocmyWidget.h–omoc_myWidget.cpp
这样会在目录下生成一个.cpp文件,make的时候加到源文件里一起make,或者编译的时候添加到源文件列表中去。
知道如何使用QT来显示图像和播放视频之后,在上述代码里面插入处理图像的代码就很简单了。显示图像的时候在构造函数里面就可以插入处理代码,当然也可以在paintEvent函数里面进行处理,播放视频的时候可以在nextFrame函数里面进行处理,有些预处理可以在构造函数里面完成。
相比于MFC的代码,QT的代码结构看上去,很明显,更加优美。
原文:http://bugway.appspot.com/?p=469802
相关文章推荐
- QT框架中快速应用OpenCV
- QT框架中快速应用OpenCV——基于图片
- QT 框架中快速应用OpenCV 基于图片
- QT框架中快速应用OpenCV——基于视频播放
- QT 框架中快速应用OpenCV 基于视频播放
- 【转】QT框架中快速应用OpenCV
- QT 框架中快速应用OpenCV 基于视频播放
- QT 框架中快速应用OpenCV
- 使用 CodeIgniter 框架快速开发 PHP 应用(五)
- 使用 Spring Boot 快速构建 Spring 框架应用
- iOS快速开发框架Bee-Framework应用和解析(一) --- 为什么使用Bee framework
- iOS快速开发框架Bee-Framework应用和解析(二) - Bee framework架构概览
- YII Framework框架使用YIIC快速创建YII应用之migrate用法实例详解
- 使用 CodeIgniter 框架快速开发 PHP 应用(七)
- 分布式应用框架Akka快速入门
- pca的具体应用QT+OPENCV人脸主成分提取和还原
- 使用 CodeIgniter 框架快速开发 PHP 应用(六)
- UCML--编译型应用框架快速开发工具体系介绍
- Qt学习之四:使用Qt+OpenCV创建GUI应用
- 如何利用an-aw-base框架快速开发android应用application