2013-05-29 2 views
8

Я хочу загрузить изображение (jpg и png) с OpenCV в качестве текстуры OpenGL.Загрузка изображения OpenCV для OpenGL Texture

Вот как я загрузить изображение в 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); 
    } 

Изображение загружается, как «image.empty» всегда возвращает ложь

Вот как я сделать сцену, используя созданную текстуру :

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; 

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

Координаты текстуры поступают из объекта буфера вершин и корректно задаются из файла .obj. Также я вижу объект в моей сцене, когда я устанавливаю цвет, например. красный в шейдере фрагмента или vec4 (tCoord, 0,1); то объект затенен в разный цвет.

К сожалению, экран остается черным, когда я хочу применить текстуру ... Может ли кто-нибудь помочь мне и сказать, почему остается черным?

ответ

16

От просмотра только кода загрузки текстуры вы игнорируете многие соображения о том, как OpenCV выводит изображения в память. Я уже объяснил, что для противоположного направления (glGetTexImage в OpenCV изображения) в this answer, но резюмировать его здесь для направления CV-GL:

Прежде всего OpenCV не делает магазин изображения провайдер блокирует строки плотно упакованы, но может выровнять их с определенными границами байтов (не знаете, сколько, по крайней мере 4, но, возможно, 8 или более?). Если вам повезет, он будет использовать 4-байтовое выравнивание, а GL будет установлен в режим хранения пикселей по умолчанию, равный 4-байтовому выравниванию. Но это лучше вручную возиться с режимами хранения пикселей для того, чтобы быть на безопасной стороне:

//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;    //maybe just cv::flip(image, image, 0)? 

И последнее, но не в последнюю очередь OpenCV хранит цветные изображения в BGR, поэтому загрузка его в виде RGB искажала бы цвета. Поэтому используйте GL_BGR (требуется OpenGL 1.2, но у кого этого нет?) В glTexImage2D.

Возможно, это не полное решение вашей проблемы (так как я думаю, что эти ошибки скорее приведут к искажению, а не к черному изображению), но они, безусловно, проблемы, о которых стоит заботиться.

EDIT: Действительно ли ваш шейдер фрагментов успешно скомпилирован (в полной версии с использованием текстуры)? Я спрашиваю, потому что в GLSL 3.30 вы используете слово texture - это также имя встроенной функции (которая фактически должна использоваться вместо устаревшей функции texture2D), поэтому, возможно, у компилятора есть проблемы с разрешением имен (и, возможно, эта ошибка игнорируется в ваших упрощенных шейдерах, учитывая, что вся униформа будет оптимизирована, и многие компиляторы GLSL, как известно, являются чем-то другим, кроме строго стандартного соответствия). Поэтому просто попробуйте дать этому образцу форму другого имени.

8

Хорошо, это мое рабочее решение - основано на идеях «Кристан Рау» - Спасибо за это!

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); 
    } 
+1

Как это работает? Кстати, почему вы изменили режимы фильтра и зажима? И почему вы генерируете mipmaps, не используя фильтр mipmapping? –

+0

Да, он работает таким образом. Конечно, это не лучшее решение и имеет большой потенциал для улучшения. Но он работает. И mipmaps будут реализованы в качестве следующей функции. Я просто забыл удалить строку – glethien

+0

Я использую ваш метод показать изображение, но я получаю нарушение доступа к чтению для использования image.ptr(). Пожалуйста, см. Мой пост здесь: https://stackoverflow.com/questions/45013214/qt-signal-slot-cvmat-unable-to-read-memory-access-violation#45014271 – Pete