1 OpenCV的cv::Mat转换OpenGLGL_TEXTURE_2D纹理数据

在有些场景下我们需要将OpenCV处理之后的cv::Mat转为OpenGL的GL_TEXTURE_2D类型的纹理数据,比如说使用OpenCV读取图片文件作为OpenGL的纹理使用。

https://gist.github.com/zhangzhensong/03f67947c22acb5ee922我找到了如下的代码:

// don't forget to include related head files
void BindCVMat2GLTexture(cv::Mat& image, GLuint& imageTexture)
{
   if(image.empty()){
      std::cout << "image empty" << std::endl;
  }else{
      //glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
      glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
      glGenTextures(1, &imageTexture1);
      glBindTexture(GL_TEXTURE_2D, imageTexture1);

      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
    }
} 

然后我又在Spout2仓库中SpoutGL类中找到了相关代码,然后进行了改进和结合,封装了如下的工具函数

GLuint ConvertCVMatToGLTexture(const cv::Mat& image)
{
    // 图片判空
    if (image.empty()) 
    {
        std::cout << "image empty" << std::endl;
        return;
    }

    // 图片深拷贝
    cv::Mat image_copy;
    image.copyTo(image_copy);

    int image_height = image_copy.rows;
    int image_width = image_copy.cols;

    // cv::Mat转换为GL_TEXTURE_2D
    unsigned int texture_id;
    glGenTextures(1, &texture_id);

    GLint texturebinding;
    glGetIntegerv(GL_TEXTURE_BINDING_2D, &texturebinding);

    glBindTexture(GL_TEXTURE_2D, texture_id);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, image_width, image_height, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

    glBindTexture(GL_TEXTURE_2D, texturebinding);

    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
    glBindTexture(GL_TEXTURE_2D, texture_id);
    // 第一种
    glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, image_width, image_height, GL_RGB, GL_UNSIGNED_BYTE, image_copy.data);

    // 第二种
    //glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, image_width, image_height, 0, GL_RGB, GL_UNSIGNED_BYTE, image_copy.data);
    glBindTexture(GL_TEXTURE_2D, 0);
    glPixelStorei(GL_UNPACK_ALIGNMENT, 4);

    return texture_id;
}

上述函数形参是cv::Mat,然后函数返回值为GL_TEXTURE_2D的纹理id。

测试代码如下:

#include <iostream>

#include "opencv2/opencv.hpp"
#include <GL\GL.h>

GLuint ConvertCVMatToGLTexture(const cv::Mat& image)
{
    // 图片判空
    if (image.empty())
    {
        std::cout << "image empty" << std::endl;
        return;
    }

    // 图片深拷贝
    cv::Mat image_copy;
    image.copyTo(image_copy);

    int image_height = image_copy.rows;
    int image_width = image_copy.cols;

    // cv::Mat转换为GL_TEXTURE_2D
    unsigned int texture_id;
    glGenTextures(1, &texture_id);

    GLint texturebinding;
    glGetIntegerv(GL_TEXTURE_BINDING_2D, &texturebinding);

    glBindTexture(GL_TEXTURE_2D, texture_id);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, image_width, image_height, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

    glBindTexture(GL_TEXTURE_2D, texturebinding);

    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
    glBindTexture(GL_TEXTURE_2D, texture_id);
    // 第一种
    glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, image_width, image_height, GL_RGB, GL_UNSIGNED_BYTE, image_copy.data);

    // 第二种
    //glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, image_width, image_height, 0, GL_RGB, GL_UNSIGNED_BYTE, image_copy.data);
    glBindTexture(GL_TEXTURE_2D, 0);
    glPixelStorei(GL_UNPACK_ALIGNMENT, 4);

    return texture_id;
}

int main()
{
    std::string image_path = "../../resource/final.png";
    cv::Mat image = cv::imread(image_path);

    GLuint texture_id = ConvertCVMatToGLTexture(image);


    return 0;
}

参考链接

https://gist.github.com/zhangzhensong/03f67947c22acb5ee922