7

openGL を使用して画像処理を行います。最初の実験は、カラー画像をグレーに変換することです。ウィジェットを表示したくないことを除いて、すべて問題ありません。

「show()」を呼び出さないと、QGLWidget はテクスチャのレンダリングを開始しません。ウィジェットを表示せずにテクスチャをレンダリングできますか? QGLWidget はそれを行うための適切なツールですか?

コードの一部

#include <QDebug>

#include "toGray.hpp"

toGray::toGray(std::string const &vertex_file, std::string const &fragment_file, QWidget *parent)
    :basicGLWidget(vertex_file, fragment_file, parent) //read shaders, compile them, allocate VBO
{
}

void toGray::initializeVertexBuffer()
{
    std::vector<GLfloat> const vertex{
        -1.0f,  1.0f, 0.0f, 1.0f,
        1.0f,  1.0f, 0.0f, 1.0f,
        -1.0f, -1.0f, 0.0f, 1.0f,
        1.0f, 1.0f, 0.0f, 1.0f,
        1.0f, -1.0f, 0.0f, 1.0f,
        -1.0f, -1.0f, 0.0f, 1.0f,
    };

    initializeVertexBufferImpl(vertex); //copy the data into QOpenGLBuffer

    QImage img(":/simpleGPGPU/images/emili.jpg");
    texture_addr_ = bindTexture(img);
    resize(img.width(), img.height());

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_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);
}

void toGray::paintGL()
{
    qglClearColor(Qt::white);
    glClear(GL_COLOR_BUFFER_BIT);

    program_.bind();
    bind_buffer();
    program_.enableAttributeArray("qt_Vertex");
    program_.setAttributeBuffer( "qt_Vertex", GL_FLOAT, 0, 4);

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

    glDrawArrays(GL_TRIANGLES, 0, get_buffer(0).size());

    program_.disableAttributeArray("qt_Vertex");
    program_.release();
    glActiveTexture(0);
    release_buffer();
}

頂点シェーダー

attribute highp vec4 qt_Vertex;
varying highp vec2 qt_TexCoord0;

void main(void)
{    
    gl_Position =  qt_Vertex;
    qt_TexCoord0 = (qt_Vertex.xy + vec2(1.0)) * 0.5;
}

フラグメントシェーダー

uniform sampler2D source;
varying highp vec2 qt_TexCoord0;

vec3 toGray(vec3 rgb)
{
    return vec3(rgb.r * 0.299 + rgb.g * 0.587 + rgb.b * 0.114);
}

void main(void)
{        
    vec3 gray = toGray(texture2D(source, qt_TexCoord0).rgb);
    gl_FragColor = vec4(gray, 0.0);
}

編集:QWindow FBOを使用してオフスクリーンレンダリングを行いますが、結果は空白の画像です

コードはコンパイルできますが、QOpenGLFrameBufferObject によって返される QImage は空です。

.hpp

#ifndef OFFSCREENEXP_HPP
#define OFFSCREENEXP_HPP

#include <QOpenGLFunctions>
#include <QWindow>

class QImage;
class QOpenGLContext;

class offScreenExp : public QWindow, protected QOpenGLFunctions
{
public:
    explicit offScreenExp(QWindow *parent = 0);

    QImage render();

private:
    QOpenGLContext *context_;
};

#endif // OFFSCREENEXP_HPP

.cpp

#include <QImage>
#include <QOpenGLBuffer>
#include <QOpenGLContext>
#include <QOpenGLFramebufferObject>
#include <QOpenGLShaderProgram>
#include <QString>
#include <QWidget>

#include <QDebug>

#include "offScreenExp.hpp"

offScreenExp::offScreenExp(QWindow *parent) :
    QWindow(parent),
    context_(nullptr)
{
    setSurfaceType(QWindow::OpenGLSurface);
    setFormat(QSurfaceFormat());
    create();
}

