Gáb*_*ete 6 c++ opengl opencv image-processing compute-shader
我正在尝试为图像处理实现多通道计算着色器.每次通过都有输入图像和输出图像.下一个'输入图像是前一个输出'.
这是我第一次在OpenGL中使用计算着色器,因此我的设置可能存在一些问题.我正在使用OpenCV的Mat作为读取/复制操作的容器.
代码的某些部分与问题无关,所以我没有包含.其中一些部分包括加载图像或初始化上下文.
//texture init
glGenTextures(1, &feedbackTexture_);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, feedbackTexture_);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glBindTexture(GL_TEXTURE_2D, 0);
glGenTextures(1, &resultTexture_);
glActiveTexture(GL_TEXTURE0+1);
glBindTexture(GL_TEXTURE_2D, resultTexture_);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glBindTexture(GL_TEXTURE_2D, 0);
// shader init
computeShaderID = glCreateShader(GL_COMPUTE_SHADER);
glShaderSource(computeShaderID, 1, &computeShaderSourcePtr, &computeShaderLength);
glCompileShader(computeShaderID);
programID = glCreateProgram();
glAttachShader(programID, computeShaderID);
glLinkProgram(programID);
glDeleteShader(computeShaderID);
Run Code Online (Sandbox Code Playgroud)
//shader code (simple invert)
#version 430
layout (local_size_x = 1, local_size_y = 1) in;
layout (location = 0, binding = 0, /*format*/ rgba32f) uniform readonly image2D inImage;
layout (location = 1, binding = 1, /*format*/ rgba32f) uniform writeonly image2D resultImage;
uniform writeonly image2D image;
void main()
{
// Acquire the coordinates to the texel we are to process.
ivec2 texelCoords = ivec2(gl_GlobalInvocationID.xy);
// Read the pixel from the first texture.
vec4 pixel = imageLoad(inImage, texelCoords);
pixel.rgb = 1. - pixel.rgb;
imageStore(resultImage, texelCoords, pixel);
}
Run Code Online (Sandbox Code Playgroud)
cv::Mat image = loadImage().clone();
cv::Mat result(image.rows,image.cols,image.type());
// These get the appropriate enums used by glTexImage2D
GLenum internalformat = GLUtils::getMatOpenGLImageFormat(image);
GLenum format = GLUtils::getMatOpenGLFormat(image);
GLenum type = GLUtils::getMatOpenGLType(image);
int dispatchX = 1;
int dispatchY = 1;
for ( int i = 0; i < shaderPasses_.size(); ++i)
{
// Update textures
glBindTexture(GL_TEXTURE_2D, feedbackTexture_);
glTexImage2D(GL_TEXTURE_2D, 0, internalformat, result.cols, result.rows, 0, format, type, result.data);
glBindTexture(GL_TEXTURE_2D, resultTexture_);
glTexImage2D(GL_TEXTURE_2D, 0, internalformat, image.cols, image.rows, 0, format, type, 0);
glBindTexture(GL_TEXTURE_2D, 0);
glClear(GL_COLOR_BUFFER_BIT);
std::shared_ptr<Shader> shaderPtr = shaderPasses_[i];
// Enable shader
shaderPtr->enable();
{
// Bind textures
// location = 0, binding = 0
glUniform1i(0,0);
// binding = 0
glBindImageTexture(0, feedbackTexture_, 0, GL_FALSE, 0, GL_READ_ONLY, internalformat);
// location = 1, binding = 1
glUniform1i(1,1);
// binding = 1
glBindImageTexture(1, resultTexture_, 0, GL_FALSE, 0, GL_WRITE_ONLY, internalformat);
// Dispatch rendering
glDispatchCompute((GLuint)image.cols/dispatchX,(GLuint)image.rows/dispatchY,1);
// Barrier will synchronize
glMemoryBarrier(GL_TEXTURE_UPDATE_BARRIER_BIT);
}
// disable shader
shaderPtr->disable();
// Here result is now the result of the last pass.
}
Run Code Online (Sandbox Code Playgroud)
有时我得到奇怪的结果(毛刺纹理,部分渲染纹理),第一个像素(0,0)有时也不会被写入.我是否正确设置了一切,还是我缺少了什么?似乎这种带有纹理的方法真的很慢,有没有其他可以提高性能的方法呢?
Edit1: 更改了memorybarrier标志.
Run Code Online (Sandbox Code Playgroud)glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
这是一个错误的障碍.屏障指定了在非相干访问之后您打算如何访问数据.如果你试图从纹理中读取glGetTexImage
,你必须使用GL_TEXTURE_UPDATE_BARRIER_BIT
.
我终于可以解决这个问题了!
问题出在 cv::Mat 的构造函数中。以下行仅为 cv::Mat 创建标头:
cv::Mat result(image.rows,image.cols,image.type());
Run Code Online (Sandbox Code Playgroud)
它确实分配数据,但不初始化该数据,这就是我得到这些奇怪结果的原因。那是记忆中的垃圾。
使用任何分配并初始化该数据的函数可以解决该问题:
cv::Mat::zeros
cv::Mat::ones
cv::Mat::create
Run Code Online (Sandbox Code Playgroud)