2013-05-29 38 views
8

Tôi muốn tải hình ảnh (jpg và png) bằng OpenCV dưới dạng OpenGL Texture.Tải hình ảnh OpenCV cho OpenGL Texture

Dưới đây là cách tôi tải hình ảnh để 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); 
    } 

Những hình ảnh được tải, như "image.empty" luôn luôn trả về false

Dưới đây là cách tôi làm cho cảnh bằng cách sử dụng kết cấu tạo :

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

Và cuối cùng là fragmentShader nơi tôi muốn áp dụng kết cấu hình học của tôi

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

Tọa độ kết cấu đến từ đối tượng đệm Vertex và được đặt chính xác từ tệp .obj. Ngoài ra tôi có thể thấy Object trong cảnh của mình khi tôi đặt màu thành ví dụ. màu đỏ trong bộ đổ bóng, hoặc vec4 (tCoord, 0,1); sau đó đối tượng được tô bóng màu khác nhau.

Thật không may màn hình vẫn đen khi tôi muốn áp dụng các kết cấu ... Ai đó có thể giúp tôi và cho tôi biết lý do tại sao vẫn là màu đen?

Trả lời

16

Từ chỉ xem mã tải kết cấu của bạn, bạn bỏ qua nhiều cân nhắc về cách OpenCV đưa hình ảnh vào bộ nhớ. Tôi đã giải thích rằng đối với hướng ngược lại (glGetTexImage vào hình ảnh OpenCV) trong this answer, nhưng sẽ tóm tắt nó ở đây theo hướng CV-GL:

Trước hết OpenCV không cần lưu trữ các hàng hình ảnh được đóng gói chặt chẽ nhưng có thể sắp xếp chúng vào các ranh giới byte nhất định (không biết bao nhiêu, ít nhất là 4, nhưng có thể là 8 hoặc nhiều hơn?). Nếu bạn may mắn, nó sẽ sử dụng liên kết 4 byte và GL được đặt ở chế độ lưu trữ pixel mặc định của căn chỉnh 4 byte. Nhưng tốt nhất là bằng tay fiddle với các phương thức lưu trữ điểm ảnh để được ở bên an toàn:

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

Sau đó, bạn phải giải thích cho thực tế là các cửa hàng OpenCV hình ảnh từ trên xuống dưới, trong khi GL sử dụng dưới lên hàng đầu. Điều này có thể được đưa về chăm sóc bằng cách chỉ phản ánh t-kết cấu phối hợp một cách thích hợp (có thể trực tiếp trong shader), nhưng bạn cũng có thể chỉ cần lật hình ảnh trước khi tải lên:

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

Cuối cùng nhưng không phải hình ảnh cửa hàng OpenCV màu ít nhất là trong Định dạng BGR để tải lên vì RGB sẽ làm méo mó màu. Vì vậy, sử dụng GL_BGR (yêu cầu OpenGL 1.2, nhưng những người không có điều đó?) Trong glTexImage2D.

Đây có thể không phải là giải pháp hoàn chỉnh cho vấn đề của bạn (vì tôi nghĩ rằng những lỗi đó sẽ dẫn đến méo thay vì hình ảnh màu đen), nhưng chúng chắc chắn là vấn đề cần quan tâm.

EDIT: Trình đổ bóng phân đoạn của bạn có thực sự biên dịch thành công (trong phiên bản hoàn chỉnh bằng cách sử dụng kết cấu) không? Tôi hỏi vì trong GLSL 3.30 bạn đang sử dụng từ texture cũng là tên của hàm dựng sẵn (nên thực sự được sử dụng thay vì hàm deprecated texture2D), vì vậy có thể trình biên dịch có một số vấn đề về độ phân giải tên (và có thể lỗi này được bỏ qua trong các trình đổ bóng đơn giản của bạn, vì toàn bộ đồng phục sẽ được tối ưu hóa và nhiều trình biên dịch GLSL được biết là khác hơn là tuân thủ nghiêm ngặt tiêu chuẩn). Vì vậy, chỉ cần cố gắng cung cấp cho bộ đồng phục mẫu đó một tên khác.

8

Được rồi đây là giải pháp làm việc của tôi - dựa trên ý tưởng của "Christan Rau" - Cảm ơn vì điều đó!

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

Vậy nó hoạt động theo cách này? Nhân tiện, tại sao bạn thay đổi chế độ lọc và kẹp? Và tại sao bạn tạo mipmaps trong khi không sử dụng bộ lọc mipmapping? –

+0

Vâng nó đang hoạt động theo cách này - Chắc chắn không phải là giải pháp tốt nhất và có nhiều tiềm năng để cải thiện - Nhưng nó đang hoạt động - Và mipmaps sẽ được thực hiện như tính năng tiếp theo, tôi vừa quên xóa dòng – glethien

+0

Tôi đang sử dụng phương pháp của bạn để hiển thị hình ảnh, nhưng tôi nhận được một sự vi phạm truy cập đọc cho việc sử dụng image.ptr(). Vui lòng xem bài đăng của tôi tại đây: https://stackoverflow.com/questions/45013214/qt-signal-slot-cvmat-unable-to-read-memory-access-violation#45014271 – Pete