[OpenCV Qt教程] 在Qt图形界面中显示OpenCV图像的OpenGL Widget (第一部分)
2017-02-21 14:10
543 查看
本文译自:http://www.robot-home.it/blog/en/software/tutorial-opencv-qt-opengl-widget-per-visualizzare-immagini-da-opencv-in-una-gui-con-qt/
重要术语保持英文不变,如Widget等。原文中rendering意为渲染或绘制。
此教程是关于在Qt图形界面中显示OpenCV图像的问题,我们创建了一个基于QGLWidget的Qt Widget。
这个Widget提供了更好的图像绘制性能,并支持在缩放窗口时固定高宽比。
此教程假定读者掌握关于C++、Qt 5 框架、OpenCV 2库在Qt Creator中开发环境的配置的基础知识。实例代码是在Windows 7下设计的,但也能在不需大幅改动的前提下移植到Linux和MacOS中,只需配置正确的库文件路径即可。
第一部分描述了Widget的创建。
CQtOpenCVViewerGl 类的创建:
在 QtCreator 中:
文件-> 新建文件或工程 -> C++ -> C++ Class -> Choose
类名: CQtOpenCVViewerGl
基类: QGLWidget [注意字母大小写]
译者注:从Qt 5.4版本开始,QGLWidget已更新为QOpenGLWidget。
到这一步你应该在工程中建立了两个新的文件,cqtopencvviewergl.cpp 和 cqtopencvviewergl.h 。
打开 cqtopencvviewergl.h 并添加几个私有成员变量:
mSceneChanged: 指示图像是否需要绘制
mRenderQtImg: 包含需要绘制的图像 (Qt格式)
mOrigImage: 包含需要绘制的图像 (OpenCV格式)
mBgColor: 不显示图像的区域的背景色
mOutH & mOutW: 图像真实绘制尺寸
mImgratio: 包含有关图像大小比例的信息
mPosX & mPosY: 左上角开始的图像坐标,允许在窗口部件的中心绘制图像
至此我们还需要一些函数,首先我们添加一个信号函数(signal)和一个槽函数(slot):
void imageSizeChanged( int outW, int outH ): 这是一个用来在“Qt世界中”交流”的函数,它能够发出widget大小发生变化的消息,还有变化后的尺寸大小(outW、outH参数)。如果我们想向Widget传递一个缩放过的图像,而不想迫使Widget在每次渲染时都进行缩放操作的话,这个函数很有用。
bool showImage( cv::Mat image ): 这个函数向窗口传递需要绘制的图像。这是一个槽函数,是信号函数的响应。
最后,添加五个函数用来绘制图像:
void initializeGL(): 初始化openGL
void paintGL(): 使用 openGL 绘制
void resizeGL(int width, int height): 使用 openGL 调整尺寸
void updateScene(): 强制绘制
void renderImage(): 被paintGL调用,用来高效地绘制图像
现在,是时候在 cqtopencvviewergl.cpp 中进行变量初始化和函数实现了。
构造函数:
其他函数:
设定背景色,这个函数如同下一个一样,从 makeCurrent 函数开始,这个函数允许图形界面使用多于一个的OpenGL部件。
这个函数在每次Widget大小变化时被调用:
3-12行: OpenGL 布局初始化
14-21行: 计算图像大小,维持高宽比
23行: 发出 “imageSizeChanged” 信号
26-27行: 计算图像左上角的坐标,使得图像位于窗口中间
29-31行: 使Widget知道有一张新的图像要显示
updateScene 函数被用来在图像更新之后 “强制” 绘制图像。 只在确定需要时才调用 updateGL 绘制图像。
paintGL 是当OpenGL Widget等待更新时被调用的一个函数。在这里,这个函数清除现有图像并调用renderImage 来高效地绘制图像。
renderImage 是widget中一个主要的函数,事实上是它绘制了图像。
19-32行: 这几行用来调整图像大小,并保证此时图像是一直可见的。注意图像大小是否正确,过于繁重的操作是不会被处理的。我在这一段插入了imageSizeChanged 信号,使得其他GUI函数仅在原始图像创建时进行调整大小的操作,而不是在每一次绘制图像时都去处理
36行: 指示图像左上角坐标,使得图像居中显示
42行: 利用OpenGL 的 glDrawPixels 函数进行真正的绘制
最后的函数也很重要,这个函数需要告诉widget哪个图像要被绘制,showImage 函数工作在单通道或三通道的8 bit OpenCV (cv::Mat) 格式下,并且把图像转换成QGLWidget要用的格式。
这个函数还计算并存储了图像的高宽比(第5行)。
教程第一部分结束。
示例代码可到Github上下载。
https://github.com/Myzhar/QtOpenCVViewerGl
重要术语保持英文不变,如Widget等。原文中rendering意为渲染或绘制。
此教程是关于在Qt图形界面中显示OpenCV图像的问题,我们创建了一个基于QGLWidget的Qt Widget。
这个Widget提供了更好的图像绘制性能,并支持在缩放窗口时固定高宽比。
此教程假定读者掌握关于C++、Qt 5 框架、OpenCV 2库在Qt Creator中开发环境的配置的基础知识。实例代码是在Windows 7下设计的,但也能在不需大幅改动的前提下移植到Linux和MacOS中,只需配置正确的库文件路径即可。
第一部分描述了Widget的创建。
CQtOpenCVViewerGl 类的创建:
在 QtCreator 中:
文件-> 新建文件或工程 -> C++ -> C++ Class -> Choose
类名: CQtOpenCVViewerGl
基类: QGLWidget [注意字母大小写]
译者注:从Qt 5.4版本开始,QGLWidget已更新为QOpenGLWidget。
到这一步你应该在工程中建立了两个新的文件,cqtopencvviewergl.cpp 和 cqtopencvviewergl.h 。
打开 cqtopencvviewergl.h 并添加几个私有成员变量:
private: bool mSceneChanged; /// Indicates when OpenGL view is to be redrawn QImage mRenderQtImg; /// Qt image to be rendered cv::Mat mOrigImage; /// original OpenCV image to be shown QColor mBgColor; /// Background color int mOutH; /// Resized Image height int mOutW; /// Resized Image width float mImgratio; /// height/width ratio int mPosX; /// Top left X position to render image in the center of widget int mPosY; /// Top left Y position to render image in the center of widget
mSceneChanged: 指示图像是否需要绘制
mRenderQtImg: 包含需要绘制的图像 (Qt格式)
mOrigImage: 包含需要绘制的图像 (OpenCV格式)
mBgColor: 不显示图像的区域的背景色
mOutH & mOutW: 图像真实绘制尺寸
mImgratio: 包含有关图像大小比例的信息
mPosX & mPosY: 左上角开始的图像坐标,允许在窗口部件的中心绘制图像
至此我们还需要一些函数,首先我们添加一个信号函数(signal)和一个槽函数(slot):
signals: void imageSizeChanged( int outW, int outH ); /// Used to resize the image outside the widget public slots: bool showImage( cv::Mat image ); /// Used to set the image to be viewed
void imageSizeChanged( int outW, int outH ): 这是一个用来在“Qt世界中”交流”的函数,它能够发出widget大小发生变化的消息,还有变化后的尺寸大小(outW、outH参数)。如果我们想向Widget传递一个缩放过的图像,而不想迫使Widget在每次渲染时都进行缩放操作的话,这个函数很有用。
bool showImage( cv::Mat image ): 这个函数向窗口传递需要绘制的图像。这是一个槽函数,是信号函数的响应。
最后,添加五个函数用来绘制图像:
protected: void initializeGL(); /// OpenGL initialization void paintGL(); /// OpenGL Rendering void resizeGL(int width, int height); /// Widget Resize Event void updateScene(); /// Forces a scene update void renderImage(); /// Render image on openGL frame
void initializeGL(): 初始化openGL
void paintGL(): 使用 openGL 绘制
void resizeGL(int width, int height): 使用 openGL 调整尺寸
void updateScene(): 强制绘制
void renderImage(): 被paintGL调用,用来高效地绘制图像
现在,是时候在 cqtopencvviewergl.cpp 中进行变量初始化和函数实现了。
构造函数:
CQtOpenCVViewerGl::CQtOpenCVViewerGl(QWidget *parent) : QGLWidget(parent) { mSceneChanged = false; mBgColor = QColor::fromRgb(150, 150, 150); mOutH = 0; mOutW = 0; mImgratio = 4.0f/3.0f; // Default image ratio mPosX = 0; mPosY = 0; }
其他函数:
void CQtOpenCVViewerGl::initializeGL() { makeCurrent(); qglClearColor(mBgColor.darker()); }
设定背景色,这个函数如同下一个一样,从 makeCurrent 函数开始,这个函数允许图形界面使用多于一个的OpenGL部件。
void CQtOpenCVViewerGl::resizeGL(int width, int height) { makeCurrent(); glViewport(0, 0, (GLint)width, (GLint)height); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(0, width, 0, height, 0, 1); // To Draw image in the center of the area glMatrixMode(GL_MODELVIEW); // ---> Scaled Image Sizes mOutH = width/mImgratio; mOutW = width; if(mOutH>height) { mOutW = height*mImgratio; mOutH = height; } emit imageSizeChanged( mOutW, mOutH ); // < --- Scaled Image Sizes mPosX = (width-mOutW)/2; mPosY = (height-mOutH)/2; mSceneChanged = true; updateScene(); }
这个函数在每次Widget大小变化时被调用:
3-12行: OpenGL 布局初始化
14-21行: 计算图像大小,维持高宽比
23行: 发出 “imageSizeChanged” 信号
26-27行: 计算图像左上角的坐标,使得图像位于窗口中间
29-31行: 使Widget知道有一张新的图像要显示
void CQtOpenCVViewerGl::updateScene() { if( mSceneChanged && this->isVisible() ) updateGL(); }
updateScene 函数被用来在图像更新之后 “强制” 绘制图像。 只在确定需要时才调用 updateGL 绘制图像。
void CQtOpenCVViewerGl::paintGL() { makeCurrent(); if( !mSceneChanged ) return; glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); renderImage(); mSceneChanged = false; }
paintGL 是当OpenGL Widget等待更新时被调用的一个函数。在这里,这个函数清除现有图像并调用renderImage 来高效地绘制图像。
void CQtOpenCVViewerGl::renderImage() { makeCurrent(); glClear(GL_COLOR_BUFFER_BIT); if (!mRenderQtImg.isNull()) { glLoadIdentity(); QImage image; // the image rendered glPushMatrix(); { int imW = mRenderQtImg.width(); int imH = mRenderQtImg.height(); // The image is to be resized to fit the widget? if( imW != this->size().width() && imH != this->size().height() ) { image = mRenderQtImg.scaled( //this->size(), QSize(mOutW,mOutH), Qt::IgnoreAspectRatio, Qt::SmoothTransformation ); //qDebug( QString( "Image size: (%1x%2)").arg(imW).arg(imH).toAscii() ); } else image = mRenderQtImg; // --->Centering image in draw area glRasterPos2i( mPosX, mPosY ); // < --- Centering image in draw area imW = image.width(); imH = image.height(); glDrawPixels( imW, imH, GL_RGBA, GL_UNSIGNED_BYTE, image.bits()); } glPopMatrix(); // end glFlush(); } }
renderImage 是widget中一个主要的函数,事实上是它绘制了图像。
19-32行: 这几行用来调整图像大小,并保证此时图像是一直可见的。注意图像大小是否正确,过于繁重的操作是不会被处理的。我在这一段插入了imageSizeChanged 信号,使得其他GUI函数仅在原始图像创建时进行调整大小的操作,而不是在每一次绘制图像时都去处理
36行: 指示图像左上角坐标,使得图像居中显示
42行: 利用OpenGL 的 glDrawPixels 函数进行真正的绘制
bool CQtOpenCVViewerGl::showImage( cv::Mat image ) { image.copyTo(mOrigImage); mImgratio = (float)image.cols/(float)image.rows; if( mOrigImage.channels() == 3) mRenderQtImg = QImage((const unsigned char*)(mOrigImage.data), mOrigImage.cols, mOrigImage.rows, mOrigImage.step, QImage::Format_RGB888).rgbSwapped(); else if( mOrigImage.channels() == 1) mRenderQtImg = QImage((const unsigned char*)(mOrigImage.data), mOrigImage.cols, mOrigImage.rows, mOrigImage.step, QImage::Format_Indexed8); else return false; mRenderQtImg = QGLWidget::convertToGLFormat(mRenderQtImg); mSceneChanged = true; updateScene(); return true; }
最后的函数也很重要,这个函数需要告诉widget哪个图像要被绘制,showImage 函数工作在单通道或三通道的8 bit OpenCV (cv::Mat) 格式下,并且把图像转换成QGLWidget要用的格式。
这个函数还计算并存储了图像的高宽比(第5行)。
教程第一部分结束。
示例代码可到Github上下载。
https://github.com/Myzhar/QtOpenCVViewerGl
相关文章推荐
- [OpenCV Qt教程] 在Qt图形界面中显示OpenCV图像的OpenGL Widget(第二部分)
- openGL的图像在Qt的界面中显示
- Qt自定义界面类并提升(提升的窗口部件),把OpenGL绘制的图形显示在QT的ui界面上
- Qt自定义界面类并提升(提升的窗口部件),把OpenGL绘制的图形显示在QT的ui界面上
- 9-基于OMAPL138开发板的Linux QT图像界面开发教程
- Qt4: Show an image in your widget – 在Qt里面显示图像
- 使用OpenCV 读取图片 ,再用OpenGL显示,图像有错位
- 9.10 QT VS2010 Opencv图像界面程序
- 【OpenCV入门教程之三】 图像的载入,显示和输出 一站式完全解析
- QT显示OPENCV的图像
- Qt界面显示图片,Qt与opencv的联合运用
- Qt中用QLabel显示OpenCV中Mat图像数据出现扭曲现象的解决
- Qt中显示opencv的图像
- ARM开发板OK6410移植opencv-2.4.7库qt界面显示(附加各种问题解决方案)
- 【Qt OpenGL教程】17:2D图像文字
- 【改进】Qt界面显示图片,在图上绘制图形,拖动顶点改变大小
- 一个显示 OpenCV Mat 图像的自定义 Qt 控件
- QT OpenCv 图像显示
- 【OpenCV入门教程之三】 图像的载入,显示和输出 一站式完全解析
- 使用Qt+OpenCV+VideoInput 显示摄像头图像