opengl 利用高斯模糊(Gaussian blur/高斯滤波)对tof深度图像进行图像平滑处理

在做AR云渲染服务中,需要对华为AR Engine获取得到的深度图进行处理,AR Engine获取得到的深度图就是直接利用tof获取得到的深度图,都没有进行优化过,这里要吐槽一下AR Engine,人家友商arcore获取得到深度图就非常的平滑。

一种简单的方式是取了图像周围所有像素,然后求平均值。虽然它确实给我们一个容易模糊,但它并没有给出最好的结果。高斯模糊是基于高斯曲线,高斯曲线通常被描述为钟形曲线,在靠近中心处给出高值,随着距离逐渐磨损。高斯曲线可以用不同的数学形式表示,但通常具有以下形状:

由于高斯曲线靠近其中心的面积较大,因此使用其值作为权重来模糊图像会得到更自然的结果,因为附近的样本具有更高的优先性。例如,如果我们对一个32x32的框在片段周围取样,那么我们使用距离片段越大的递进权值越小;这将产生一个更好和更现实的模糊,称为高斯模糊。

为了实现高斯模糊滤波器,我们需要一个二维权重框,我们可以从二维高斯曲线方程得到。然而,这种方法的问题在于它很快会变得非常沉重的性能。以32乘32的模糊内核为例,这将需要我们对每个片段的纹理进行总共1024次的采样!

幸运的是,高斯方程有一个非常整洁的性质,它允许我们把二维方程分成两个较小的一维方程:一个描述水平权重,另一个描述垂直权重。然后,我们首先使用场景纹理上的水平权重来做水平模糊,然后在生成的纹理上做垂直模糊。由于这个属性的结果是完全相同的,但这次节省了我们令人难以置信的数量的性能,因为我们现在只需要做32 + 32个样本相比1024!这被称为两遍高斯模糊。

 

这确实意味着我们需要模糊图像至少两次,这里使用framebuffer对象效果最好。特别针对两遍高斯模糊,我们将实现乒乓帧缓冲。这是一对帧缓冲器,在给定次数的时间内,我们渲染和交换另一个帧缓冲器的颜色缓冲器到当前帧缓冲器的颜色缓冲器,并具有交替着色效果。我们基本上连续地切换帧缓冲区渲染和纹理绘制。这允许我们首先将场景的纹理模糊在第一帧缓冲器,然后将第一帧缓冲器的颜色缓冲器模糊到第二帧缓冲器,然后将第二帧缓冲器的颜色缓冲器模糊到第一帧缓冲器,等等。

在深入研究帧缓冲器之前,让我们先讨论一下高斯模糊的片段着色器:

#version 330 core
out vec4 FragColor;
  
in vec2 TexCoords;

uniform sampler2D image;
  
uniform bool horizontal;
uniform float weight[5] = float[] (0.227027, 0.1945946, 0.1216216, 0.054054, 0.016216);

void main()
{             
    vec2 tex_offset = 1.0 / textureSize(image, 0); // gets size of single texel
    vec3 result = texture(image, TexCoords).rgb * weight[0]; // current fragment's contribution
    if(horizontal)
    {
        for(int i = 1; i < 5; ++i)
        {
            result += texture(image, TexCoords + vec2(tex_offset.x * i, 0.0)).rgb * weight[i];
            result += texture(image, TexCoords - vec2(tex_offset.x * i, 0.0)).rgb * weight[i];
        }
    }
    else
    {
        for(int i = 1; i < 5; ++i)
        {
            result += texture(image, TexCoords + vec2(0.0, tex_offset.y * i)).rgb * weight[i];
            result += texture(image, TexCoords - vec2(0.0, tex_offset.y * i)).rgb * weight[i];
        }
    }
    FragColor = vec4(result, 1.0);
}

这里我们选取一个相对较小的高斯权重样本,我们每个样本用来给当前片段周围的水平或垂直样本分配特定的权重。您可以看到,我们根据设置水平均匀值的任何值,将模糊滤镜分成水平和垂直部分。我们根据纹理大小的1.0除以纹理大小(从纹理大小的vec2)得出的texel的确切大小来计算偏移距离。

为了使图像模糊化,我们创建两个基本的帧缓冲区,每个帧缓冲区仅具有颜色缓冲区纹理:

