我尝试使用 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 的热情!
最佳答案
My histogram buffer always return zeros.
有趣的。因为我不知道哪个编译器可以让这样的事情飞过:
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
您还尝试绑定(bind)您甚至还没有的帧缓冲区。
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'
在对纹理应用任何更改之前,您也没有绑定(bind)纹理。
// 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()
仍然只产生零。然而,解除绑定(bind)或根本不创建帧缓冲区。然后它给出了我认为是期望的结果。由于不应该使用帧缓冲区,我怀疑它有问题。但是,我似乎无法通过浏览您的代码来确定它。但由于代码已经充满了问题,这是一个公平的起点。额外的:
glTexStorage2D()
是4.2的核心。重点是,如果你想确定 glTexStorage2D()
支持,目标 4.2。 glActiveTexture()
是多余的。 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
.因此红色 channel 应该是0.0
从一开始。我意识到了这个问题。在您的顶点着色器中,您手动设置
y
至-1.0
.鉴于您正在绘制 GL_POINTS
,这最终会从屏幕上掉下来。 .将其设置为
y
至-0.9999
现在似乎给出了预期的结果。然而,依靠这一点,就像玩火一样。如果您现在运行该应用程序,您现在将看到
0.0
的混合。和 1.0
.你得到1.0
的原因是因为在您的片段着色器中您正在设置 outputColor
红色 channel 为 1.0
.再次总结所有这些可能是一些疯狂的值(value),但最终它会被限制在 1.0
.而是尝试:
outputColor = vec4(0.005, 1.0, 1.0, 1.0);
现在您应该看到输出增加和减少,而不是
0.0
或 1.0
.但是请注意,如果 hist[i]
大于 200,那么任何大于 200 的都将导致 1.0
.因为1 / 0.005 = 200
.至少现在一切正常。
关于c++ - 在 OPENGL 中计算直方图,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43159931/