如何使用 QPainter 在 QOpenGLWidget 中进行叠加 [关闭]

Posted

技术标签:

【中文标题】如何使用 QPainter 在 QOpenGLWidget 中进行叠加 [关闭]【英文标题】:How to use QPainter for overlaying in QOpenGLWidget [closed] 【发布时间】:2015-03-09 04:05:10 【问题描述】:

我收到了问题,使用QPainter 覆盖在QOpenGLWidget Qt 中。

我创建了一个CameraSurface_GL 类来绘制从 ip camera 接收到的 yuv 图像。

这是我的代码:

#include "camerasurface_gl.h"
#include <QtWidgets>
#include <QtGui>
#include <QOpenGLFunctions_3_0>

const char* YUV420P_VS = ""
    "#version 330\n"
    ""
    "uniform mat4 u_pm;"
    "uniform vec4 draw_pos;"
    ""
    "const vec2 verts[4] = vec2[] ("
    "  vec2(-0.5,  0.5), "
    "  vec2(-0.5, -0.5), "
    "  vec2( 0.5,  0.5), "
    "  vec2( 0.5, -0.5)  "
    ");"
    ""
    "const vec2 texcoords[4] = vec2[] ("
    "  vec2(0.0, 1.0), "
    "  vec2(0.0, 0.0), "
    "  vec2(1.0, 1.0), "
    "  vec2(1.0, 0.0)  "
    "); "
    ""
    "out vec2 v_coord; "
    ""
    "void main() "
    "   vec2 vert = verts[gl_VertexID];"
    "   vec4 p = vec4((0.5 * draw_pos.z) + draw_pos.x + (vert.x * draw_pos.z), "
    "                 (0.5 * draw_pos.w) + draw_pos.y + (vert.y * draw_pos.w), "
    "                 0, 1);"
    "   gl_Position = u_pm * p;"
    "   v_coord = texcoords[gl_VertexID];"
    ""
    "";

const char* YUV420P_FS = ""
    "#version 330\n"
    "uniform sampler2D y_tex;"
    "uniform sampler2D u_tex;"
    "uniform sampler2D v_tex;"
    "in vec2 v_coord;"
    "layout( location = 0 ) out vec4 fragcolor;"
    ""
    "const vec3 R_cf = vec3(1,  0.000000,  1.13983);"
    "const vec3 G_cf = vec3(1, -0.39465, -0.58060);"
    "const vec3 B_cf = vec3(1,  2.03211,  0.000000);"
    "const vec3 offset = vec3(-0.0625, -0.5, -0.5);"
    ""
    "void main() "
    "  float y = texture(y_tex, v_coord).r;"
    "  float u = texture(u_tex, v_coord).r;"
    "  float v = texture(v_tex, v_coord).r;"
    "  vec3 yuv = vec3(y,u,v);"
    "  yuv += offset;"
    "  fragcolor = vec4(0.0, 0.0, 0.0, 1.0);"
    "  fragcolor.r = dot(yuv, R_cf);"
    "  fragcolor.g = dot(yuv, G_cf);"
    "  fragcolor.b = dot(yuv, B_cf);"
    ""
    "";


CameraSurface_GL::CameraSurface_GL(QWidget *parent) :
    QOpenGLWidget(parent)
  ,vid_w(0)
  ,vid_h(0)
  ,win_w(0)
  ,win_h(0)
  ,vao(0)
  ,vao1(0)
  ,y_tex(0)
  ,u_tex(0)
  ,v_tex(0)
  ,vert(0)
  ,frag(0)
  ,prog(0)
  ,u_pos(-1)
  ,textures_created(false)
  ,shader_created(false)

    qRegisterMetaType<YUVFrame>("YUVFrame");
    m_ipCamera = new IpCamera;

    m_yuvWidth = 0;
    m_yuvHeight = 0;


    connect(m_ipCamera, SIGNAL(frameChanged(YUVFrame)), this, SLOT(slotFrameChanged(YUVFrame)));

    m_frameCount = 0;
    m_setup = 0;


CameraSurface_GL::~CameraSurface_GL()

    glDeleteTextures(1, &y_tex);
    glDeleteTextures(1, &u_tex);
    glDeleteTextures(1, &v_tex);

    glDeleteProgram(prog);


void CameraSurface_GL::openCamera(QString ipAddress, QString userName, QString password)

    if(m_ipCamera->isRunning())
        m_ipCamera->close();

    qDebug() << "open camera";

    bool opend = m_ipCamera->open(ipAddress, userName, password);
    if(opend == false)
        return;


void CameraSurface_GL::closeCamera()

    m_ipCamera->close();


void CameraSurface_GL::slotFrameChanged(YUVFrame frame)

    m_yuvData = QByteArray((char*)frame.yuvData, frame.width * frame.height * 3 / 2);
    m_yuvWidth = frame.width;
    m_yuvHeight = frame.height;

    if(m_setup == 0)
    
        setup_gl(frame.width, frame.height);
        resize_gl(rect().width(), rect().height());

        m_setup = 1;
    

    update();

    m_frameCount ++;


void CameraSurface_GL::setup_gl(int width, int height)

    vid_w = width;
    vid_h = height;

    if(!vid_w || !vid_h) 
      printf("Invalid texture size.\n");
      return;
    

    if(!setupTextures()) 
      return;
    

    if(!setupShader()) 
      return;
    

    return;


void CameraSurface_GL::resize_gl(int width, int height)

    win_w = width;
    win_h = height;

    pm.setToIdentity();
    pm.ortho(0, win_w, win_h, 0, 0.0, 100.0f);

    glUseProgram(prog);
    glUniformMatrix4fv(glGetUniformLocation(prog, "u_pm"), 1, GL_FALSE, pm.data());


void CameraSurface_GL::resizeGL(int width, int height)

    glViewport(0, 0, width, height);
    if(m_setup)
    
        resize_gl(width, height);
    


bool CameraSurface_GL::setupTextures()

    if(textures_created) 
      printf("Textures already created.\n");
      return false;
    

    glGenTextures(1, &y_tex);
    glBindTexture(GL_TEXTURE_2D, y_tex);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, vid_w, vid_h, 0, GL_RED, GL_UNSIGNED_BYTE, NULL);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

    glGenTextures(1, &u_tex);
    glBindTexture(GL_TEXTURE_2D, u_tex);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, vid_w/2, vid_h/2, 0, GL_RED, GL_UNSIGNED_BYTE, NULL);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

    glGenTextures(1, &v_tex);
    glBindTexture(GL_TEXTURE_2D, v_tex);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, vid_w/2, vid_h/2, 0, GL_RED, GL_UNSIGNED_BYTE, NULL);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

    textures_created = true;

    return true;


bool CameraSurface_GL::setupShader()

    if(shader_created) 
      printf("Already creatd the shader.\n");
      return false;
    

    vert = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vert, 1, &YUV420P_VS, 0);
    glCompileShader(vert);

    frag = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(frag, 1, &YUV420P_FS, 0);
    glCompileShader(frag);

    prog = glCreateProgram();
    glAttachShader(prog, vert);
    glAttachShader(prog, frag);
    glLinkProgram(prog);

    glUseProgram(prog);
    glUniform1i(glGetUniformLocation(prog, "y_tex"), 0);
    glUniform1i(glGetUniformLocation(prog, "u_tex"), 1);
    glUniform1i(glGetUniformLocation(prog, "v_tex"), 2);

    u_pos = glGetUniformLocation(prog, "draw_pos");

    glUseProgram(0);

    return true;


void CameraSurface_GL::setYPixels(uint8_t* pixels, int stride)

    glBindTexture(GL_TEXTURE_2D, y_tex);
    glPixelStorei(GL_UNPACK_ROW_LENGTH, stride);
    glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, vid_w, vid_h, GL_RED, GL_UNSIGNED_BYTE, pixels);


void CameraSurface_GL::setUPixels(uint8_t* pixels, int stride)

    glBindTexture(GL_TEXTURE_2D, u_tex);
    glPixelStorei(GL_UNPACK_ROW_LENGTH, stride);
    glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, vid_w/2, vid_h/2, GL_RED, GL_UNSIGNED_BYTE, pixels);


void CameraSurface_GL::setVPixels(uint8_t* pixels, int stride)

    glBindTexture(GL_TEXTURE_2D, v_tex);
    glPixelStorei(GL_UNPACK_ROW_LENGTH, stride);
    glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, vid_w/2, vid_h/2, GL_RED, GL_UNSIGNED_BYTE, pixels);



void CameraSurface_GL::initializeGL()

    initializeOpenGLFunctions();
    glClearColor(0, 0, 0, 1);


void CameraSurface_GL::paintEvent(QPaintEvent* e)

    QPainter painter;
    painter.begin(this);

    painter.beginNativePainting();

    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    if(m_yuvData.size())
    
        setYPixels((unsigned char*)m_yuvData.data(), m_yuvWidth);
        setUPixels((unsigned char*)m_yuvData.data() + m_yuvWidth * m_yuvHeight, m_yuvWidth / 2);
        setVPixels((unsigned char*)m_yuvData.data() + m_yuvWidth * m_yuvHeight * 5 / 4, m_yuvWidth / 2);

        glBindVertexArray(vao);
        glUseProgram(prog);

        glUniform4f(u_pos, rect().left(), rect().top(), rect().width(), rect().height());

        glActiveTexture(GL_TEXTURE0);
        glBindTexture(GL_TEXTURE_2D, y_tex);

        glActiveTexture(GL_TEXTURE1);
        glBindTexture(GL_TEXTURE_2D, u_tex);

        glActiveTexture(GL_TEXTURE2);
        glBindTexture(GL_TEXTURE_2D, v_tex);

        glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

        glUseProgram(0);
    

    painter.endNativePainting();

    painter.end();

我想在yuv层上绘制内容,所以我在void paintEvent(QPaintEvent* e)函数中附加了如下代码:

void CameraSurface_GL::paintEvent(QPaintEvent* e)

    QPainter painter;
    painter.begin(this);

    painter.beginNativePainting();

    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    if(m_yuvData.size())
    
        setYPixels((unsigned char*)m_yuvData.data(), m_yuvWidth);
        setUPixels((unsigned char*)m_yuvData.data() + m_yuvWidth * m_yuvHeight, m_yuvWidth / 2);
        setVPixels((unsigned char*)m_yuvData.data() + m_yuvWidth * m_yuvHeight * 5 / 4, m_yuvWidth / 2);

        glBindVertexArray(vao);
        glUseProgram(prog);

        glUniform4f(u_pos, rect().left(), rect().top(), rect().width(), rect().height());

        glActiveTexture(GL_TEXTURE0);
        glBindTexture(GL_TEXTURE_2D, y_tex);

        glActiveTexture(GL_TEXTURE1);
        glBindTexture(GL_TEXTURE_2D, u_tex);

        glActiveTexture(GL_TEXTURE2);
        glBindTexture(GL_TEXTURE_2D, v_tex);

        glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

        glUseProgram(0);
    

    painter.endNativePainting();

    //////new appended code//////
    QPixmap memPix(rect().width(), rect().height());
    QPainter memDC;
    memDC.setPen(Qt::red);
    memDC.drawRect(QRect(0, 0, 100, 100));

    painter.drawPixmap(rect(), memPix);

    /////end/////


    painter.end();

此时,我收到了导致程序崩溃的问题。

而且,当我也更改为以下内容时,我收到了相同的结果:

void CameraSurface_GL::paintEvent(QPaintEvent* e)

    QPainter painter;
    painter.begin(this);

    painter.beginNativePainting();

    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    if(m_yuvData.size())
    
        setYPixels((unsigned char*)m_yuvData.data(), m_yuvWidth);
        setUPixels((unsigned char*)m_yuvData.data() + m_yuvWidth * m_yuvHeight, m_yuvWidth / 2);
        setVPixels((unsigned char*)m_yuvData.data() + m_yuvWidth * m_yuvHeight * 5 / 4, m_yuvWidth / 2);
    

    painter.endNativePainting();

    QPixmap memPix(rect().width(), rect().height());
    QPainter memDC;
    memDC.setPen(Qt::red);
    memDC.drawRect(QRect(0, 0, 100, 100));

    painter.drawPixmap(rect(), memPix);
    painter.end();

而且,当我删除调用setYPixelssetUPixelssetVPixels 的部分时,我的程序并没有崩溃。

我不知道为什么会收到错误消息。我想知道这个问题的原因。

【问题讨论】:

【参考方案1】:

您应该取消绑定任何纹理、缓冲区等。我在未绑定的 VBO 上遇到过类似的问题。

【讨论】:

以上是关于如何使用 QPainter 在 QOpenGLWidget 中进行叠加 [关闭]的主要内容,如果未能解决你的问题,请参考以下文章

如何在Qgraphicsview上使用QPainter绘图

我如何使用 QPainter 进行绘画?

如何在 QML Canvas 对象中检索 QPainter 对象

如何使用 OpenGL 3.3 格式的 QPainter?

如何使用 Qpainter 在 Qt 中绘制棋盘

如何在paintEvent之外获取QPainter的字体度量?