配置环境:qt5.2,opencv 2.4.8,vs2010,win8.1 32位
http://download.csdn.net/detail/cy_543/7113933
注:读取图片的路径一定不要包含中文
Qt是跨平台C++图形用户界面应用程序开发框架。主要包括以下几个部分:(1)跨平台的IDE,被称为Qt Creater;(2)一系列Qt类库和开发工具。使用Qt SDK 开发C++应用有很多好处:
Qt团队开发的开源代码,让你接触不同Qt组件的源代码、。
跨平台,意味着开一在不同的操作系统上开发,比如Windows,Linux,Mac OS X等。
包括了完整的跨平台GUI库,提供有效的面向对象和事件驱动的模型。
Qt包括不同的跨平台库来发展多媒体、图形、数据库,多线程,web应用以及其对先进设计有用的模块。
上面这段话是从英文上翻译过来的,主要就是说可以跨多个平台。
尽管之前看了浅墨的文章,对于opencv的内容不再陌生,但是qt依然是自己的弱点。这篇文章就归类在qt里面了。因为我觉得,Qt的问题比较多,而涉及opencv的内容比较少。
这次要做的就是实现从本地读取图像,在Qt设计师中显示。然后反转再现实。打开图像显示如下:
点击处理图像之后,显示如下:
首先建立一个qt解决方案,命名为 imagprocess
步骤如下:
1、在Qt设计师中选择push_botton。显示的名字分别显示为打开图像、处理图像,objective_name分别为 open,process.
2、梳理下本文的思路:点击打开图像,要在本地选择一张图像并输出;点击处理图像,图像被旋转,然后输出。主要就是为了实现这两个内容。
声明:由于在自己学习的时候,遇到了两个版本,一个简单,一个复杂。所以说,这里将会分成两块来说。为了不显得太复杂,就不用加标注的方法来说,就单独来说。
简单的显示:
3.1、imagprocess.h内容填写,加粗的部分是需要我们填写的。在类的声明中,需要将用到的声明都写清楚,便于后续的使用。
#ifndefIMAGPROCESS_H
#defineIMAGPROCESS_H
#include
#include"ui_imagprocess.h"
#include
#include
#include
classimagprocess : public QMainWindow
{
Q_OBJECT
public:
imagprocess(QWidget *parent = 0);
~imagprocess();
private slots:
voidon_open_clicked();
voidon_process_clicked();//声明两个槽函数,分别对应open、process
private:
Ui::imagprocessClass ui;
cv::Mat image; // the image variable
};
#endif// IMAGPROCESS_H
总的来说,没有需要特别说明的。这些都是比较基本的,当然了在不知情的情况下。总是会出现很多的问题,这些都是在不断地阅读中明白的。没有什么文献可以阅读,书籍去约定俗称。遇到了,记下来,然后就可以了。
4.1、imagprocess.cpp的填写。这个是关键,所以出现了很多问题。也算是写了很长时间。所以说,这里将会把自己遇到的众多问题跟大家分享一下。
#include"imagprocess.h"
using namespace cv;
imagprocess::imagprocess(QWidget*parent)
: QMainWindow(parent)
{
ui.setupUi(this);
//connect(ui.open,SIGNAL(clicked()),this,SLOT(on_open_clicked()));
//connect(ui.process,SIGNAL(clicked()),this,SLOT(on_process_clicked()));
}
imagprocess::~imagprocess()
{
}
void imagprocess::on_open_clicked()
{
QString fileName =QFileDialog::getOpenFileName(this, tr("Open Image"),
".", tr("Image Files (*.png *.jpg *.jpeg*.bmp)"));
std::string str = fileName.toStdString();
image=imread(str);
//image = cv::imread(fileName.toLatin1().data());
namedWindow("Original Image");
imshow("Original Image",image);
}
void imagprocess::on_process_clicked()
{
flip(image, image, 1);
namedWindow("Output Image");
imshow("Output Image", image);
}
这是函数最核心的部分。将会详细去说:
(1)//connect(ui.open,SIGNAL(clicked()),this,SLOT(on_open_clicked()));
/connect(ui.process,SIGNAL(clicked()),this,SLOT(on_process_clicked()));
这个是槽函数的连接函数,如果在Qt设计师里没有添加槽函数的话,是需要用语句来写出来的。当然,程序运行了之后,我发现打开图像要进行两次,所以就想着把它注释掉,结果不影响运行。所以,这里我就比较疑惑。
当我还没写完的时候,问题就解决了:由于我在声明函数的过程中,使用了on_ 这样就有内置的函数,来完成链接。所以问题就变得更加简单了!
(2)void imagprocess::on_open_clicked()
{
QString fileName =QFileDialog::getOpenFileName(this, tr("Open Image"),
".",tr("Image Files (*.png*.jpg *.jpeg *.bmp)"));
std::string str = fileName.toStdString();
image=imread(str);
//image =cv::imread(fileName.toLatin1().data());
namedWindow("Original Image");
imshow("Original Image",image);
}
函数on_open_clicked()的主体,当点击打开图像之后,就会执行这里的内容。当然,为了简单,并没有对异常情况进行判断。这个之后会慢慢来弥补。
QStringfileName = QFileDialog::getOpenFileName(this, tr("Open Image"),
".", tr("Image Files (*.png*.jpg *.jpeg *.bmp)"));
获取图像的路径,比如E:\cat.jpg等。这个没什么好说的,很明了,就是自己去写的时候,需要多加注意。每个参数的意思也很明确。
std::stringstr = fileName.toStdString();
image=imread(str);
//image= cv::imread(fileName.toLatin1().data());
这三行内容放在一起说。前两行所要表达的内容和第三行是一样的。上一行中,fileName是Qstring类型的,也就说想要利用cv::imread来显示不可能的。为了用imread来显示,先来看看imread的结构:
Matimaread(const string &filename,intflags=1)这里的filename要求是string来显示。所以就要转换了,第一行就是将Qstring转换成string.
第三行就直接可以了。
namedWindow("OriginalImage");
imshow("OriginalImage",image);
参考opencv的内容,本人已经烂熟于心,所以不多说。
(3)void imagprocess::on_process_clicked()
{
flip(image, image, 1);
namedWindow("Output Image");
imshow("Output Image", image);
}
点击process,将会执行的函数内容。flip就是一个图像的翻转,没什么难度
void flip(InputArray src, OutputArray dst, int flipCode);
参数fipCode:整数,水平发转;0垂直反转;负数,水平垂直均反转。就是这样了。
Main函数不做处理就是了。
5、实验结果
void flip(InputArray src, OutputArray dst, int flip
没什么问题哦!当然了,没有充分利用到qt,只是用了两个按钮。不过,这也让我们体验一下图像显示的小成就。
稍微复杂点的显示
3.2 imagprocess.h
#ifndef IMAGPROCESS_H
#define IMAGPROCESS_H
#include
#include "ui_imagprocess.h"
#include
#include
#include
#include
#include
class imagprocess : public QMainWindow
{
Q_OBJECT
public:
imagprocess(QWidget*parent = 0);
~imagprocess();
private slots:
void on_open_clicked();
void on_process_clicked();
private:
Ui::imagprocessClassui;
cv::Mat image; // the image variable
};
#endif // IMAGPROCESS_H
其他的内容跟简单的版本没有差别。
4.2 imagprocess.cpp
#include "imagprocess.h"
using namespace cv;
imagprocess::imagprocess(QWidget *parent)
:QMainWindow(parent)
{
ui.setupUi(this);
//connect(ui.open,SIGNAL(clicked()),this,SLOT(on_open_clicked()));
//connect(ui.process,SIGNAL(clicked()),this,SLOT(on_process_clicked()));
}
imagprocess::~imagprocess()
{
}
voidimagprocess::on_open_clicked()
{
QString fileName =QFileDialog::getOpenFileName(this, tr("Open Image"),
".", tr("Image Files (*.png*.jpg *.jpeg *.bmp)"));
//std::string str = fileName.toStdString();
//image=imread(str);
image =cv::imread(fileName.toLatin1().data());
cvtColor(image,image,CV_RGB2RGBA);
QImage img = QImage((const unsignedchar*)(image.data), image.cols, image.rows, QImage::Format_RGB32);
QLabel *label = new QLabel(this);
label->move(100, 20);//图像在窗口中所处的位置;
label->setPixmap(QPixmap::fromImage(img));
label->resize(label->pixmap()->size());
label->show();
}
voidimagprocess::on_process_clicked()
{
cv::flip(image, image, 1);
cv::cvtColor(image, image,CV_RGB2RGBA);
QImage img = QImage((const unsignedchar*)(image.data), image.cols, image.rows, QImage::Format_RGB32);
QLabel *label = new QLabel(this);
label->move(100, 20);
label->setPixmap(QPixmap::fromImage(img));
label->resize(label->pixmap()->size());
label->show();
}
程序解释:
voidimagprocess::on_open_clicked()里面的内容:
(1)cvtColor(image,image,CV_RGB2RGBA);
cvtColor是Opencv里的颜色空间转换函数,可以实现RGB颜色向HSV,HSI等颜色空间的转换,也可以转换成灰度图像。
void cvCvtColor( const CvArr*src, CvArr* dst, int code );
第一个参数是输入图像
第二个参数是输出图像
第三个参数是彩色空间转换的模式,能实现不同类型的颜色空间转换。比如CV_BGR2GRAY表示转换为灰度图,CV_BGR2HSV将图片从RGB空间转换为HSV空间。当code选用CV_BGR2HSV时,对于8位图,需要将RGB值归一化到0-1之间。这样得到HSV图中的H范围才是0-360,S和V的范围是0-1。图像在QT显示前,必须转化成QImage格式,图像在QT显示前,必须转化成QImage格式,将RGBA格式转化成RGB。到底是什么格式转换成什么呢?这个有点疑惑,为什么成了RGBA转换成RGB了呢。这个也算是个遗留的问题吧。
(2)QImage img = QImage((const unsigned char*)(image.data),image.cols, image.rows, QImage::Format_RGB32);
这句是将cv::image转换成QImage。
(3)QLabel *label = new QLabel(this);
QT平台下创建一个标签的语句。
(4) label->move(100, 20); /
点的位置是(100,20),图像的左上角坐标
(5)label->setPixmap(QPixmap::fromImage(img));
就是将Qimage显示,QPixmap的具体信息,还没有搞明白。
(6)label->resize(label->pixmap()->size());
更改尺寸
(7)label->show();
最后显示。从(3)-(7)是QT图象显示的部分,还不算很明白。不过先记住!
on_process_clicked()函数就不多介绍了。
显示一个效果吧。分别是原始图像和反转图像。很显然,颜色有变化。那就是cvtColor的效果吧。不过,还是希望显示一个正常的颜色了。具体要怎么弄呢?以后再做研究。
注:写程序的过程中遇到的问题。
1、class “QString”没有成员“toAscii”
这是在寻找别人程序的过程中看到的。然后就出现了这样的问题。然后将toAscii换成toLatin1就OK了。这是由于版本升级导致的。2.4版本以后就不用toAscii了。
2、Debud Error!R6010-abort() has been called
这个问题太常见了。主要问题是:下标等越界,指针位置不恰当。而这里呢,是由于我犯了一个错误。就是在读取图片的过程中,路径是E:\C++程序\cat.jpg里面包含了汉字。然后就出现了这个问题。个人认为,这样导致了fileName无法正确被使用,所以读取图片自己让对不对了。
因此,不管是什么语言编程,除了注释,方便自己去理解,一定要用英文的。这样才不会因为这些细小的问题,浪费了自己的时间。