我有一个要用OpenGL渲染的OpenCV垫。因此,我尝试通过在网上找到的代码将openCV垫加载为纹理并将其渲染为该纹理:
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垫:
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的初学者,现在我自己找不到任何解决方案。有什么想法我做错了吗?
答案 0 :(得分: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会使颜色失真。因此,请在GL_BGR
中使用glTexImage2D
。
答案 1 :(得分:1)
所以我解决了我的问题,应该添加更多我在本教程中完全忽略的VertexBufferObject,以发布更轻松的答案。同样,这非常重要,我同时使用SFML lib来显示我的框架。 SFML还内部使用OpenGL。因此,我需要保存和恢复相互干扰的OpenGL状态。
如果有人遇到类似问题,我会删除此链接: using-opengl-together-with-the-graphics-module
在我使用SFML以及缺少的VAO代码和Draw()方法使其工作后重置OpenGL绑定之前,此添加的状态保存/恢复。这可能不是性能最高的解决方案,但就目前而言,这是一种实现我所需要的方法。