QT4.8+opencv2.4.9:点击按钮实现不同的图像操作

QT是一款可进行界面开发的工具,在Windows系统下可以与vs进行联合编译,最近接触了QT4.8,是一个比较老的版本,先熟悉熟悉相关的操作。下面是利用QT与opencv实现的一个简单应用:通过QT设计界面,界面上有若干个按钮,点击不同的按钮实现图像的不同显示。界面如下所示。界面简陋,后面会慢慢优化,并加上更多的功能。

前提条件

安装好opencv2.4.9,vs2010,QT4.8

设计步骤

打开vs2010,新建工程,新建QT模板,如下先点击QT4Project,再点击QT  Application新建。

新建之后,会出现如下的工程目录,目录自动生成,其中qttest.ui是QT模板,qttest.h是头文件,main.cpp和qttest.cpp是源文件,新建之后各文件中都已建好模板。

双击qttest.ui显示QT界面,该界面如文章开头需要添加几个组件,如下所示,Push Button为按钮,Label用来显示图像。直接鼠标拖拽即可,界面上按钮的名字双击即可修改。

此外还有一个地方要注意,如下QT界面右侧的编辑器与查看器,QObjectName的名称要自定义,每新建一个组件在上面的查看器中都有显示,在后面的程序中有用。

QT界面如上方法进行设计。

程序设计

打开vs的工程目录,打开main.cpp如下,该段代码是工程自动生成。

#include "qttest.h"
#include <QtGui/QApplication>

int main(int argc, char *argv[])
{
	QApplication a(argc, argv);
	qttest w;
	w.show();
	return a.exec();
}

QApplication是一个QT的应用程序类,a是定义的应用程序的对象,qttest是新建QT界面的类名,为Widget 类。w.sho()就是用来显示窗口的,a.exec() 启动应用程序的执行,开始应用程序的消息循环和事件处理,即界面中按钮与标签的程序功能。

其次打开qttest.h头文件,该文件也是工程自动生成好的,代码如下。

#ifndef QTTEST_H
#define QTTEST_H
#include <QtGui/QMainWindow>
#include "ui_qttest.h"
class qttest : public QMainWindow
{
	Q_OBJECT
    public:
	    qttest(QWidget *parent = 0, Qt::WFlags flags = 0);
	    ~qttest();
    private:
	    Ui::qttestClass ui;
};
#endif

其中包含的"ui_qttest.h"是QT软件生成的头文件,关于QMainWindow和Q_OBJECT一些类和相关变量在这里不在赘述,有很多博客解释的很清楚,想详细了解的可以搜索。而我们要设计QT就需要在这个头文件里加入我们想要的声明,在文章开头的最终界面上可以看到我们需要添加九个按钮,每个按钮负责实现不同的功能。所以我们要在头文件里声明九个函数,分别负责九个不同的功能。在头文件class qttest类中加入如下代码

private slots://定义私有的槽函数
		void openImage();//打开图像
		void otsu();//实现otsu
		void recover();//恢复图像
		void threshold2();//二值化
		void decolor();//减色处理
		void averagepooling();//平均池化
		void maxpooling();//最大池化
		void gaussianBlur();//高斯滤波
		void channel_change();//通道转换
		void Setfont();//字体设置

其中private slots是定义私有变量,slots是表示槽的意思,说到槽,就要理解QT是如何实现界面交互的,就是通过信号与槽,这里简单说明一下QT的机制,如在界面中鼠标点击按钮,那么标签中就会显示相应的功能,鼠标点击就代表信号,实现功能的函数就是槽,两者通过connect函数连接,信号有多种,如QT自带的clicked(),就是代表鼠标的点击信号,我们就是要在头文件中加入我们需要的槽。详细了解可查阅其他博客。

最后就是打开qttest.cpp文件,这里就是我们要进行源码编写的地方,头文件中引入类,那就是cpp的语法,所以要在该文件中对所有声明的函数进行编写代码。不可缺少的就是下面的两个函数,他们都是QT定义的类成员函数,上述所说的信号与槽的操作就是写在该函数下。

qttest::qttest(QWidget *parent, Qt::WFlags flags): QMainWindow(parent, flags)
{

}
qttest::~qttest(){}

当然用到的opencv都要用include包含进来,所以qttest.cpp文件中包含的头文件如下

#include "qttest.h"
#include "ui_qttest.h"
#include <QFile>
#include <QDir>
#include <QFileDialog>
#include <QString>
#include <QStringList>
#include <QTextStream>
#include <QDebug>
#include <iostream>
#include <opencv\cv.h>
#include <opencv2\highgui\highgui.hpp>
#include <QMessageBox>

由于所有得按钮都是大同小异,因此我就只详细介绍一个按钮,功能是打开图像。因为按钮是通过鼠标点击的所以信号就是鼠标点击,而对应的槽就是头文件中声明的void openImage()函数。代码如下

qttest::qttest(QWidget *parent, Qt::WFlags flags): QMainWindow(parent, flags)
{
	ui.setupUi(this);
	connect(ui.btn_openimage, SIGNAL(clicked()),this, SLOT(openImage()));//信号与槽(鼠标点击与openImage)
}

