2013-05-29 7 views
8

Voglio caricare un'immagine (jpg e png) con OpenCV come Texture OpenGL.Caricamento immagine OpenCV per Texture OpenGL

Ecco come si carica l'immagine 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); 
    } 

L'immagine viene caricata, come "image.empty" restituisce sempre false

Ecco come io rendo la scena utilizzando la texture creata :

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(); 

E infine il fragmentShader dove voglio applicare la texture alla mia geometria

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

Le coordinate della trama provengono da un oggetto buffer Vertex e sono impostate correttamente dal file obj. Inoltre posso vedere l'oggetto nella mia scena quando imposto il colore ad es. rosso nello shader del frammento, o in vec4 (tCoord, 0,1); quindi l'oggetto è ombreggiato in diversi colori.

Sfortunatamente lo schermo rimane nero quando voglio applicare la trama ... Qualcuno può aiutarmi e dirmi perché rimane nero?

risposta

16

Solo guardando il tuo codice di caricamento della trama stai ignorando molte considerazioni su come OpenCV disponga le immagini in memoria. Ho già spiegato che per la direzione opposta (glGetTexImage immagine OpenCV in) in this answer, ma sarà ricapitolare qui per la direzione CV-GL:

Prima di tutto OpenCV non memorizza i file immagine neccessarily strettamente imballati, ma potrebbe allinearli a determinati limiti di byte (non so quanto, almeno 4, ma forse 8 o più?). Se sei fortunato userà l'allineamento a 4-byte e GL è impostato sulla modalità di memorizzazione dei pixel di default dell'allineamento a 4-byte. Ma è meglio perdere tempo manualmente con le modalità di memorizzazione dei pixel in modo da essere al sicuro:

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

poi si deve tenere conto del fatto che memorizza OpenCV immagini dall'alto verso il basso, mentre la GL utilizza basso verso superiore. Questo potrebbe essere curato da solo rispecchia la t-struttura coordinata in modo appropriato (forse direttamente nello shader), ma si potrebbe anche semplicemente capovolgere l'immagine prima di caricare:

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

ultimo ma non meno immagini negozi OpenCV a colori in Formato BGR quindi caricarlo come RGB distorce i colori. Quindi utilizzare GL_BGR (richiede OpenGL 1.2, ma chi non ha questo?) In glTexImage2D.

Queste potrebbero non essere la soluzione completa al tuo problema (dal momento che penso che quegli errori dovrebbero piuttosto risultare in un'immagine distorta piuttosto che in nero), ma sono sicuramente problemi da risolvere.

MODIFICA: Il frammento di shader viene compilato correttamente (nella versione completa utilizzando la trama)? Ti sto chiedendo perché nel GLSL 3.30 stai usando la parola texture è anche il nome di una funzione incorporata (che dovrebbe essere effettivamente utilizzata al posto della deprecata funzione texture2D), quindi forse il compilatore ha qualche problema di risoluzione dei nomi (e forse questo errore viene ignorato nei vostri shader semplificati, dato che l'intera divisa verrà ottimizzata e molti compilatori GLSL sono nient'altro che rigorosamente conformi allo standard). Quindi prova a dare a quel campionatore un nome diverso.

8

Ok, ecco la mia soluzione di lavoro, basata sulle idee di "Christan Rau" - Grazie per questo!

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

Quindi funziona in questo modo? A proposito, perché hai cambiato il filtro e le modalità di bloccaggio? E perché generi mipmap mentre non usi un filtro mipmapping? –

+0

Sì, sta funzionando in questo modo - Sicuramente non è la soluzione migliore e ha molte potenzialità per migliorare - Ma sta funzionando - E mipmaps sarà implementato come funzione successiva, ho appena dimenticato di rimuovere la linea – glethien

+0

Sto usando il tuo metodo per mostrare l'immagine, ma sto ricevendo una violazione di accesso in lettura per l'utilizzo di image.ptr(). Si prega di consultare il mio post qui: https://stackoverflow.com/questions/45013214/qt-signal-slot-cvmat-unable-to-read-memory-access-violation#45014271 – Pete