背景:
我原来的工程是使用opencv的,所以程序中的图像都是表示为cv::Mat类型,为了能够在imgui窗口中显示我的cv::Mat的图像,我找到了下面这个函数:
void ImGui::Image(ImTextureID user_texture_id, const ImVec2& size, const ImVec2& uv0, const ImVec2& uv1,const ImVec4& tint_col, const ImVec4& border_col)
上面这个函数负责在imgui中的窗口中显示图像。但是需要先将我的cv::Mat类型的图像转换为这个的ImTextureID类型。可以通过下面这个函数来实现上述功能。
cv::Mat& image为待转换的cv::Mat图像,GLuint& imageTexture就是ImGui::Image()函数中需要的类型。
void Mat2Texture(cv::Mat& image, GLuint& imageTexture) {if (image.empty()) {std::cout << "image is empty! " << std::endl;return;}else {//generate texture using GL commandsglGenTextures(1, &imageTexture);glBindTexture(GL_TEXTURE_2D, imageTexture);glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);glTexImage2D(GL_TEXTURE_2D,0,GL_BGRA,image.cols,image.rows,0,GL_RGBA,GL_UNSIGNED_BYTE,image.data); }}
函数说明:
//用来产生你要操作的纹理对象的索引
//n:用来生成纹理的数量
//texture:用于存储纹理索引
glGenTextures(GLsizei n, GLuint *textures);
//glBindTexture实际上改变了OpenGL的这个状态,他告诉OpenGL下面对纹理的操作都是对他绑定的纹理对象的
//比如下面这里,就是在告诉opengl下面代码中对2D纹理的任何操作都是针对索引imageTexture的纹理的。
glBindTexture(GL_TEXTURE_2D, imageTexture);
注意事项1:
函数glGenTextures(GLsizei n, GLuint *textures);只能放在循环外面使用,否则当程序循环次数多了以后,程序很吃内存,电脑会变得越来越卡,我刚开始没有注意这个问题,将Mat2Texture函数放在了while循环里面,眼看着我的内存占用率直线上升。这是因为Mat2Texture函数中的glGenTextures函数被反复调用。而我需要将视频流数据源源不断的更新到imgui的窗口中,所以我需要循环调用Mat2Texture函数。那么我可以将函数换成下面的形式。
我只需要在窗口初始化的时候,反正就是在while循环的外面先执行一遍:
glGenTextures(1, &imageTexture);
然后把下面的函数放在while循环中就可以了。
void Mat2Texture(cv::Mat& image, GLuint& imageTexture) {if (image.empty()) {std::cout << "image is empty! " << std::endl;return;}else {//generate texture using GL commandsglBindTexture(GL_TEXTURE_2D, imageTexture);glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);glTexImage2D(GL_TEXTURE_2D,0,GL_BGRA,image.cols,image.rows,0,GL_RGBA,GL_UNSIGNED_BYTE,image.data); }}
注意事项2:
在函数Mat2Texture中的glTextImage2D()函数中我使用的是GL_BGRA和GL_RGBA参数,其实我在将调用Mat2Texture函数之前对image图像进行如下操作:
cv::cvtColor(image, image, cv::COLOR_RGB2BGRA);
就是将RGB模式转换为BGRA模式。明显的区别是把之前的三通道图像转换成四通道图像,如果不这样做,有些图像无法正常的呈现在imgui的窗口中,但是有些图像也是可以的。我也试过BGR2BGRA和RGB2RGBA的形式,但是得到的图像颜色不对,所以你在将cv::Mat转换为Texture时,如果遇到这样的问题可以试一下我上面的方法。