【问题标题】:OpenGL render to a OpenCV mat as texture and reuse it in OpenCVOpenGL 渲染到 OpenCV mat 作为纹理并在 OpenCV 中重用它
【发布时间】:2018-11-30 13:29:00
【问题描述】:

我有一个 OpenCV 垫子,我想用 OpenGL 进行渲染。所以我尝试通过我在网上找到的代码将 openCV mat 作为纹理加载并渲染到该纹理:

void BindCVMat2GLTexture(cv::Mat& image, GLuint& imageTexture)
{
    if (image.empty()) {
        std::cout << "image empty" << std::endl;
    }
    else {
        glEnable(GL_TEXTURE_2D);
        glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
        //glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
        glGenTextures(1, &imageTexture);
        glBindTexture(GL_TEXTURE_2D, imageTexture);

        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

        // Set texture clamping method
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);

        cv::cvtColor(image, image, CV_RGB2BGR);

        glTexImage2D(GL_TEXTURE_2D,         // Type of texture
            0,                   // Pyramid level (for mip-mapping) - 0 is the top level
            GL_RGB,              // Internal colour format to convert to
            image.cols,          // Image width  i.e. 640 for Kinect in standard mode
            image.rows,          // Image height i.e. 480 for Kinect in standard mode
            0,                   // Border width in pixels (can either be 1 or 0)
            GL_RGB,              // Input image format (i.e. GL_RGB, GL_RGBA, GL_BGR etc.)
            GL_UNSIGNED_BYTE,    // Image data type
            image.ptr());        // The actual image data itself
            //NULL);
    }
}

然后我创建一个 FBO:

//init the texture
    GLuint imageTexture;
    BindCVMat2GLTexture(target, imageTexture);

    //init the frame buffer
    GLuint fbo = 0;
    glGenFramebuffers(1, &fbo);
    glBindFramebuffer(GL_FRAMEBUFFER, fbo);
    // Set "renderedTexture" as our colour attachement #0
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, imageTexture, 0);

然后我打电话:

glViewport(0, 0, target.cols, target.rows);
MyDraw();

在这个调用之后,我使用另一个我发现的函数将纹理数据复制回 openCV mat:

cv::Mat GetOcvImgFromOglImg(GLuint ogl_texture_id)
{
    glBindTexture(GL_TEXTURE_2D, ogl_texture_id);
    GLenum gl_texture_width, gl_texture_height;

    glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, (GLint*)&gl_texture_width);
    glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, (GLint*)&gl_texture_height);

    unsigned char* gl_texture_bytes = (unsigned char*)malloc(sizeof(unsigned char)*gl_texture_width*gl_texture_height * 3);
    glGetTexImage(GL_TEXTURE_2D, 0 /* mipmap level */, GL_BGR, GL_UNSIGNED_BYTE, gl_texture_bytes);

    return cv::Mat(gl_texture_height, gl_texture_width, CV_8UC3, gl_texture_bytes);
}

并通过以下方式调用它:

target = GetOcvImgFromOglImg(imageTexture);

我还创建了三角形顶点和一个简单地保持它们不变的顶点着色器和一个只显示红色的片段着色器。理论上,我只想要在这个纹理上绘制一个红色三角形作为第一步。但是它不起作用,因为我根本没有得到渲染图像。我是openGL的初学者,现在我自己找不到任何解决方案。任何想法我做错了什么?

【问题讨论】:

    标签: c++ opencv opengl


    【解决方案1】:

    OpenCV 将图像存储为紧密打包的行数据,但可能会将它们对齐到某些字节边界,可能是 4 或 8,但我们不知道如果幸运的话,它将使用 4 字节对齐,这也是 OpenGL 的默认设置。但为了安全起见,最好手动设置像素存储模式:

    // use fast 4-byte alignment (default anyway) if possible glPixelStorei(GL_UNPACK_ALIGNMENT, (image.step & 3) ? 1 : 4);

    //set length of one complete row in data (doesn't need to equal image.cols) glPixelStorei(GL_UNPACK_ROW_LENGTH, image.step/image.elemSize());

    然后您必须考虑 OpenCV 从上到下存储图像,而 GL 使用从下到上的事实。为了照顾这个使用以下

    cv::flip(image, flipped, 0); image = flipped;

    OpenCV 以 BGR 格式存储彩色图像,因此将其上传为 RGB 会扭曲颜色。所以在glTexImage2D中使用GL_BGR

    【讨论】:

    • 实际上这些都没有解决我的特殊情况,但我认为这是因为正如你所说,4字节对齐是默认的。也不需要翻转,正如您在上面的代码中看到的那样,我使用的是 openCV RGB2BGR 转换。所以我可以使用你提出的方法,它在颜色格式方面也是如此。
    【解决方案2】:

    所以我解决了我的问题,我应该发布更多代码以使答案更容易,方法是添加一个我在教程中完全忽略的 VertexBufferObject。这也很重要,我同时使用 SFML lib 来显示我的帧。 SFML 在内部也使用 OpenGL。所以我需要保存和恢复相互干扰的OpenGL状态。

    如果有人遇到类似问题,我会删除此链接: using-opengl-together-with-the-graphics-module

    这在我使用 SFML 之前添加了状态保存/恢复以及丢失的 VAO 代码以及在我的 Draw() 方法使其工作之后重置 OpenGL 绑定。这可能不是最高效的解决方案,但目前它是实现我所需要的一种方式。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多