首页 > 其他分享 >QT 绘制YUV420图片

QT 绘制YUV420图片

时间:2022-12-15 14:23:01浏览次数:39  
标签:tex 1.0 QT TEXTURE YUV420 program 2D GL 绘制

Qt不能直接绘制YUV数据,需要使用QOPenGLWidget使用OPENGL来绘制,并且这样显示直接用的显卡绘制

使用QOPenGLWidget绘制YUV数据,我们需要继承QOpenGLWidget和QOpenGLFunctions(可以使用更高版本的QOpenGLFunctions_4_5_Core),QOpenGLFunctions提供了OPENGL的绘制接口。

头文件如下:

#include "QOpenGLWidget"

#include "QMatrix4x4"

#include "qopenglfunctions_4_5_core.h"

class PlayerWidget : public QOpenGLWidget,
                     public QOpenGLFunctions_4_5_Core
{
    Q_OBJECT
public:
    PlayerWidget(QWidget *parent = Q_NULLPTR);

    /// I420 就是 YUV420P,这个函数设置裸数据,和图片宽高
    void setI420Data(std::shared_ptr> d, int width, int height);


    // 以下是绘制YUV420P的方法,继承自QOPenGLWidget
protected:
    void initializeGL() override;
    void paintGL() override;
    void resizeGL(int w, int h) override;
private:
    void InitShaders();
    GLuint program{0};
    GLuint tex_y{0};
    GLuint tex_u{0};
    GLuint tex_v{0};
    GLuint sampler_y{0};
    GLuint sampler_u{0};
    GLuint sampler_v{0};
    GLuint matWorld{0};
    GLuint  matView{0};
    GLuint  matProj{0};

    QMatrix4x4 mProj;
    QMatrix4x4 mView;
    QMatrix4x4 mWorld;

// 图片宽高,和I420裸数据
    int m_width{-1};
    int m_height{1};
    std::shared_ptr> m_cur_data{nullptr};// 需要绘制的I420数据

};

源文件如下:

#include "playerwidget.h"

#define ATTRIB_VERTEX 3
#define ATTRIB_TEXTURE 4

static const char *vertexShader = "\
        attribute vec4 vertexIn;\
attribute vec2 textureIn;\
varying vec2 textureOut;\
uniform mat4 mWorld;\
uniform mat4 mView;\
uniform mat4 mProj;\
void main(void)\
{\
    gl_Position =vertexIn * mWorld * mView * mProj  ;\
    textureOut = textureIn;\
}";

static const char *fragmentShader =
        #if defined(WIN32)
        "#ifdef GL_ES\n"
        "precision mediump float;\n"
        "#endif\n"
        #else
        #endif
        "varying vec2 textureOut;\
        uniform sampler2D tex_y;\
uniform sampler2D tex_u;\
uniform sampler2D tex_v;\
void main(void)\
{\
    vec3 yuv;\
    vec3 rgb;\
    yuv.x = texture2D(tex_y, textureOut).r;\
    yuv.y = texture2D(tex_u, textureOut).r - 0.5;\
    yuv.z = texture2D(tex_v, textureOut).r - 0.5;\
    rgb = mat3( 1,       1,         1,\
                0,       -0.39465,  2.03211,\
                1.13983, -0.58060,  0) * yuv;\
    gl_FragColor = vec4(rgb, 1);\
}";

static const GLfloat vertexVertices[] = {
    -1.0f, -1.0f,
    1.0f, -1.0f,
    -1.0f,  1.0f,
    1.0f,  1.0f,
};

static const GLfloat textureVertices[] = {
    0.0f,  1.0f,
    1.0f,  1.0f,
    0.0f,  0.0f,
    1.0f,  0.0f,
};

PlayerWidget::PlayerWidget(QWidget *parent):QOpenGLWidget(parent)
{}

void PlayerWidget::setI420Data(std::shared_ptr > d, int width, int height )
{
    m_cur_data = std::move(d);
    m_width = width;
    m_height = height;

    repaint();
}

void PlayerWidget::initializeGL()
{
    initializeOpenGLFunctions();

    const GLubyte* name = glGetString(GL_VENDOR); //返回负责当前OpenGL实现厂商的名字
    const GLubyte* biaoshifu = glGetString(GL_RENDERER); //返回一个渲染器标识符,通常是个硬件平台
    const GLubyte* OpenGLVersion =glGetString(GL_VERSION); //返回当前OpenGL实现的版本号
    //    const GLubyte* OpenGLExensions =glGetString(GL_EXTENSIONS); //

    /// 打印OpenGL版本,标识,厂商信息
    QString str;
    str.sprintf("%s | %s | %s",name, biaoshifu, OpenGLVersion);
    qDebug()<data();
    }
    else
    {
        return;
    }

    int w = m_width;
    int h = m_height;
    const uint8_t *u = y + w*h ;
    const uint8_t *v = u + w*h/4;

    // 清除缓冲区
    glClearColor(0.0,0.0,0.0,0.0);
    glClear(GL_COLOR_BUFFER_BIT);

    // Y
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, tex_y);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, w, h, 0, GL_RED, GL_UNSIGNED_BYTE, y);
    glUniform1i(sampler_y, 0);

    // U
    glActiveTexture(GL_TEXTURE1);
    glBindTexture(GL_TEXTURE_2D, tex_u);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, w/2, h/2, 0, GL_RED, GL_UNSIGNED_BYTE, u);
    glUniform1i(sampler_u, 1);

    // V
    glActiveTexture(GL_TEXTURE2);
    glBindTexture(GL_TEXTURE_2D, tex_v);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, w/2, h/2, 0, GL_RED, GL_UNSIGNED_BYTE, v);
    glUniform1i(sampler_v, 2);

    //        QOpenGLShaderProgram::setUniformValue();
    glUniformMatrix4fv(matWorld,1, GL_FALSE, mWorld.constData());
    glUniformMatrix4fv(matView,1, GL_FALSE, mView.constData());
    glUniformMatrix4fv(matProj,1, GL_FALSE, mProj.constData());

    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

    glFlush();

}

void PlayerWidget::resizeGL(int w, int h)
{
    float viewWidth=2.0f;
    float viewHeight=2.0f;

    mWorld.setToIdentity();

    mView.setToIdentity();
    mView.lookAt(QVector3D(0.0f,0.0f,1.0f),QVector3D(0.f,0.f,0.f),QVector3D(0.f,1.f,0.f));

    mProj.setToIdentity();
    if(m_cur_data) /// 在这里计算宽高比
    {
        float aspectRatio = 1.0*m_width/m_height;
        //aspectRatio = float(4) / 3; // 强制长宽比
        if(float(float(w)/h > aspectRatio))
        {
            viewHeight = 2.0f;
            viewWidth = w*viewHeight / (aspectRatio * h);
        }
        else
        {
            viewWidth = 2.0f;
            viewHeight = h*viewWidth / (1/aspectRatio * w);
        }
    }

    mProj.ortho(-viewWidth/2,viewWidth/2,-viewHeight/2,viewHeight/2,-1.f,1.0f);
}

void PlayerWidget::InitShaders()
{
    GLint vertCompiled, fragCompiled, linked;
    GLint v, f;

    //Shader: step1
    v = glCreateShader(GL_VERTEX_SHADER);
    f = glCreateShader(GL_FRAGMENT_SHADER);

    //Shader: step2
    glShaderSource(v, 1, &vertexShader,NULL);
    glShaderSource(f, 1, &fragmentShader,NULL);

    //Shader: step3
    glCompileShader(v);
    glGetShaderiv(v, GL_COMPILE_STATUS, &vertCompiled);    //Debug

    glCompileShader(f);
    glGetShaderiv(f, GL_COMPILE_STATUS, &fragCompiled);    //Debug

    //Program: Step1
    program = glCreateProgram();
    //Program: Step2
    glAttachShader(program,v);
    glAttachShader(program,f);

    glBindAttribLocation(program, ATTRIB_VERTEX, "vertexIn");
    glBindAttribLocation(program, ATTRIB_TEXTURE, "textureIn");
    //Program: Step3
    glLinkProgram(program);
    //Debug
    glGetProgramiv(program, GL_LINK_STATUS, &linked);

    glUseProgram(program);

    //Get Uniform Variables Location
    sampler_y = glGetUniformLocation(program, "tex_y");
    sampler_u = glGetUniformLocation(program, "tex_u");
    sampler_v = glGetUniformLocation(program, "tex_v");

    //Init Texture
    glGenTextures(1, &tex_y);
    glBindTexture(GL_TEXTURE_2D, tex_y);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

    glGenTextures(1, &tex_u);
    glBindTexture(GL_TEXTURE_2D, tex_u);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

    glGenTextures(1, &tex_v);
    glBindTexture(GL_TEXTURE_2D, tex_v);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

    glVertexAttribPointer(ATTRIB_VERTEX,2,GL_FLOAT,0,0,vertexVertices);
    glEnableVertexAttribArray(ATTRIB_VERTEX);

    glVertexAttribPointer(ATTRIB_TEXTURE,2,GL_FLOAT,0,0,textureVertices);
    glEnableVertexAttribArray(ATTRIB_TEXTURE);

    matWorld = glGetUniformLocation(program,"mWorld");
    matView = glGetUniformLocation(program,"mView");
    matProj = glGetUniformLocation(program,"mProj");
} 

标签:tex,1.0,QT,TEXTURE,YUV420,program,2D,GL,绘制
From: https://www.cnblogs.com/livio/p/16984904.html

相关文章

  • 基于Pyqt5和PaddleOCR实现PDF转DOC
    OverridetheentrypointofanimageIntroducedinGitLabandGitLabRunner9.4.Readmoreaboutthe extendedconfigurationoptions.Beforeexplainingtheav......
  • QtableWidget、QlistWidget、QTreeWidget 单行选中,单击选中,再单击取消选中
    1.问题描述,QtableWidget、QlistWidget、QTreeWidget设置单选行模式时,就会一直选中一行,无法取消选中行,恢复全不选的状态;点击空白处,也不会取消选中行;多行选择模式,可以取消选......
  • Qt平台下使用QJson 使用
    前言在Qt开发环境下使用Json的解析和输出当然要使用QJson来完成。QJson解析JSON主要使用的类如下#include<QJsonDocument>#include<QJsonObject>#include<QJsonArray>......
  • qt-信号与槽初步
    接下来,我们将沿着上一篇的进度,学习如何将按钮与退出程序建立连接。建立连接是什么意思呢,我们就拿按钮来解释一下。按钮可以被按下。显然当按钮按下的时候,我们希望程序做出......
  • 使用java 实现mqtt两种方式
    前言在开发MQTT时有两种方式一种是使用PahoJava原生库来完成,一种是使用springboot来完成。PahoJava库实现EclipsePahoJavaClient(opensnewwindow)是用Java编......
  • 7段数码管绘制
    """7段数码管绘制"""importturtle,datetimedefdrawGap():#绘制数码管间隔turtle.penup()turtle.fd(5)defdrawLine(draw):#绘制单段数码管d......
  • QTreewidget树状列表右击事件
     树状列表右击事件(添加删除修改等操作) 思路:首先我们需要一个voidcontextMenuEvent(QContextMenuEvent*event);管理Menu事件的一个接口此接口为系统自带的,不需......
  • 产品分享:Qt鸿图电子智慧白板(适合会议机、电子黑板、电子笔记、电子阅读器等场景),当前版
    产品  鸿途电子智慧白板。 原理  使用Qt技术为基础,开发的windows/ubuntu/arm电子绘图板,主要为windows,支持触摸鼠标,可以定制跨平台。 适合场景  ......
  • 超全!Python图形界面框架PyQt5使用指南!
    使用Python开发图形界面的软件其实并不多,相对于GUI界面,可能Web方式的应用更受人欢迎。但对于像我一样对其他编程语言比如C#或WPF并不熟悉的人来说,未必不是一个好的工具。......
  • Qt-1-信号和槽
    信号和槽的概念什么是信号和槽,就是说通过connect函数将信号和槽函数连接起来,当信号发出的时候回触发槽函数自动执行。QObject::connect(constQObject*sender, const......