2017-04-01 46 views
0

我嘗試使用OPENGL計算圖像的直方圖。我已經閱讀了一些關於這方面的文章,但我仍然有錯誤。我的直方圖緩衝區總是返回零。 一些後,我已閱讀:計算OPENGL中的直方圖

Maknoll Histogram

Luminance histogram calculation in GPU-android opengl es 3.0

我的代碼:

#include <stdio.h> 
#include <stdlib.h> 
#include <iostream> 
#include <vector> 

// Include GLEW 
#include <GL/glew.h> 

// Include GLFW 
#include <GLFW/glfw3.h> 
GLFWwindow* window; 

// Include GLM 
#include <glm/glm.hpp> 
using namespace glm; 
#include <SOIL.h> 

// Shader sources 
const GLchar* vertexSource = "\n" 
"#version 330 core\n" 
"attribute vec3 inPosition;\n" 
"void main()\n" 
"{\n" 
" float x = inPosition.x;\n" 
"\n" 
" gl_Position = vec4(\n" 
"  -1.0 + ((x) * 0.0078125),\n" 
"  -1,\n" 
"  0.0,\n" 
"  1.0\n" 
" );\n" 
"}\n"; 

const GLchar* fragmentSource = "\n" 
"#version 330 core\n" 
"out vec4 outputColor;\n" 
"void main()\n" 
"{\n" 
" outputColor = vec4(1.0, 1.0, 1.0, 1.0);\n" 
"}\n"; 

void CheckStatus(GLuint obj) 
{ 
    GLint status = GL_FALSE, len = 10; 
    if(glIsShader(obj)) glGetShaderiv(obj, GL_COMPILE_STATUS, &status); 
    if(glIsProgram(obj)) glGetProgramiv(obj, GL_LINK_STATUS, &status); 
    if(status == GL_TRUE) return; 
    if(glIsShader(obj)) glGetShaderiv(obj, GL_INFO_LOG_LENGTH, &len); 
    if(glIsProgram(obj)) glGetProgramiv(obj, GL_INFO_LOG_LENGTH, &len); 
    std::vector<char> log(len, 'X'); 
    if(glIsShader(obj)) glGetShaderInfoLog(obj, len, NULL, &log[0]); 
    if(glIsProgram(obj)) glGetProgramInfoLog(obj, len, NULL, &log[0]); 
    std::cerr << &log[0] << std::endl; 
    exit(-1); 
} 

GLfloat buffer[256]; 
GLuint hist[256]; 
float _image[512*512*3]; 

