使用Qt创建第一个OpenCV的Gui应用
写在前面
学习OpenCV有一些小日子了,发现群里还有很多初学OpenCV的人像我当初一样跌跌撞撞到处找资料,所以在这里把学习笔记分享给大家,希望有志学习OpenCV进行计算机视觉活动的小伙伴们能少走一些弯路。
经过多方面查阅资料,了解到Qt开发平台对OpenCV的支持很好,但是在网上这方面的资料很少,能查到的大部分的图形交互设计都是基于OpenCV2.0之前的数据结构IplImage,而OpenCV现在官方已经更新到2.4.9版本了。偶然发现一本好书最近得到了一本好书《 OpenCV 2 Computer Vision Application Programming Cookbook》,下载的链接为http://ishare.iask.sina.com.cn/f/20485520.html?retcode=0, 2011年5月出版,全书都是基于OpenCV2.2版本的实现,采用了新的数据结构,该书现在已经有中文版《OpenCV2计算机视觉编程手册》,2013年7月科学出版社出版。我这里强烈建议利用C++开发的朋友们不要再使用老版本的数据结构了,实在影响开发效率。至于大家最熟悉的参考书《learning OpenCV》和《OpenCV教程——基础篇》这两本广为流传的书,我的看法是已经远远不能满足OpenCV新版本的学习了。老版本的OpenCV头文件的包含格式一般是:
#include "cv.h" #include "highgui.h"
而2.2以后的版本头文件包含一般为:
#include <opencv2/core/core.hpp> #include <opencv2/highgui/highgui.hpp> #include <opencv2/imgproc/imgproc.hpp>
为了保持对之前版本的兼容,这些头文件仍然能够使用,但是建议使用新的包含方式。
打开并显示图片
在Qt中,信号与槽是最重要的机制,这里我们可以创建一个按钮、或者菜单、工具条,来作为发射信号的载体,用一个槽函数来接收打开这个动作。
QPushButton OpenImageButton = new QPushButton( tr("Find Image") ); OpenImageButton->setDefault( false ); OpenImageButton->setEnabled( true );
void qttest1::on_OpenImage_clicked() { QString fileName = QFileDialog::getOpenFileName( this, tr( "Open Image" ), ".", tr("Image Files(*.png*.jpg*.jpeg*.bmp)")); image = cv::imread( fileName.toLocal8Bit().data()); cv::imshow("Source Image", image); }
上面的函数已经实现了打开并显示图片。我们再添加一个按钮,并定义一个函数来对图片进行操作。
void qttest1::on_Process_clicked() { cv::flip(image, image, 1); cv::namedWindow("Output Image"); cv::imshow("Output Image", image); }
对于初学者,这些工作都做完之后,当然不要忘记连接信号与槽。
connect(OpenImageButton,SIGNAL(clicked()),SLOT(on_OpenImage_clicked()));
connect(ProcessButton,SIGNAL(clicked()),SLOT(on_Process_clicked()));
这些工作做完以后,就可以打开并显示图片啦!
当然,有些同学可能会出现下面这样的情况,记得在你的析构函数里释放对象,
cvDestroyAllWindows();
按理说,OpenCV2是自动释放对象的,楼主这里还没有搞清楚,也请搞清楚的同学留言,非常感谢。
小小改进一下吧
单独弹出一个窗口并显示总是给人突兀的感觉,下面实现Qt的窗体中显示图片,显示的方法有很多,不同的显示方法存在着效率等各方面的问题,这里使用QImage转QPixmap,然后用QLabel::setPixmap()来完成显示,还有比较常用的方法是在paintEvent()中直接画,具体的差异没有去探究。
我们写一个小函数来实现:
void qttest1::displayMat(cv::Mat image) { cv::Mat rgb; QImage img; if(image.channels()==3) { //cvt Mat BGR 2 QImage RGB cv::cvtColor(image,rgb,CV_BGR2RGB); img =QImage((const unsigned char*)(rgb.data), rgb.cols,rgb.rows, rgb.cols*rgb.channels(), QImage::Format_RGB888); } else { img =QImage((const unsigned char*)(image.data), image.cols,image.rows, image.cols*image.channels(), QImage::Format_RGB888); } imagelabel->setPixmap(QPixmap::fromImage(img)); imagelabel->resize(imagelabel->pixmap()->size()); }
最后的效果是这样,是不是简洁明了了很多?