QImage offScreenExp::render()
{
    //create the context
    if (!context_) {
        context_ = new QOpenGLContext(this);
        QSurfaceFormat format;
        context_->setFormat(format);

        if (!context_->create())
            qFatal("Cannot create the requested OpenGL context!");
    }

    context_->makeCurrent(this);
    initializeOpenGLFunctions();

    //load image and create fbo
    QString const prefix("/Users/Qt/program/experiment_apps_and_libs/openGLTest/simpleGPGPU/");
    QImage img(prefix + "images/emili.jpg");
    if(img.isNull()){
      qFatal("image is null");
    }
    QOpenGLFramebufferObject fbo(img.size());
    qDebug()<<"bind success? : "<<fbo.bind();

    //if(glCheckFramebufferStatus(fbo.handle()) != GL_FRAMEBUFFER_COMPLETE){
    //    qDebug()<<"frame buffer error";
    //}
    qDebug()<<"has opengl fbo : "<<QOpenGLFramebufferObject::hasOpenGLFramebufferObjects();

    //use two triangles two cover whole screen
    std::vector<GLfloat> const vertex{
        -1.0f,  1.0f, 0.0f, 1.0f,
        1.0f,  1.0f, 0.0f, 1.0f,
        -1.0f, -1.0f, 0.0f, 1.0f,
        1.0f, 1.0f, 0.0f, 1.0f,
        1.0f, -1.0f, 0.0f, 1.0f,
        -1.0f, -1.0f, 0.0f, 1.0f,
    };

    //initialize vbo
    QOpenGLBuffer buffer(QOpenGLBuffer::VertexBuffer);
    buffer.create();
    buffer.setUsagePattern(QOpenGLBuffer::StaticDraw);
    buffer.bind();
    buffer.allocate(&vertex[0], vertex.size() * sizeof(GLfloat) );
    buffer.release();

    //create texture
    GLuint rendered_texture;
    glGenTextures(1, &rendered_texture);

    // "Bind" the newly created texture : all future texture functions will modify this texture
    glBindTexture(GL_TEXTURE_2D, rendered_texture);

    //naive solution, better encapsulate the format in a function
    if(img.format() == QImage::Format_Indexed8){
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, img.width(), img.height(), 0, GL_RED, GL_UNSIGNED_BYTE, img.scanLine(0));
    }else if(img.format() == QImage::Format_RGB888){
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, img.width(), img.height(), 0, GL_RGB, GL_UNSIGNED_BYTE, img.scanLine(0));
    }else{
        QImage temp = img.convertToFormat(QImage::Format_RGB888);
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, img.width(), img.height(), 0, GL_RGB, GL_UNSIGNED_BYTE, temp.scanLine(0));
    }

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_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);

    glBindTexture(GL_TEXTURE_2D, 0);

    //compile and link program
    QOpenGLShaderProgram program;
    if(!program.addShaderFromSourceCode(QOpenGLShader::Vertex,
                                        "attribute highp vec4 qt_Vertex;"
                                        "varying highp vec2 qt_TexCoord0;"

                                        "void main(void)"
                                        "{"
                                        "   gl_Position =  qt_Vertex;"
                                        "   qt_TexCoord0 = (qt_Vertex.xy + vec2(1.0)) * 0.5;"
                                        "}")){
        qDebug()<<"QOpenGLShader::Vertex error : " + program.log();
    }

    // Compile fragment shader
    if (!program.addShaderFromSourceCode(QOpenGLShader::Fragment,
                                         "uniform sampler2D source;"
                                         "varying highp vec2 qt_TexCoord0;"

                                         "vec3 toGray(vec3 rgb)"
                                         "{"
                                         " return vec3(rgb.r * 0.299 + rgb.g * 0.587 + rgb.b * 0.114);"
                                         "}"

                                         "void main(void)"
                                         "{"
                                         "vec3 gray = toGray(texture2D(source, qt_TexCoord0).rgb);"
                                         "gl_FragColor = vec4(gray, 0.0);"
                                         "}"
                                         )){
        qDebug()<<"QOpenGLShader::Fragment error : " + program.log();
    }

    // Link shader pipeline
    if (!program.link()){
        qDebug()<<"link error : " + program.log();
    }

    //render the texture as usual
    //render the texture as usual
glClearColor(0, 0, 0, 1);
glClear(GL_COLOR_BUFFER_BIT);
glViewport(0, 0, img.width(), img.height());

program.bind();
buffer.bind();
program.enableAttributeArray("qt_Vertex");
program.setAttributeBuffer( "qt_Vertex", GL_FLOAT, 0, 4);

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

//bind and create fbo
QOpenGLFramebufferObject fbo(img.size());
qDebug()<<"bind success? : "<<fbo.bind();

glDrawArrays(GL_TRIANGLES, 0, buffer.size());
QImage result = fbo.toImage();

program.disableAttributeArray("qt_Vertex");
program.release();    
buffer.release();

fbo.release();
glActiveTexture(0);
glBindTexture(GL_TEXTURE_2D, 0);
context_->doneCurrent();

    return result;
}

コードを簡略化するために最善を尽くしていますが、それでもかなり冗長です

4

1 に答える 1

10

オフスクリーン レンダリングの場合は、 QOpenGLFramebufferObjectにレンダリングしてみてください。これは に変換QImageでき、ディスクに簡単に保存できます。

ただし、そのためには、( で必要な場合にQOpenGLContext::makeCurrent()) レンダリングするサーフェスが必要なため、そのようなサーフェスを取得するために実際に aQWindowまたは aを使用する以外に選択肢はありQGLWidgetません。

Qt 5.1 では、 QOffscreenSurfaceと呼ばれる新しいクラスが追加されます。これは、おそらくユースケースに最も適しています。を使用してOpenGL コンテキストQOffscreenSurfaceのサーフェスを取得し、を使用して FBO にレンダリングし、を呼び出してピクセルにアクセスします。QOpenGLFramebufferObjectQOpenGLFramebufferObject::toImage()

于 2013-06-20T19:53:05.120 に答える