简体   繁体   English

OpenGL纹理的OpenCV图像加载

[英]OpenCV image loading for OpenGL Texture

I want to load an image (jpg and png) with OpenCV as OpenGL Texture. 我想用OpenCV加载图像(jpg和png)作为OpenGL纹理。

Here is how I load the image to OpenGL: 这是我如何将图像加载到OpenGL:

glEnable(GL_TEXTURE_2D);
  textureData = loadTextureData("textures/trashbin.png");
  cv::Mat image = cv::imread("textures/trashbin.png");
  if(image.empty()){
      std::cout << "image empty" << std::endl;
  }else{
      glGenTextures( 1, &textureTrash );
      glBindTexture( GL_TEXTURE_2D, textureTrash );
      glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
      glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
      glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S , GL_REPEAT );
      glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );
      glTexImage2D(GL_TEXTURE_2D,0,3,image.cols, image.rows,0,GL_RGB,GL_UNSIGNED_BYTE, image.data);
  }

The image is loaded, as "image.empty" always returns false 加载图像,因为“image.empty”始终返回false

Here is how I render the scene using the created texture: 以下是使用创建的纹理渲染场景的方法:

  glActiveTexture(GL_TEXTURE0);
  glBindTexture(GL_TEXTURE_2D, textureTrash);
  glm_ModelViewMatrix.top() = glm::translate(glm_ModelViewMatrix.top(),0.0f,-13.0f,-10.0f);
  glUniformMatrix4fv(uniformLocations["modelview"], 1, false, glm::value_ptr(glm_ModelViewMatrix.top()));

  std::cout << "textureShaderID: " << glGetUniformLocation(shaderProgram,"texture") << std::endl;

  glUniform1i(glGetUniformLocation(shaderProgram,"texture"), 0);
  objLoader->getMeshObj("trashbin")->render();

And finally the fragmentShader where I want to apply the texture to my geometry 最后我想将纹理应用到几何体中的fragmentShader

#version 330
in vec2 tCoord;

// texture //
// TODO: set up a texture uniform //
uniform sampler2D texture;

// this defines the fragment output //
out vec4 color;

void main() {
  // TODO: get the texel value from your texture at the position of the passed texture coordinate //
  color = texture2D(texture, tCoord);
}

The texture coordinates are comeing from a Vertex Buffer Object and are correctly set from the .obj file. 纹理坐标来自顶点缓冲区对象,并从.obj文件中正确设置。 Also I can see the Object in my scene when I set the color to eg red in the fragment shader, or to vec4(tCoord,0,1); 当我在片段着色器中将颜色设置为红色或vec4(tCoord,0,1)时,我也能看到场景中的对象; then the object is shaded in different color. 然后对象以不同的颜色着色。

Unfortunately the screen stays black when I want to apply the texture... Can someone help me and tell me why is stays black? 不幸的是,当我想要应用纹理时,屏幕保持黑色......有人可以帮助我并告诉我为什么保持黑色?

From only looking at your texture loading code you are ignoring many considerations about how OpenCV lays out images in memory. 从仅查看纹理加载代码开始,您忽略了许多关于OpenCV如何在内存中布局图像的注意事项。 I've already explained that for the opposite direction ( glGetTexImage into OpenCV image) in this answer , but will recapitulate it here for the CV-GL direction: 我已经在这个答案中解释了相反的方向( glGetTexImage进入OpenCV图像),但是在这里将它概括为CV-GL方向:

First of all OpenCV doesn't neccessarily store image rows tightly packed but might align them to certain byte boundaries (don't know how much, at least 4, but maybe 8 or more?). 首先,OpenCV不一定存储紧密打包的图像行,但可能将它们与某些字节边界对齐(不知道多少,至少4,但可能是8或更多?)。 If you're lucky it will use 4-byte alignment and the GL is set to the default pixel storage mode of 4-byte alignment, too. 如果你很幸运,它将使用4字节对齐,GL也设置为4字节对齐的默认像素存储模式。 But it's best to manually fiddle with the pixel storage modes in order to be on the safe side: 但为了安全起见,最好手动摆弄像素存储模式:

//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());

Then you have to account for the fact that OpenCV stores images from top to bottom, while the GL uses bottom to top. 然后你必须考虑到OpenCV从上到下存储图像的事实,而GL使用从下到上。 This could be taken care of by just mirroring the t-texture coordinate appropriately (maybe directly in the shader), but you could also just flip the image before uploading: 这可以通过恰当地镜像t纹理坐标(可能直接在着色器中)来处理,但您也可以在上传之前翻转图像:

cv::flip(image, flipped, 0);
image = flipped;              //maybe just cv::flip(image, image, 0)?

Last but not least OpenCV stores color images in BGR format so uploading it as RGB would distort the colors. 最后但并非最不重要的是,OpenCV以BGR格式存储彩色图像,因此将其上传为RGB会使颜色失真。 So use GL_BGR (requires OpenGL 1.2, but who doesn't have that?) in glTexImage2D . 那么在glTexImage2D使用GL_BGR (需要OpenGL 1.2,但谁没有?)。

These might not be the complete solution to your problem (since I think those errors should rather result in a distorted rather than a black image), but they are definitely problems to take care of. 这些可能不是你问题的完整解决方案(因为我认为这些错误应该导致扭曲而不是黑色图像),但它们肯定是需要处理的问题。

EDIT: Does your fragment shader actually compile successfully (in the complete version using the texture)? 编辑:您的片段着色器是否实际编译成功(在使用纹理的完整版本中)? I'm asking because in the GLSL 3.30 you're using the word texture is also the name of a builtin function (which should actually be used instead of the deprecated texture2D function), so maybe the compiler has some name resolution problems (and maybe this error is ignored in your simplified shaders, given that the whole uniform will be optimized away and many GLSL compilers are known to be anything else than strictly standard compliant). 我问,因为在GLSL 3.30中你使用的是texture这个词也是内置函数的名称(实际应该使用它而不是不推荐使用的texture2D函数),所以编译器可能有一些名称解析问题(也许在您的简化着色器中忽略此错误,因为整个制服将被优化掉,并且已知许多GLSL编译器不是严格标准兼容的其他内容。 So just try to give that sampler uniform a different name. 所以试着给那个采样器统一一个不同的名字。

Okay here is my working solution - based on the ideas of "Christan Rau" - Thanks for that! 好的,这是我的工作解决方案 - 基于“Christan Rau”的想法 - 感谢您的支持!

cv::Mat image = cv::imread("textures/trashbin.png");
  //cv::Mat flipped;
  //cv::flip(image, flipped, 0);
  //image = flipped;
  if(image.empty()){
      std::cout << "image empty" << std::endl;
  }else{
      cv::flip(image, image, 0);
      glGenTextures(1, &textureTrash);
      glBindTexture(GL_TEXTURE_2D, textureTrash);

      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);


      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_BGR, // 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

      glGenerateMipmap(GL_TEXTURE_2D);
  }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM