使用 glTexImage2D 和 glGetTexImage 的一些问题

Posted

技术标签:

【中文标题】使用 glTexImage2D 和 glGetTexImage 的一些问题【英文标题】:Some problems using glTexImage2D and glGetTexImage 【发布时间】:2016-07-26 16:45:56 【问题描述】:

我遇到了一些关于glTexImage2D()glGetTexImage() 的问题。

在我的代码中,我尝试使用 OpenCV 的 imread() 加载图像,将其转换为带有 texture_id 句柄的纹理格式,然后再次将其转换回矩阵类型(OpenCV 的 Mat)。在某处,我的图像数据似乎丢失了,image.data 返回 NULL。

我怀疑问题出在我对matToTexture() 的实现中。

我在 Visual Studio 15 中使用 C++ 编写并使用 OpenCV 3.1 和 OpenGL 4.4。

纹理.cpp:

#include "Texture.h"

Mat textureToMat(GLuint textureID);
GLuint matToTexture(Mat image);

GLuint matToTexture(Mat image) 

    GLuint texture_id;

    if (image.empty()) 
        cout << "Image empty." << endl;
    

    else 

        glGenTextures(1, &texture_id);
        glBindTexture(GL_TEXTURE_2D, texture_id);

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

        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);

        glTexImage2D(GL_TEXTURE_2D,
            0,
            GL_RGB,
            image.cols,
            image.rows,
            0,
            GL_BGR,
            GL_UNSIGNED_BYTE,
            image.ptr());

    

    return texture_id;


Mat textureToMat(GLuint texture_id) 

    glBindTexture(GL_TEXTURE_2D, texture_id);
    GLenum texture_width, texture_height, texture_format;

    glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, (GLint*)&texture_width);
    glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, (GLint*)&texture_height);
    glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_INTERNAL_FORMAT, (GLint*)&texture_format);

    unsigned char* texture_bytes = (unsigned char*)malloc(sizeof(unsigned char)*texture_width*texture_height * 3);

    glGetTexImage(GL_TEXTURE_2D, 0, GL_BGR, GL_UNSIGNED_BYTE, texture_bytes);

    Mat out(texture_height, texture_width, CV_8UC3, texture_bytes);

    free(texture_bytes);

    return out;


还有头文件Texture.h:

#ifndef TEXTURE_H
#define TEXTURE_H

#include "glew.h"
#include "glfw3.h"

#include <string>
#include <iostream>
#include <sstream>
#include <iterator>
#include <vector>
#include <opencv\highgui.h>
#include <opencv\cv.h>
#include <opencv2\opencv.hpp>

using namespace std;
using namespace cv;

Mat textureToMat(GLuint textureID);
GLuint matToTexture(Mat image);

#endif /*!TEXTURE_H*/

还有电话:

#include "Texture.h"

int main()

    glfwInit();
    glewExperimental = GL_TRUE;
    glewInit();

    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 4);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
    glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
    glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);

    GLFWwindow* offscreen_context = glfwCreateWindow(800, 600, "OpenGL", nullptr, nullptr);
    glfwMakeContextCurrent(offscreen_context);

    Mat dummy = imread("mini.jpg", CV_LOAD_IMAGE_COLOR);

    GLuint tex = matToTexture(dummy);

    glBindTexture(GL_TEXTURE_2D, tex);

    Mat some = textureToMat(tex);

    while (!glfwWindowShouldClose(offscreen_context)) 

        glfwSwapBuffers(offscreen_context);
        glfwPollEvents();

        if (glfwGetKey(offscreen_context, GLFW_KEY_ESCAPE) == GLFW_PRESS) 
            glfwSetWindowShouldClose(offscreen_context, GL_TRUE);
        
    

    glfwTerminate();


    

【问题讨论】:

我怀疑free(texture_bytes) 是“NULLness”的来源:D。尝试将其注释掉。 @sarasvati 是正确的,Mat out(texture_height, texture_width, CV_8UC3, texture_bytes) 仅提供数据的浅拷贝,内部 Mat 指向您提供的 texture_bytes,如果您删除内存,它就消失了。你可以用Mat out = Mat(texture_height, texture_width, CV_8UC3, texture_bytes).clone() 来解决这个问题,更好的方法是创建一个大小合适的Mat,然后在Mat 上调用glGetTexImage 以避免复制。 在哪里创建 OpenGL 上下文?如果没有当前的 GL 上下文,这些 GL 纹理操作都不会工作。在minimal reproducible example 中编辑。 啊,我现在已经删除了 free() 操作。此外,我什至没有想到上下文创建。我对 OpenGL 很陌生,所以我今天会尝试阅读这个。谢谢大家:) 我现在更新了帖子以澄清代码 ++。我也尝试在主函数中实现上下文,但很可能我做错了。我仍然得到同样的错误,想法? 【参考方案1】:

您无需创建 OpenGL 上下文。就这么简单。如果没有创建 OpenGL 上下文并在当前线程上处于活动状态,所有 OpenGL 函数调用都是无操作的。

【讨论】:

谢谢!你可能会说我对 OpenGL 很陌生,所以我什至没有想到。我现在正在阅读它。 我试图找到有关为我的使用创建上下文的信息,但我发现很难理解。我已经更新了上面的代码,使其在 .cpp、.h 和调用部分中分开。我应该在哪里说明上下文,以及如何说明?到目前为止,我只找到了为绘图窗口制作上下文的教程,这不是我想要的。 @T.Soemod:(不幸的是)创建 OpenGL 上下文并非易事。这解释了存在几个处理这个问题的应用程序框架(GLUT、GLFW、SMFL、SDL)。 OpenGL 始终专注于实时渲染,并将生成的图像发送到显示器。尽管 OpenGL 本身是窗口系统中立的,但实际创建 OpenGL 上下文所需的 API 与窗口系统(WGL、GLX、NSOpenGLView)相关联。 @T.Soemod:在过去的两年中,出现了许多允许直接设置屏幕外上下文的 API,但创建 OpenGL 上下文的常用方法仍然是通过窗口。步骤是:1.) 创建一个窗口,2.) 配置它的帧缓冲格式,3.) 使用窗口作为要使用的帧缓冲格式的模板创建一个 OpenGL 上下文,4.) 使 OpenGL 上下文在线程上处于活动状态具有与上下文的主帧缓冲区格式兼容的窗口。像 GLUT 或 GLFW 这样的库将这些步骤合并到一个函数调用中。 感谢您澄清一点@datenwolf。我应该在哪里写上下文?它必须在 main() 或其他地方吗?隐藏上下文对我的情况有用吗?

以上是关于使用 glTexImage2D 和 glGetTexImage 的一些问题的主要内容,如果未能解决你的问题,请参考以下文章

在执行 glTexImage2D 和 glTexSubImage2D 之前是不是需要调用 glGenTextures 和 glBindTexture

如何在 glTexImage2D 中使用动态大小的纹理数组?

OpenGL API 之 glTexImage2D

C++ OpenGL glTexImage2D 访问冲突

对符号 glTexImage2D 的未定义引用

glTexImage2D() 函数访问冲突错误