int main() 
{ 
    // Initialise GLFW 
    if(!glfwInit()) 
    { 
     fprintf(stderr, "Failed to initialize GLFW\n"); 
     getchar(); 
     return -1; 
    } 

    glfwWindowHint(GLFW_SAMPLES, 4); 
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); 
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); 
    glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // To make MacOS happy; should not be needed 
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); 

    int width, height; 
    unsigned char* image = SOIL_load_image("sample_gray.bmp", &width, &height, 0, SOIL_LOAD_RGB); 
    unsigned char image_gray[width * height]; 
    printf("%d\t%d\n", width, height); 

    for (int i = 0; i < width * height; ++i) 
    { 
     image_gray[i] = image[i * 3]; 
     _image[i * 3] = image[i * 3]; 
     _image[i * 3 + 1] = image[i * 3 + 1]; 
     _image[i * 3 + 2] = image[i * 3 + 2]; 
    } 

    for (int i = 0; i < width * height; ++i) 
    { 
     hist[image_gray[i]]++; 
    } 

    // Open a window and create its OpenGL context 
    window = glfwCreateWindow(width, height, "Basic", NULL, NULL); 
    if(window == NULL){ 
     fprintf(stderr, "Failed to open GLFW window. If you have an Intel GPU, they are not 3.3 compatible. Try the 2.1 version of the tutorials.\n"); 
     getchar(); 
     glfwTerminate(); 
     return -1; 
    } 
    glfwMakeContextCurrent(window); 

    // Initialize GLEW 
    glewExperimental = true; // Needed for core profile 
    if (glewInit() != GLEW_OK) { 
     fprintf(stderr, "Failed to initialize GLEW\n"); 
     getchar(); 
     glfwTerminate(); 
     return -1; 
    } 

    // Ensure we can capture the escape key being pressed below 
    glfwSetInputMode(window, GLFW_STICKY_KEYS, GL_TRUE); 

    // Dark blue background 
    glClearColor(0.0f, 0.0f, 0.0f, 0.0f); 

    GLuint vbo; 
    glGenBuffers(1, &vbo); 
    glBindBuffer(GL_ARRAY_BUFFER, vbo); 

    GLuint num_input_data = width * height; 

    /* Upload data */ 
    glBufferData(GL_ARRAY_BUFFER, num_input_data * sizeof(float) * 3, _image, GL_STATIC_DRAW); 

    GLuint vertexShader, fragmentShader, shaderProgram; 
    // Create and compile the vertex shader 
    vertexShader = glCreateShader(GL_VERTEX_SHADER); 
    glShaderSource(vertexShader, 1, &vertexSource, NULL); 
    glCompileShader(vertexShader); 
    CheckStatus(vertexShader); 
    // Create and compile the fragment shader 
    fragmentShader = glCreateShader(GL_FRAGMENT_SHADER); 
    glShaderSource(fragmentShader, 1, &fragmentSource, NULL); 
    glCompileShader(fragmentShader); 
    CheckStatus(fragmentShader); 
    // Link the vertex and fragment shader into a shader program 
    shaderProgram = glCreateProgram(); 
    glAttachShader(shaderProgram, vertexShader); 
    glAttachShader(shaderProgram, fragmentShader); 
    glBindFragDataLocation(shaderProgram, 0, "outputColor"); 
    glLinkProgram(shaderProgram); 


    CheckStatus(shaderProgram); 

    glUseProgram(shaderProgram); 


    // Specify the layout of the vertex data 
    GLint posAttrib = glGetAttribLocation(shaderProgram, "inPosition"); 
    glEnableVertexAttribArray(posAttrib); 
    glVertexAttribPointer(posAttrib, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), 0); 

    GLuint tex; 
    GLuint fbo; 
    glGenTextures(1, &tex); 
    glBindFramebuffer(GL_FRAMEBUFFER, fbo); 

    glGenFramebuffers(1, &fbo); 
    glActiveTexture(GL_TEXTURE0); 
    // glBindTexture(GL_TEXTURE_2D, tex); 
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 
    glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32F, 256, 1); 
    // glBindTexture(GL_TEXTURE_2D, 0); 

    glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex, 0); 

    /* Clear buffer */ 
    glClearColor(1.0, 0.0, 0.0, 1.0); 
    glClear(GL_COLOR_BUFFER_BIT); 

    glBlendEquation(GL_FUNC_ADD); 
    glBlendFunc(GL_ONE, GL_ONE); 
    glEnable(GL_BLEND); 

    /* Init viewport */ 
    glViewport(0, 0, 256, 1); 
    glUseProgram(shaderProgram); 
    /* Draw */ 
    glDrawArrays(GL_POINTS, 0, num_input_data); 


    glReadPixels(0, 0, 256, 1, GL_RED, GL_FLOAT, buffer); 

    for (int i = 0; i < 256; ++i) 
    { 
     printf("%d\t%f\t%d\n", i, buffer[i], hist[i]); 
    } 

} 

任何人可以幫助我,在此先感謝。

我已經更新了我的代碼,它的工作現在:d

#include <stdio.h> 
#include <stdlib.h> 
#include <iostream> 
#include <vector> 
// Include GLEW 
#include <GL/glew.h> 

// Include GLFW 
#include <GLFW/glfw3.h> 
GLFWwindow* window; 

// Include GLM 
#include <glm/glm.hpp> 
using namespace glm; 
#include <SOIL.h> 

// Shader sources 
const GLchar* vertexSource = "\n" 
"#version 330 core\n" 
"in vec3 inPosition;\n" 
"void main()\n" 
"{\n" 
" float x = inPosition.x;\n" 
"\n" 
" gl_Position = vec4(\n" 
"  -1.0 + ((x + 1) * 0.0078125),\n" 
"  0.0,\n" 
"  0.0,\n" 
"  1.0\n" 
" );\n" 
"}\n"; 

