在 QGLWidget 中绘制一个 cv::Mat?
Posted
技术标签:
【中文标题】在 QGLWidget 中绘制一个 cv::Mat?【英文标题】:Draw a cv::Mat inside a QGLWidget? 【发布时间】:2013-04-15 14:46:11 【问题描述】:我想知道如何将 cv::Mat 绘制到 QGLWidget 中。我找到了here 一种方法并尝试实现它。但是我的小部件是黑色的。
这是我的小部件的代码:
h 文件
#ifndef GLVIEWER_H
#define GLVIEWER_H
#include <QtOpenGL/QGLWidget>
#include <QtOpenGL/QtOpenGL>
#include <opencv2/core/core.hpp>
class GLViewer : public QGLWidget
Q_OBJECT
public:
GLViewer(QWidget *parent = NULL);
void setNewFrame(cv::Mat newframe);
protected:
void initializeGL();
void resizeGL(int w, int h);
void paintGL();
void mousePressEvent(QMouseEvent *event);
void mouseMoveEvent(QMouseEvent *event);
void keyPressEvent(QKeyEvent *event);
cv::Mat frame;
;
#endif // GLVIEWER_H
cpp 文件
#include "glviewer.h"
#include <iostream>
#include <QtGui/QMouseEvent>
GLViewer::GLViewer(QWidget *parent) : QGLWidget(parent)
setMouseTracking(true);
frame = cv::Mat::ones(25, 50, CV_8UC3) * 255;
void GLViewer::setNewFrame(cv::Mat newframe)
frame = newframe;
paintGL();
void GLViewer::initializeGL()
std::cout << "initializeGL" << std::endl;
glViewport(0,0,this->width(), this->height());
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-this->width()/2, this->width()/2, this->height()/2, -this->height()/2, -1, 1);
void GLViewer::resizeGL(int w, int h)
glViewport(0, 0, w, h);
// glMatrixMode(GL_PROJECTION);
// glLoadIdentity();
// gluOrtho2D(0, w, 0, h); // set origin to bottom left corner
// glMatrixMode(GL_MODELVIEW);
// glLoadIdentity();
void GLViewer::paintGL()
//std::cout << "paint" << std::endl;
glClear(GL_COLOR_BUFFER_BIT);
glClearColor(1.0f, 0, 0, 1.0f);
glDrawPixels(frame.rows, frame.cols,
GL_RGB,
GL_UNSIGNED_BYTE,
frame.data);
由于我已经使用 'cv::Mat::ones(25, 50, CV_8UC3) * 255;' 初始化了 cv::Mat,我希望看到一个蓝色的小矩形,但是.. 什么也没发生,全黑的小部件.
谁能给我指出一个解决方案?
编辑
我试图将背景更改为红色,现在一切都是红色的。这是输出:
背景是正确的,但蓝色矩形..不是蓝色的,即使它看起来是一个矩形.. 发生了什么?我试图反转 frame.cols 和 frame.cols,以及 GL_BGR 而不是 GL_RGB 以及一些数据类型的随机试验(GL_UNSIGNED_SHORT 等),但没有什么比这更好的结果了..
【问题讨论】:
I've talked about this stuff here. 【参考方案1】:glDrawPixels
不是一个明智的选择。 OpenGL 中的 2D 像素绘制速度非常慢。您真正想要做的是将矩阵加载到纹理中,然后在其上绘制带有纹理的图元。
但是对于您的简单用例:
我建议你使用 QGLWidget,但仍然使用 QPainter 来绘制东西。它将完全加速,但您不必处理所有这些转换等!
代码相当简单。看一下: https://sourceforge.net/p/gerbil/svn/HEAD/tree/trunk/gerbil-gui/scaledview.cpp (自动缩放内容的小部件示例)
要从 Mat 转换为 QImage,请参阅: https://sourceforge.net/p/gerbil/svn/HEAD/tree/trunk/common/qtopencv.cpp
转换 QImage QPixmap 可以通过从另一个构造一个来隐式地完成。请注意,它本质上只会将图像数据作为纹理存储在显卡上。
cv::Mat 到 QImage 的转换是“冗余”数据副本。不过真的可以忽略不计,试试吧!
【讨论】:
我更喜欢在纯opengl中保留绘图的东西。无论如何,我知道纹理更好但我认为它有点复杂..你能指出一些例子吗? 显然您尝试直接使用 Mat 的内存失败了。可能每行的跳过是罪魁祸首。或者……像那样。 OpenCV 文档中描述了如何在内部设计矩阵。好吧,在不知道自己在做什么的情况下访问 Mat.data 并不是一个好主意。即使你这样做,它也会变得复杂。顺便提一句。很抱歉,我手头没有 GL 示例。【参考方案2】:您的resizeGL()
正在清除您在initializeGL()
中进行的矩阵设置,尤其是glOrtho()
调用。
尝试将矩阵设置移动到paintGL()
:
...
void GLViewer::initializeGL()
std::cout << "initializeGL" << std::endl;
glViewport(0,0,width(), height());
void GLViewer::resizeGL(int w, int h)
glViewport(0, 0, w, h);
void GLViewer::paintGL()
std::cout << "paint" << std::endl;
glClear(GL_COLOR_BUFFER_BIT);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-width()/2.0, width()/2.0, height()/2.0, -height()/2.0, -1, 1);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glRasterPos2i(width()/2.0,-height()/2.0);
// also try glRasterPos2i(0,0)
glPixelZoom(-1.0f,-1.0f);
glDrawPixels
(
frame.rows, frame.cols,
GL_RGB,
GL_UNSIGNED_BYTE,
frame.data
);
...
编辑:尝试在glDrawPixels()
调用之前发出glPixelStore( GL_UNPACK_ALIGNMENT, 1 )
。或切换到GL_RGBA
和四分量cv::Mat
格式。
【讨论】:
以上是关于在 QGLWidget 中绘制一个 cv::Mat?的主要内容,如果未能解决你的问题,请参考以下文章
QDockWidget - QGlWidget - 当小部件从停靠栏中拖出时,可绘制无效