2017-04-01 6 views
0

Ich versuche, Histogramm eines Bildes mit OPENGL zu berechnen. Ich habe einen Post darüber gelesen, aber ich bekomme immer noch Fehler. Mein Histogrammpuffer gibt immer Nullen zurück. noch einige Kleinigkeiten, die ich gelesen habe:Histogramm in OPENGL berechnen

Maknoll Histogram

Luminance histogram calculation in GPU-android opengl es 3.0

Mein Code:

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

} 

Könnte jemand mir helfen, danke im voraus.

ich meinen Code aktualisiert haben, es funktioniert jetzt: 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); 
} 

Besonderer Dank für Ihre Begeisterung @Vallentin!

+0

Das erste, was ich sehe, ist, dass Sie 'fbo' binden, bevor Sie es erzeugen. Zweitens: Ihre 'CheckStatus'-Methode funktioniert nur, wenn es kein Shader-Objekt und kein Shader-Programm mit derselben ID gibt. Alle Handles sind nur vorzeichenlose Integer, und es ist durchaus zulässig, dass eine OpenGL-Implementierung Ihnen ein Shader-Objekt 0 und ein Shader-Programm-Objekt 0 liefert. In diesem Fall würde Ihre Methode sowohl den Verbindungsstatus als auch den Kompilierungsstatus abfragen. – BDL

+0

@ BDL, Danke. Ich habe meinen Code unten aktualisiert. Kannst du mir helfen, es noch einmal zu überprüfen? –

Antwort

2

Mein Histogrammpuffer gibt immer Nullen zurück.

Interessant. Weil ich weiß nicht, welchem ​​Compiler, den sie so etwas wie diese Fliege von:

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

Wo müssen Sie tun:

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

Denken Sie daran, später die delete[] image_gray Speicher frei.

Ihr Shader kompiliert auch nicht oder vielleicht ist Ihr Treiber ein bisschen schlanker als meins. Wie angegeben #version 330 core können Sie attribute nicht verwenden und in verwenden müssen.

in vec3 inPosition; 

Wie CheckStatus() ist sagt auch dies:

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

Sie auch einen Framebuffer zu binden versuchen, aber Sie haben nicht einmal.

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

Sie müssten, dass um kippen:

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

Es ist mir auch ein Rätsel, warum der Compiler würde diese Folie lassen, wie MSVC bei mir schreit.

Error C4700 uninitialized local variable 'fbo' 

Sie die Textur nicht verbindlich auch vor Änderungen daran Anwendung.

// glBindTexture(GL_TEXTURE_2D, tex); 

So uncomment dass glBindTexture() Anruf.

Sie erstellen auch keine Vertex-Arrays. Welche Überprüfung hätte glGetError() gesagt.

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

Tun Sie dies vor dem Anruf glEnableVertexAttribArray().

Auch Ihre klare Farbe ist rot. Das wird dir nicht so viel helfen. Wie jetzt würde Ihr Anruf an glReadPixels() nur 1.0 ergeben.

glClearColor(0.0, 0.0, 0.0, 1.0) 

Jetzt glReadPixels() immer noch nur Null ergeben. Jedoch nicht oder überhaupt nicht den Framebuffer erstellen. Dann gibt es das, was ich für das gewünschte Ergebnis halte. Da ich den Framebuffer nicht benutzen sollte, bin ich der Meinung, dass etwas nicht stimmt. Ich kann jedoch nicht durch einen Blick auf Ihren Code darauf hinweisen. Aber da der Code bereits mit Problemen gespickt ist, ist dies ein fairer Ausgangspunkt.

Zusätzlich:

  • Sie Targeting OpenGL 3.3, während glTexStorage2D() Kern in 4.2 ist. Punkt ist, dass, wenn Sie sicherstellen möchten, dass glTexStorage2D() unterstützt wird, Ziel 4.2.
  • Der Aufruf an glActiveTexture() ist redundant.
  • Da Ihre Textur eine Höhe von 1 hat, sollten Sie eine 1D-Textur verwenden.
  • Denken Sie daran, glGetError() oder besser nutzen noch prüfen Debug Output

bearbeiten

Zunächst einmal können Sie _check_gl_error() nicht aufrufen, bevor das Fenster (und Kontext) geschaffen zu haben und glewInit() genannt.

Anstatt die Zeilennummer manuell hinzuzufügen, können Sie __LINE__ verwenden. Also _check_gl_error(__LINE__).

Verwenden Sie wieder keine rote, klare Farbe. Verwenden Sie eine schwarze, klare Farbe . Als Blending 1.0 und sagen 0.1 Ergebnisse in 1.1, die auf 1.0 geklammert wird. So sollte der rote Farbkanal von Anfang an 0.0 sein.

Ich erkannte das Problem. In Ihrem Vertex-Shader setzen Sie y manuell auf -1.0. Dies führt dazu, dass Sie aus dem Bildschirm fallen, da Sie GL_POINTS zeichnen. Einstellung auf y zu -0.9999 scheint jetzt das gewünschte Ergebnis zu geben. Sich darauf zu verlassen, ist wie mit Feuer zu spielen. Wenn Sie jetzt die Anwendung ausführen, sehen Sie jetzt eine Mischung aus 0.0 und 1.0. Der Grund dafür, dass Sie 1.0 erhalten, liegt darin, dass Sie in Ihrem Fragment-Shader outputColor für den roten Kanal als 1.0 festlegen. Das alles wieder zusammenzufassen könnte ein verrückter Wert sein, aber am Ende wird es wieder auf 1.0 geklemmt.

Stattdessen versuchen, mit:

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

Nun sollten Sie die Ausgabe Erhöhen und Erniedrigen, statt entweder 0.0 sein oder 1.0 sehen. Beachten Sie jedoch, dass, wenn hist[i] größer als 200 ist, das Ergebnis 1.0 ist. Weil 1/0.005 = 200.

Alles ist mindestens arbeiten jetzt.

+0

Danke für die Antwort @Vallentin. Ich habe meinen Code mit Punkten aktualisiert, die Sie empfehlen. Ich füge '_check_gl_error' -Funktion mit' glGeterror() 'hinzu, um Fehler zu überprüfen. Allerdings gibt mein Puffer immer noch Nullen zurück (1.0, wenn ich die Farbe auf rot lösche, wie du gesagt hast). Können Sie meinen Code erneut überprüfen? Vielen Dank. Noch eine Sache, Können Sie mir vorschlagen, die Funktion 'glTexStorage1D' durch eine andere Funktion zu ersetzen? –

+0

@ tiena2cva Schau dir meinen Schnitt an. – Vallentin

+1

@ BDL natürlich. Tippfehler und behoben;) – Vallentin