const GLchar* fragmentSource = "\n" 
"#version 330 core\n" 
"out vec4 outputColor;\n" 
"void main()\n" 
"{\n" 
" outputColor = vec4(1.0, 1.0, 1.0, 1.0);\n" 
"}\n"; 

void CheckStatus(GLuint obj) 
{ 
    GLint status = GL_FALSE, len = 10; 
    if(glIsShader(obj)) glGetShaderiv(obj, GL_COMPILE_STATUS, &status); 
    if(glIsProgram(obj)) glGetProgramiv(obj, GL_LINK_STATUS, &status); 
    if(status == GL_TRUE) return; 
    if(glIsShader(obj)) glGetShaderiv(obj, GL_INFO_LOG_LENGTH, &len); 
    if(glIsProgram(obj)) glGetProgramiv(obj, GL_INFO_LOG_LENGTH, &len); 
    std::vector<char> log(len, 'X'); 
    if(glIsShader(obj)) glGetShaderInfoLog(obj, len, NULL, &log[0]); 
    if(glIsProgram(obj)) glGetProgramInfoLog(obj, len, NULL, &log[0]); 
    std::cerr << &log[0] << std::endl; 
    exit(-1); 
} 

void _check_gl_error(int line) 
{ 
    GLenum err (glGetError()); 

    while(err!=GL_NO_ERROR) 
    { 
     std::string error; 

     switch(err) 
     { 
      case GL_INVALID_OPERATION:  error="INVALID_OPERATION";  break; 
      case GL_INVALID_ENUM:   error="INVALID_ENUM";   break; 
      case GL_INVALID_VALUE:   error="INVALID_VALUE";   break; 
      case GL_OUT_OF_MEMORY:   error="OUT_OF_MEMORY";   break; 
      case GL_INVALID_FRAMEBUFFER_OPERATION: error="INVALID_FRAMEBUFFER_OPERATION"; break; 
     } 

     std::cerr << "GL_" << error.c_str() <<":"<<line<<std::endl; 
     err=glGetError(); 
    } 
} 

GLfloat buffer[256]; 
GLuint hist[256]; 
float _image[512*512*3]; 

int main() 
{ 
    // Initialise GLFW 
    if(!glfwInit()) 
    { 
     fprintf(stderr, "Failed to initialize GLFW\n"); 
     getchar(); 
     return -1; 
    } 

    glfwWindowHint(GLFW_SAMPLES, 4); 
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); 
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); 
    glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // To make MacOS happy; should not be needed 
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); 

    int width, height; 
    unsigned char* image = SOIL_load_image("sample_gray.bmp", &width, &height, 0, SOIL_LOAD_RGB); 
    unsigned char* image_gray = new unsigned char[width * height]; 

    printf("%d\t%d\n", width, height); 


    for (int i = 0; i < width * height; ++i) 
    { 
     image_gray[i] = image[i * 3]; 
     _image[i * 3] = image[i * 3]; 
     _image[i * 3 + 1] = image[i * 3 + 1]; 
     _image[i * 3 + 2] = image[i * 3 + 2]; 
    } 

    for (int i = 0; i < width * height; ++i) 
    { 
     hist[image_gray[i]]++; 
    } 

    // Open a window and create its OpenGL context 
    window = glfwCreateWindow(width, height, "Basic", NULL, NULL); 
    if(window == NULL){ 
     fprintf(stderr, "Failed to open GLFW window. If you have an Intel GPU, they are not 3.3 compatible. Try the 2.1 version of the tutorials.\n"); 
     getchar(); 
     glfwTerminate(); 
     return -1; 
    } 
    glfwMakeContextCurrent(window); 

    // Initialize GLEW 
    glewExperimental = true; // Needed for core profile 
    if (glewInit() != GLEW_OK) { 
     fprintf(stderr, "Failed to initialize GLEW\n"); 
     getchar(); 
     glfwTerminate(); 
     return -1; 
    } 
    _check_gl_error(__LINE__); 
    // Ensure we can capture the escape key being pressed below 
    glfwSetInputMode(window, GLFW_STICKY_KEYS, GL_TRUE); 

    // Dark blue background 
    glClearColor(0.0f, 0.0f, 0.0f, 0.0f); 


    GLuint vao; 
    glGenVertexArrays(1, &vao); 
    glBindVertexArray(vao); 

    GLuint vbo; 
    glGenBuffers(1, &vbo); 
    glBindBuffer(GL_ARRAY_BUFFER, vbo); 

    GLuint num_input_data = width * height; 

    /* Upload data */ 
    glBufferData(GL_ARRAY_BUFFER, num_input_data * sizeof(float) * 3, _image, GL_STATIC_DRAW); 

    GLuint vertexShader, fragmentShader, shaderProgram; 
    // Create and compile the vertex shader 
    vertexShader = glCreateShader(GL_VERTEX_SHADER); 
    glShaderSource(vertexShader, 1, &vertexSource, NULL); 
    glCompileShader(vertexShader); 
    CheckStatus(vertexShader); 
    // Create and compile the fragment shader 
    fragmentShader = glCreateShader(GL_FRAGMENT_SHADER); 
    glShaderSource(fragmentShader, 1, &fragmentSource, NULL); 
    glCompileShader(fragmentShader); 
    CheckStatus(fragmentShader); 
    // Link the vertex and fragment shader into a shader program 
    shaderProgram = glCreateProgram(); 
    glAttachShader(shaderProgram, vertexShader); 
    glAttachShader(shaderProgram, fragmentShader); 
    glBindFragDataLocation(shaderProgram, 0, "outputColor"); 
    glLinkProgram(shaderProgram); 


    CheckStatus(shaderProgram); 

    glUseProgram(shaderProgram); 


    // Specify the layout of the vertex data 
    GLint posAttrib = glGetAttribLocation(shaderProgram, "inPosition"); 
    glEnableVertexAttribArray(posAttrib); 
    glVertexAttribPointer(posAttrib, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), 0); 

    GLuint tex; 
    GLuint fbo; 
    glGenFramebuffers(1, &fbo); 
    glBindFramebuffer(GL_FRAMEBUFFER, fbo); 

    glGenTextures(1, &tex); 
    glActiveTexture(GL_TEXTURE0); 
    glBindTexture(GL_TEXTURE_2D, tex); 
    glTexImage2D(GL_TEXTURE_2D, 0, GL_R32F, 256, 1, 0, GL_RED, GL_FLOAT, NULL); 
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 
    // glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32F, 256, 1); 

    glBindTexture(GL_TEXTURE_2D, 0); 

    glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex, 0); 

    glBindFramebuffer(GL_FRAMEBUFFER, 0); 

    _check_gl_error(__LINE__); 

    glBindFramebuffer(GL_FRAMEBUFFER, fbo); 
    /* Clear buffer */ 
    glClearColor(0.0, 0.0, 0.0, 1.0); 
    glClear(GL_COLOR_BUFFER_BIT); 

    glBlendEquation(GL_FUNC_ADD); 
    glBlendFunc(GL_ONE, GL_ONE); 
    glEnable(GL_BLEND); 
    _check_gl_error(__LINE__); 


    /* Init viewport */ 
    glViewport(0, 0, 256, 1); 
    glUseProgram(shaderProgram); 
    /* Draw */ 
    glDrawArrays(GL_POINTS, 0, num_input_data); 


    glReadPixels(0, 0, 256, 1, GL_RED, GL_FLOAT, buffer); 
    _check_gl_error(__LINE__); 
    for (int i = 0; i < 256; ++i) 
    { 
     printf("%d\t%f\t%d\n", i, buffer[i], hist[i]); 
    } 
    free(image_gray); 
} 

特別感謝到@Vallentin你的熱情!

+0

我看到的第一件事情就是你綁定'fbo'您生成它。第二:只有當沒有着色器對象和着色器程序具有相同的ID時,「CheckStatus」方法才起作用。所有的句柄都是無符號整數,並且對於OpenGL實現來說,它是完全有效的,可爲您提供着色器對象0和着色器程序對象0.在這種情況下,您的方法將查詢鏈接狀態和編譯狀態。 – BDL

+0

@BDL,謝謝。我在下面更新了我的代碼。你能幫我檢查一遍嗎? –

回答

2

我的直方圖緩衝區總是返回零。

有趣。因爲我不知道哪個編譯器,它可以讓這樣的事情飛過:

int width, height; 
unsigned char* image = SOIL_load_image("sample_gray.bmp", &width, &height, 0, SOIL_LOAD_RGB); 
unsigned char image_gray[width * height]; 

