使用OpenCV打开一张图片是一件很简单的事情,并且显示出来也非常的轻松,简单到只需两行代码,这是因为OpenCV本身提供了一个HighGui模块,用来做图片的交互显示。
#include<opencv2/opencv.hpp>
int main(){
cv::Mat src = cv::imread("lena.jpg");
std::string winName = "lena";
cv::namedWindow(winName, cv::WINDOW_AUTOSIZE);
cv::imshow(winName, src);
}
但通常情况下,我们需要自己制作一个ui,用来显示一张图像。如果以Qt作为一个制作UI的工具,网上常用的方法是将cv::Mat格式转换为QImage,或者QPixel格式,然后输出在Qt的控件上。
那有没有可能在qt中直接使用OpenCV的highgui显示cv::Mat类型的数据,而不作转换呢?当然是可以的,而且省略了一步转换,效率更高:
首先准备一个简单的测试界面:由一个widget控件和一个pushButten控件,这样点击按钮打开图像动作和载体都有了。
fig1. 一个widget和一个按钮
1. OpenCV HighGUI
用OpenCV的方式打开一个图片,并显示在nameWindow窗口:
#include "MatShow.h"
#include<opencv2/opencv.hpp>
MatShow::MatShow(QWidget *parent)
: QMainWindow(parent)
{
ui.setupUi(this);
connect(ui.pushButton, &QPushButton::clicked, [&]() {
//我们所熟悉的Opencv打开一张图片,并显示
cv::Mat src = cv::imread("lena.jpg");
std::string winName = "lena";
cv::namedWindow(winName, cv::WINDOW_AUTOSIZE);
cv::imshow(winName, src);
});
}
执行之后,这样的结果很明显不是我们想要的。
2. Qt嵌入HighGUI
既然nameWindow窗口也是一个窗口,那么我们可以将nameWindow窗口的句柄 传递给Qt的ui控件上,需要注意的是:
- 需要注意的是 opencv4之后使用cvGetWindowHandle需要添加头文件#include <opencv2/highgui/highgui_c.h>
- 使用windows的api需要添加#include<Windows.h>
#include "MatShow.h"
#include<opencv2/opencv.hpp>
#include<Windows.h>
#include <opencv2/highgui/highgui_c.h>
MatShow::MatShow(QWidget *parent)
: QMainWindow(parent)
{
ui.setupUi(this);
connect(ui.pushButton, &QPushButton::clicked, [&]() {
//我们所熟悉的Opencv打开一张图片,并显示
cv::Mat src = cv::imread("lena.jpg");
std::string winName = "lena";
cv::namedWindow(winName, cv::WINDOW_AUTOSIZE);
cv::imshow(winName, src);
//再Qt控件上显示cv::nameWindow窗口
HWND hwnd = (HWND)cvGetWindowHandle(winName.c_str());
HWND paraent = GetParent(hwnd);//得到nameWindow窗口的父句柄
SetParent(hwnd, (HWND)ui.widget->winId());//设置ui控件的句柄是父句柄
ShowWindow(paraent, SW_HIDE);//隐藏掉nameWindow窗口
cv::resizeWindow(winName, cv::Size(ui.widget->width(), ui.widget->height()));
});
}
运行起来就是这个样子了:
3. 后记
整体代码就这20几行,是很简单的,主要就是对窗口句柄的理解。