connect函数有四个参数,分别是发送方,信号,接收方,槽。第一个参数中ui代表QT界面的窗口,btn_openimage是窗口中的按钮,这里就显示到了名称的重要性不能出错,即在QT界面拖拽组件在右边查看器和编辑器中组建的命名,信号的发送方就是按钮,所以是ui.btn_openimage,信号用SIGNAL(),括号中就是信号的类型,此次为鼠标点击信号,this就是QT界面窗口,信号的接收端,槽就是接收端收到信号后进行的openImage()操作,这里要注意的是函数名务必于头文件中声明的槽相同。

接下来就要编写槽。如下

void qttest::openImage()
{
	QString pFileName;
	pFileName=QFileDialog::getOpenFileName(0,QString::fromLocal8Bit("请选择图像:"),QString::fromLocal8Bit("F:\\vs2010test\\test1\\test1\\"),QString::fromLocal8Bit("Images (*.png *.bmp *.jpg *.tif *.GIF )"));
	Mat srcImage,grayImage;
	char*  pChar;
	QByteArray pByteArray = pFileName.toLatin1();    
	pChar=pByteArray.data();
	Mat image=imread(pChar,IMREAD_COLOR);
	Mat dstImage=Channel_swap(image);
	QImage pImage;
	pImage=QImage((const unsigned char*)dstImage.data,dstImage.cols,dstImage.rows,QImage::Format_RGB888);
	pImage = pImage.scaled(ui.lb_displayimage->size(),Qt::KeepAspectRatio,Qt::SmoothTransformation);
	ui.lb_displayimage->setPixmap(QPixmap::fromImage(pImage));
}

函数前要加qttest::,因为openImage是qttest类的成员函数,pFileName是QString类定义的变量,QFileDialog::getOpenFileName()函数负责读取图片,该函数有多个参数,声明如下,最重要的是前四个。第一个参数用于指定父组件,默认为零。第二个参数是对话框的标题,可自定义。第三个参数是目标路径。第四个参数是后缀名过滤器,读取的文件类型,如图片格式(jpg,png)。

QString QFileDialog::getOpenFileName (
          QWidget * parent = 0,
          const QString & caption = QString(),
          const QString & dir = QString(),
          const QString & filter = QString(),
          QString * selectedFilter = 0,
          Options options = 0 )

下面三行代码是数据格式转换,QT中图像的格式为QString类型,QString转QByteArray,Latin1表示ASCII,转换后可使用opencv的Mat变量表示,这是要注意的,否则图像格式有问题,显示出错。

char*  pChar;
QByteArray pByteArray = pFileName.toLatin1();    
pChar=pByteArray.data();

转换为Mat类型后就可以进行像素值等一系列操作,但是还要注意的一点是QT的图像通道与opencv的imread通道顺序不同,为了显示的是opencv下的彩色图像,要进行通道转换,也就是程序中的Mat dstImage=Channel_swap(image),代码如下

Mat Channel_swap(Mat img){
	int imgcol=img.cols;
	int imgrow=img.rows;
	Mat out_img=Mat::zeros(imgrow,imgcol,CV_8UC3);
	for(int j=0;j<imgrow;j++){
		for(int i=0;i<imgcol;i++){   //BGR,8U的彩色图像表示为Vec3b
			out_img.at<Vec3b>(j,i)[0] = img.at<Vec3b>(j,i)[2]; //R->B
			out_img.at<Vec3b>(j,i)[2] = img.at<Vec3b>(j,i)[0]; //B->R
			out_img.at<Vec3b>(j,i)[1] = img.at<Vec3b>(j,i)[1]; //G->G
		}
	}
	return out_img;
}

程序的最后几行是让图像在标签中显示,QT图像的变量是QImage类,前面转换成了Mat所以还要再转换回去,所以后面几行为标签显示图像的固定语句,最后一行中的lb_displayimage就是标签的OBjectName。

以上就是打开图像按钮的相关程序,但是在执行前还有一点要注意,cpp文件的开头有一个ui_qttest.h头文件,而我们一直都没遇见到它,原来它是QT界面窗口的头文件,没有这个头文件你之前的按钮标签的代码在哪里运行呢,不过Qt有个缺点就是你设计好或修改窗口界面上的组件,要手动更新ui_qttest.h的代码,代码哪里来,就是在qttest.ui界面点击工具栏的窗体,有一个查看代码,把里面的代码全部复制到ui_qttest.h里,QT界面每改动之后都要执行这一操作,完成后点击vs上的编译就大功告成了。效果如下。就可以选中图像打开了。

整体代码我放在了下面的链接里有需要的可以看一看。

https://blog.csdn.net/yuan123890/article/details/108101410

当然我之前说了最终的窗口界面如文章开头那样,但是还可以加上其他的组件实现多样化功能。拓展的地方会在以后的时间里继续更新。

猜你喜欢

转载自blog.csdn.net/yuan123890/article/details/108094511
今日推荐