如果你需要做的:

unsigned char *image_gray = new unsigned char[width * height]; 

記得後來釋放內存delete[] image_gray

你的着色器也不能編譯,或者你的驅動程序比我的更精簡。由於#version 330 core你不能使用attribute,將不得不使用in

in vec3 inPosition; 

正如CheckStatus()還講述了這樣:

0(3) : error C7555: 'attribute' is deprecated, use 'in/out' instead 

你也試圖綁定一個幀緩衝區,你甚至不用呢。

GLuint fbo; 
glBindFramebuffer(GL_FRAMEBUFFER, fbo); 
[...] 
glGenFramebuffers(1, &fbo); 

你需要圍繞翻轉:

GLuint fbo; 
glGenFramebuffers(1, &fbo); 
glBindFramebuffer(GL_FRAMEBUFFER, fbo); 

這也讓我爲難,爲什麼你的編譯器將讓該幻燈片,隨着MSVC尖叫我。

Error C4700 uninitialized local variable 'fbo' 

在應用任何更改之前,您也沒有約束紋理。

// glBindTexture(GL_TEXTURE_2D, tex); 

因此取消註釋glBindTexture()呼叫。你也不是創建任何頂點數組。哪些檢查glGetError()會告訴。

GLuint vao; 
glGenVertexArrays(1, &vao); 
glBindVertexArray(vao); 

在致電glEnableVertexAttribArray()之前這樣做。

此外,您的清晰顏色是紅色。所以這不會對你有太大的幫助。現在您致電glReadPixels()只會產生1.0

glClearColor(0.0, 0.0, 0.0, 1.0) 

現在glReadPixels()仍然只產生零。但是根本不需要綁定或不創建幀緩衝區。然後它給出我所期望的結果。由於不使用framebuffer不應該如此,我懷疑它有什麼問題。然而,我不能通過瀏覽你的代碼來指明它。但是,由於代碼已經充滿了問題,這是一個公平的起點。

附加:

  • 你瞄準的OpenGL 3.3,而glTexStorage2D()爲核心的4.2。要點是,如果你想確保glTexStorage2D()支持,目標4.2。
  • glActiveTexture()的呼叫是多餘的。
  • 由於紋理的高度爲1,因此請考慮使用1D紋理。
  • 記住要檢查glGetError()或者更好的利用所有的Debug Output

編輯

首先,你不能叫_check_gl_error()已經創建的窗口(和上下文)之前,並呼籲glewInit()

您可以使用__LINE__來代替手動添加行號。因此_check_gl_error(__LINE__)

再次不要使用紅色清晰的顏色。使用黑色清晰的顏色glClearColor(0.0, 0.0, 0.0, 1.0)。作爲混合1.0並且說0.1結果在1.1,其被限制回1.0。因此,紅色通道從開始應該是0.0

我意識到了這個問題。在頂點着色器中,您手動將y設置爲-1.0。考慮到你正在繪製GL_POINTS,這最終會從屏幕上掉下來。 將其設置爲y-0.9999現在似乎給出了期望的結果。但依靠這一點就像玩火一樣。

如果您現在運行該應用程序,您現在將看到0.01.0的混合。你得到1.0的原因是因爲在你的片段着色器中,你將紅色通道的outputColor設置爲1.0。再次總結所有這些可能是一些瘋狂的價值,但最終它會被限制回到1.0

而是嘗試:

outputColor = vec4(0.005, 1.0, 1.0, 1.0); 

現在你應該看到的輸出增加和減少,而不是被任何0.01.0。但是請注意,如果hist[i]大於200,那麼任何這樣的結果都將導致1.0。因爲1/0.005 = 200

一切都是至少工作現在。

+0

感謝@Vallentin的回覆。我用你推薦的點更新了我的代碼。我使用'glGeterror()'添加'_check_gl_error'函數來檢查錯誤。但是,我的緩衝區仍然返回零(如果我將顏色清除爲紅色,則爲1.0,如您所說)。你能再次檢查我的代碼嗎?謝謝。還有一件事,你可以建議我將函數'glTexStorage1D'替換爲其他函數嗎? –

+0

@ tiena2cva查看我的編輯。 – Vallentin

+1

@BDL當然。錯字和固定;) – Vallentin