您的位置:首页 > 编程语言 > Qt开发

QT与openCV,与PCL结合!

2013-10-20 13:41 495 查看
(1):详解QT多媒体框架:给予视频播放器
原文链接: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 plaincopy

INCLUDEPATH += 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:
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 上篇内容介绍完了

(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-vs2008

win32-msvc*{
INCLUDEPATH += $${OPENCVPATH_MSVC}/include
CONFIG(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}/include
LIBS += -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_NAMESPACE

namespace 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_OBJECT

public:
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下可发现资源泄漏。不清楚是什么原因。

简单调整几行代码,改为多线程程序后,该问题似乎消失了。

改动主要在对话框类中:

#include <QtCore/QThread>
#include "dialog.h"
#include "ui_dialog.h"
#include "cameradevice.h"

Dialog::Dialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::Dialog),
m_camera(new CameraDevice)
{
ui->setupUi(this);

QThread * thread = new QThread(this);
m_camera->moveToThread(thread);
thread->start();

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()
{
m_camera->deleteLater();
delete ui;
}

void Dialog::onImageArrival(const QImage &image)
{
ui->view->setPixmap(QPixmap::fromImage(image));
}


改为多线程后,可将捕捉类中的定时器的时间设为 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?

QImage image((const uchar*)frame->imageData, frame->width, frame->height, QImage::Format_RGB888);

[cpp] view plaincopy?

改为了 QImage image = QImage((const uchar*)frame->imageData, frame->width, frame->height, QImage::Format_RGB888).rgbSwapped();



(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中文论坛的文章

./configure//头文件和库文件一般都是默认安装到/usr/local/include/usr/local/lib内

make

make install

具体代码:

先讲最终要实现什么,很简单,一个窗口,里面有一个label显示摄像头的图像。

然后讲讲原理:每隔一段时间我们就去摄像头抓取一帧图像,然后放到ui->label上面,如果取的时间快,就造成“视频”的感觉了。(可以想到,其实摄像头拍照也是很简单,我们就把其中一帧取出来即可。)

新建一个工程,继承QDialog(用什么窗体都可以),在UI上拖出一个label放在中间,

拉到适当大小。

在工程xxx.pro里面添加必要的库及头文件的路径:

INCLUDEPATH +=/usr/local/include/opencv
LIBS +=/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_OBJECT
public:
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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: