OpenCV本身能生成的GUI界面极为简陋,故一般使用MFC或Qt等框架来搭建GUI界面,并将OpenCV嵌入进去。因为我之前也用过Qt,故此处选择了Qt作为GUI框架,二者结合的主要问题在于图片的显示上,本文就以最新的OpenCV3及Qt5为例介绍一下实现方法。
基本环境的搭建
首先保证独立的Qt及OpenCV程序都能在VS上正常的编译运行起来。
相关版本
Windows 10 64-bit
Visual Studio 2015
OpenCV 3.1
Qt 5.7
Qt @ VS
参考之前的文章:VS2015搭建Qt 5.7开发环境
注意Qt要选32-bit,以便和OpenCV兼容。
OpenCV @ VS
参考之前的文章:VS2015下编译OpenCV 3.1
需要注意的是,CMake配置时有一个WITH_QT
选项,这个选项是指OpenCV的highgui
模块本身是否使用Qt,似乎可以不选这个选项的。如果选择了WITH_QT
,点击Configure
后会出现新的Qt相关路径的选项,如果Qt安装正常的话,这里的路径是会自动生成的:
点击Generate
后会出现很多如下warning:
1 | CMake Warning (dev) in modules/highgui/CMakeLists.txt: |
相关解释可以参考这里,直接忽略这个警告即可。
另外,在编译OpenCV时也会出现很多和Qt有关的Warning,不过没有Error,可以忽略。
选择了WITH_QT
后,highgui
本身的窗口界面会变成基于Qt的,比原来要好看一些,而且自动集成了一些图片缩放、保存等功能:
不过这还是满足不了我们自由设计GUI界面的需求,接下来就要讨论如何在Qt项目中使用OpenCV。
数据结构转换算法
OpenCV中使用Mat
保存图片,而Qt中则使用QImage
或QPixmap
,故二者结合的核心就在于这两个类之间的转换。网上已经有人实现了转换代码:
经实际测试,上述代码基本是可以正常使用的,只是有一些小Bug需要修正下,后文会具体说明。这里将其中Mat
->QImage
的核心代码摘录备份如下:
1 | QImage cvMatToQImage( const cv::Mat &inMat ) |
上述代码在处理CV_8UC1
类型时存在Bug,sColorTable.isEmpty()
这个判断永远都是不会为真的,即使是在第一次执行时。解决方法有以下几种:
1.直接去掉这个if
判断,此做法的缺点是每次都会生成颜色表,效率不高;
2.使用sColorTable
中元素的值来判断是否初始化过了;
3.一般使用时会将这个方法封装在一个类中,此时可以将sColorTable
设置为类变量,在构造函数中初始化即可。
以上这种方法相当于调用构造函数生成了一个新的QImage,然后复制图像数据过去。另一种思路可参考以下链接:
Qt中图片的显示
最简单的办法是使用QLabel
,更高效一些的方法是使用QWidget
。使用QLabel
时只需调用setPixmap()
方法设置图片即可,QPixmap
与QImage
间的转换可用QPixmap::fromImage()
函数完成。另外,使用QLabel
的setScaledContents()
方法可以设置图像自动缩放。
给出一个完整的例子:
1 | Mat inputimg = imread("pic.jpg"); |