OpenCV图像加载OpenGL纹理 [英] OpenCV image loading for OpenGL Texture

查看:447
本文介绍了OpenCV图像加载OpenGL纹理的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想使用OpenCV作为OpenGL纹理加载图片(jpg和png)。



这是我如何将图片加载到OpenGL:

  glEnable(GL_TEXTURE_2D); 
textureData = loadTextureData(textures / trashbin.png);
cv :: Mat image = cv :: imread(textures / trashbin.png);
if(image.empty()){
std :: cout<< 图像空< 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);
}

图像被加载,因为image.empty总是返回false

下面是使用创建的纹理渲染场景的方法:

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

最后是fragmentShader,我想将纹理应用到我的几何

  #version 330 
in vec2 tCoord;

//纹理//
// TODO:设置纹理统一//
uniform sampler2D纹理;

//定义片段输出//
out vec4 color;

void main(){
// TODO:从纹理中获取纹理坐标位置的texel值//
color = texture2D(texture,tCoord) ;
}

纹理坐标来自顶点缓冲区对象, .obj文件。此外,我可以看到我的场景中的对象,当我将颜色设置为红色在片段着色器,或vec4(tCoord,0,1);



不幸的是,当我想应用纹理时,屏幕保持黑色...有人可以帮助我,告诉我为什么是黑色?

解决方案

从只查看你的纹理加载代码,你忽略了许多关于OpenCV如何在内存中布局图像的注意事项。我已经在中解释了相反的方向( glGetTexImage into OpenCV image)这个回答,但将在这里重述CV-GL方向:



首先OpenCV不必要存储图像行紧密包装,但可能会对齐他们到某些字节边界(不知道多少,至少4,但也许8或更多?)。如果你幸运,它将使用4字节对齐,GL被设置为4字节对齐的默认像素存储模式。但是最好手动解决像素存储模式,以安全的方式:

  //使用快速4-字节对齐(如果可能,默认)
glPixelStorei(GL_UNPACK_ALIGNMENT,(image.step& 3)?1:4);

//设置数据中一个完整行的长度(不需要等于image.cols)
glPixelStorei(GL_UNPACK_ROW_LENGTH,image.step / image.elemSize());

然后你必须考虑OpenCV从上到下存储图像的事实,底部到顶部。这可以通过恰当地镜像t纹理坐标(可能直接在着色器中)来处理,但是您也可以在上传之前翻转图像:

  cv :: flip(image,flipped,0); 
image = flipped; //也许只是cv :: flip(image,image,0)?

最后但并非最不重要的一点OpenCV以BGR格式存储彩色图像,因此上传为RGB会扭曲颜色。所以在 glTexImage2D 中使用 GL_BGR (需要OpenGL 1.2,但谁没有?

这些可能不是你的问题的完整解决方案(因为我认为这些错误应该导致扭曲,而不是一个黑色的图像),但他们肯定是照顾的问题。



编辑:您的片段着色器是否真正成功编译(在使用纹理的完整版本中)?我问,因为在GLSL 3.30你使用的词纹理也是一个内置函数的名称(实际应该使用,而不是过时的 texture2D 函数),所以也许编译器有一些名称解析问题(也许这个错误被忽略在简化的着色器,考虑到整个统一将被优化,许多GLSL编译器是已知的是严格遵守标准的任何东西)。所以只是试着给采样器制服一个不同的名字。


I want to load an image (jpg and png) with OpenCV as OpenGL Texture.

Here is how I load the image to 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

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

#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. Also I can see the Object in my scene when I set the color to e.g. red in the fragment shader, or to 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. 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:

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?). 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. 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. 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:

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. So use GL_BGR (requires OpenGL 1.2, but who doesn't have that?) in glTexImage2D.

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). So just try to give that sampler uniform a different name.

这篇关于OpenCV图像加载OpenGL纹理的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