解决Qt中Qlabel显示OpenCV的Mat数据图像产生扭曲现象问题

前言

  曾写过一个程序,需要有一个界面,但 Shaun 不想使用 MFC,因缘巧合,在网上看到 Qt,就尝试用了一下,遂有此文。Shaun 的 Qt 版本为 qt-opensource-windows-x86-msvc2013-5.6.2,看其名字就知道该版本的 Qt 可以通过 Visual Studio 2013 开发 Qt 程序(各位看官猜的没错,Shaun 并没有直接使用 Qt Creator 开发 Qt 程序,而是通过 VS 开发 Qt 程序的 \(^o^)/),一来是熟悉 VS 开发,对 Qt Creator 完全没用过;二来是已经在 VS 配好全套的开发环境了(画外音:说白了就是懒嘛 ╭(╯^╰)╮)。但是在 VS 中开发 Qt 程序还需要一些其它的配置。

准备篇

  在 VS 中开发 Qt 程序首先需要安装一个 addin 外接程序,下载并安装 qt-vs-addin-1.2.5.exehttp://download.qt.io/archive/vsaddin/),(网上说该程序已不支持 VS2013 及以上版本的 VS,原因是 VS2013 及其以上版本的 VS 都不支持该种类型的插件,新版本的 VS 需要安装新型插件 qt-vs-tools-msvc2013-2.1.1.vsixqt-vs-tools-msvc2015-2.1.1.vsix),但是经 Shaun 实测,Shaun 的 VS2013-update5 英文旗舰版通过 qt-vs-addin-1.2.5 编写 Qt 程序完全没问题,不过 VS2015 就不知道了,可能真需要安装新型插件。下载安装好相应的软件之后需要在 VS 中配置 Qt 环境,虽然不配置也能正常编译,但是会在 Qt 相关的语句下面出现红色波浪线,Shaun 轻微强迫症表示不能忍 ╭(╯^╰)╮。具体配置如下:

选中“VC++目录”,在“包含目录”中添加:

C:\Qt\Qt5.6.2\5.6\msvc2013\include

在“库目录”中添加:

C:\Qt\Qt5.6.2\5.6\msvc2013\lib

配置完成之后即可发现红色波浪线已消失。

使用篇

  VS 中如何开发 Qt 程序请详见参考资料,懒癌发作,不想写了 =_=(其实是因为要写的话只能贴图了,Shaun 表示不想使用图片 (╯﹏╰) )。

问题篇

问题描述:Shaun 在用 Qt 显示 OpenCV 的 Mat 数据图像时,有时会发生扭曲现象(图像从对角线分开,两边颠倒,扭曲),有时却不会,为了撤了解决问题,查阅了相关资料,终于发现症结所在,原来是图片数据格式不符合 Qt 的图片数据格式。

解决办法:正文来喽 ~\(≧▽≦)/~,就不说废话了,“Talk is cheap. Show you the code”,具体完整正确显示C++代码为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
void showMatWithQtQlabel(const cv::Mat &img, QLabel *label)
{
// [Qt中用QLabel显示OpenCV中Mat图像数据出现扭曲现象的解决](http://lovelittlebean.blog.163.com/blog/static/11658218620125208212189/)
QImage q_img;
if(img.channels() == 3) // RGB image
{
q_img = QImage((const uchar*)(img.data), img.cols, img.rows, img.cols*img.channels(), QImage::Format_RGB888).rgbSwapped();
}else if (img.channels() == 4) // RGBA image
{
q_img = QImage((const uchar*)(img.data), img.cols, img.rows, img.cols*img.channels(), QImage::Format_RGB32);
}else // gray image
{
q_img = QImage((const uchar*)(img.data), img.cols, img.rows, img.cols*img.channels(), QImage::Format_Indexed8);
}

// -------------- 图片自适应label -------------------
QImage q_label_img = q_img.scaled(label->size(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation); // 图片自适应label大小
label->setPixmap(QPixmap::fromImage(q_label_img)); // 将图片显示到label上

// -------------- label自适应图片 -------------------
/*label->setPixmap(QPixmap::fromImage(q_img)); // 显示在label中
label->resize(label->pixmap()->size()); // 改变label的尺寸以自适应图像
label->show(); */
}

  rgbSwapped() 函数是为了使 Qt 中显示图形颜色更自然,因为 OpenCV 的 Mat 数据 RGB 图像是以 BGR 的顺序排列,而 Qt 中是以 RGB 的顺序排列,所以需要 rgbSwapped() 交换一下颜色通道排列顺序。

附录

1、摄像头数据采集问题

注意:如果是从摄像头实时采集显示图像,在显示时需先判断图像有没有数据

1
2
3
4
5
6
7
if (image.data)
{
// 执行显示操作
showMatWithQtQlabel(mat, ui.label);

// 执行其它操作...
}

1
2
3
4
5
6
7
if (!image.empty())
{
// 执行显示操作
showMatWithQtQlabel(mat, ui.label);

// 执行其它操作...
}

具体原因可参考 Shaun 的一篇文章 解决OpenCV-2.4.11调用摄像头显示拍摄视频出错问题

2、信号与槽的连接函数问题

Qt4 中信号与槽的连接函数语法为:

1
connect(&theTimer,SIGNAL(timeout()),this,SLOT(getFrame()));	// 超时就去取下一帧

而 Qt5 中信号与槽的连接函数新语法为:

1
connect(&theTimer, &QTimer::timeout, this, &QtTest::getFrame);	//超时就去取下一帧 

推荐使用 Qt5 新语法,具体原因可参考 qt5中信号和槽的新语法

个人粗浅理解:信号函数一般是 Qt 中控件的库函数,比如按钮控件 QButton 的 QButton::clicked () 函数,定时器 QTimer 的 QTimer::timeout () 等函数;而槽函数是响应函数,一般由用户自己编写,也可以使用 Qt 中库函数。

  使用 Qt 中可能会遇到的一些错误请参考 使用VS2010开发Qt程序的一点经验http://www.cnblogs.com/csuftzzk/category/445772.html)。

后记

  本来其实就想把问题篇写出来的,毕竟主要就是想记录一下那个显示函数,但是感觉有点没头没尾,就把 VS 集成 Qt 开发环境也稍微写了一下,而使用篇确实是因为参考资料已经写的很详细了,所以就直接一笔带过了。

参考资料

[1] QT +openCV 实现摄像头采集以及拍照功能http://blog.csdn.net/llh318724/article/category/930663

[2] VS2010 + QT5.2+ QT-VS-Addin1.2.2开发环境配置http://blog.csdn.net/qqmindyourwill/article/category/5990841

[3] Qt+OpenCV界面http://blog.csdn.net/fm0517/article/category/1110960

[4] Qt中用QLabel显示OpenCV中Mat图像数据出现扭曲现象的解决http://blog.csdn.net/loveaborn/article/category/1164072