2013-05-29 152 views
8

我想加載OpenCV的圖像(JPG和PNG)作爲OpenGL紋理。OpenCV圖像加載OpenGL紋理

這是我如何加載圖像到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」總是返回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; 

// 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如何在內存中繪製圖像的注意事項。我已經解釋說,在this answer相反的方向(glGetTexImage到OpenCV的圖像),但這裏將它概括爲CV-GL方向:

首先OpenCV中的不neccessarily店面形象行排列緊密,但可能將它們與特定的字節邊界對齊(不知道有多少,至少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採用底部最佳。這可以通過只鏡像T-紋理座標適當地(也許直接在着色器)被照顧,但你也可以只上傳之前翻轉圖像:

cv::flip(image, flipped, 0); 
image = flipped;    //maybe just cv::flip(image, image, 0)? 

最後但並非最不重要的OpenCV商店彩色圖像BGR格式,因此將其上傳爲RGB會扭曲顏色。因此,使用GL_BGR(需要OpenGL 1.2,但誰沒有呢?)在glTexImage2D

這可能不是你的問題的完整解決方案(因爲我認爲這些錯誤而應導致一個扭曲的,而不是一個黑色圖像),但他們肯定是問題的照顧。

編輯:您的片段着色器是否實際編譯成功(使用紋理的完整版本)?我這麼問是因爲在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

那麼這樣工作嗎?順便說一句,你爲什麼改變濾波器和鉗位模式?爲什麼在不使用mipmapping過濾器的情況下生成mipmap? –

+0

是的,它是以這種方式工作 - 當然不是最好的解決方案,並且有很大的改進潛力 - 但它工作正常 - 而且mipmap將作爲下一個功能實現,我忘記刪除行 – glethien

+0

我正在使用你的方法來顯示圖像,但我得到了使用image.ptr()的讀訪問衝突。請參閱我的帖子在這裏:https://stackoverflow.com/questions/45013214/qt-signal-slot-cvmat-unable-to-read-memory-access-violation#45014271 – Pete