unsigned int pingpongFBO[2];
unsigned int pingpongBuffer[2];
glGenFramebuffers(2, pingpongFBO);
glGenTextures(2, pingpongBuffer);
for (unsigned int i = 0; i < 2; i++)
{
    glBindFramebuffer(GL_FRAMEBUFFER, pingpongFBO[i]);
    glBindTexture(GL_TEXTURE_2D, pingpongBuffer[i]);
    glTexImage2D(
        GL_TEXTURE_2D, 0, GL_RGBA16F, SCR_WIDTH, SCR_HEIGHT, 0, GL_RGBA, GL_FLOAT, NULL
    );
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_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);
    glFramebufferTexture2D(
        GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, pingpongBuffer[i], 0
    );
}

将纹理填充到乒乓帧缓存中,然后对图像进行10次模糊(水平5次,垂直5次):

bool horizontal = true, first_iteration = true;
int amount = 10;
shaderBlur.use();
for (unsigned int i = 0; i < amount; i++)
{
    glBindFramebuffer(GL_FRAMEBUFFER, pingpongFBO[horizontal]); 
    shaderBlur.setInt("horizontal", horizontal);
    glBindTexture(
        GL_TEXTURE_2D, first_iteration ? colorBuffers[1] : pingpongBuffers[!horizontal]
    ); 
    RenderQuad();
    horizontal = !horizontal;
    if (first_iteration)
        first_iteration = false;
}
glBindFramebuffer(GL_FRAMEBUFFER, 0); 

每次迭代,我们将根据是水平还是垂直模糊来绑定两个帧缓冲中的一个,并将另一个帧缓冲的颜色缓冲作为要模糊的纹理来绑定。在第一次迭代中,我们特别地绑定了我们想要模糊的纹理(亮度纹理),否则两个颜色缓冲器最终会空。通过重复这个过程10次,亮度图像以重复5次的完整高斯模糊结束。这个结构允许我们尽可能频繁地模糊任何图像;高斯模糊迭代越多,模糊越强。

 

参考文献:

https://learnopengl.com/Advanced-Lighting/Bloom

https://blog.csdn.net/nima1994/article/details/79776802?utm_medium=distribute.pc_relevant.none-task-blog-baidujs_baidulandingword-2&spm=1001.2101.3001.4242

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
1 课程简介:本课程详细讲解了OpenGL从入门到精通的理论+实践知识,对于每一个知识点都会带领学员通过代码来实现功能。其中涵盖了基础图元绘制,基础光照,高级过程,高级光照等内容;当前图形引擎的应用已经越来越广泛,春晚以及各大综艺节目已经开始使用XR作为主流的内容制作技术,房地产漫游及Web渲染技术已经开始茁壮发展,VR也即将突破硬件瓶颈;普遍的游戏引擎在独特的领域已经无法完全实用,且我们国家要发展自主科技技术,图形引擎以及CAD等卡脖子技术一定会蓬勃发展,所以同学们要抓住机会,趁势而上,熟悉底层,博取更大发展,学习OpenGL底层接口的应用以及图形学算法,将是您向纵深发展的第一步!2 课程解决优势:很多同学学习OpenGL最难的是找到路径,并且其中牵扯到的理论知识点无法完全理解透彻(比如VAO与VBO的区别,MVP矩阵变换的推导及原理,光照系统的设计及算法推导,帧缓存的灵活应用等),我们的课程可以带领大家从原理+实践的角度进行学习,每一个知识点都会:a 推导基础公式及原理 b 一行一行进行代码实践从而能够保证每位同学都学有所得,能够看得懂,学得会,用得上,并且能够培养自主研究的能力。学习课程所得:学习本课程完毕之后,学员可以全方位的完全了解OpenGL当中的必要接口,并且可以对图形学的基础知识融会贯通,可以制作中级的特效。并且对于UnrealEngine以及Unity3D的学习更加轻松,对于各类商业引擎当中的算法以及内容制作手法更加深刻理解把控。学员也可以自行进行图形引擎的设计以及研究,并且将本课程的知识点进行代码模块化编写;能够自主推导图形学管线以及应用当中的各类公式,并且理解其几何含义。 代码与PPT资源,已随课程附赠,请同学们对应课程下载 

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

XR风云

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值