我们都知道AREngine返回的深度图质量并不高,大概率是直接返回的tof深度图,跟ARCORE返回的深度图差距还是比较大的。在我们当前AR云渲染项目中,需要用到AREngine返回的深度图,这就需要提高深度图的质量。
所以就开始研究怎样优化AREngine的深度图的方法。本篇博客是对深度图进行补洞的常规方法。
基于最大/最小/平均值的补洞方法,无非就是在周边像素找到能够对候补像素进行补值的算法。如下图所示。
在opengl中,我们会查找周边的像素,找到最大/最小值,或者计算出所有像素的平均值,作为候补像素的值。注意的是,在我们算法中,主要是补“白点”像素,根据不同场景,你们可能有不同的判断。但是基本的算法都是想通的。
#version 320 es
#extension GL_OES_EGL_image_external_essl3: enable
precision highp float;
precision highp usampler2D;
#define ARCLOUD_MAX_DEPTH_MM 2000.0
#define FAR ARCLOUD_MAX_DEPTH_MM
#define NEAR 50.0
layout (binding = 0) uniform sampler2D inTexture;
float bias = 0.001;
vec4 encodeFloatRGBA(float v)
{
float r = float((int(v)) & 0xFF);
float g = float((int(v) >> 8) & 0xFF);
return vec4(r / 255.0, g / 255.0, 0.0, 1.0);
}
float decodeFloatRGBA(vec4 enc)
{
return enc.r * 255.0 + enc.g * 256.0 * 255.0;
}
//opt == 1: max
//opt == 2: min
//opt == 3: +
//return x: 计算之后的值,y: 计算之后的个数
vec2 calOperator(float left, float right, int opt) {
float ret = 0.0;
float count = 0.0;
switch (opt) {
case 1:
ret = max(left, right);
count = 0.0;
break;
case 2:
ret = min(left, right);
count = 0.0;
break;
case 3:
ret = left + right;
count = 1.0;
break;
}
return vec2(ret, count);
}
vec4 statisticalFilter(vec2 texCoords, int mode) {
const int rad = 2;
float sum = 0.0;
int opt = 3;
switch (mode) {
case 1:
sum = 1.0;
opt = 1;
break;
case 2:
sum = 1.0;
opt = 2;
break;
case 3:
sum = 0.0;
opt = 3;
break;
}
ivec2 size = ivec2(0);
if (isSrcTexture) {
size = textureSize(srcTexture, 0);
} else {
size = textureSize(inTexture, 0);
}
vec2 tex_offset = 1.0 / vec2(size);
float result = 0.0;
float curDepth = getDepth(texCoords);
//如果像素不是为白点,则直接返回原始的深度值, FAR为我们的最大深度值,在AREngine中,设置4000mm比较好一点
if (abs(curDepth - FAR) < bias) {
for (int x = -rad; x <= rad; ++x)
{
for (int y = -rad; y <= rad; ++y)
{
if (x == 0 && y == 0) {
continue;
}
//超越边界的不做处理
vec2 curUv = texCoords + vec2(x, y) * tex_offset;
if (any(lessThan(curUv, vec2(0.0, 0.0)))) {
continue;
}
if (any(greaterThan(curUv, vec2(1.0, 1.0)))) {
continue;
}
float tempDepth = getDepth(curUv);
//只寻找非白点的值
if (abs(tempDepth - FAR) < bias) {
continue;
}
vec2 calResult = calOperator(result, tempDepth, opt);
result = calResult.x;
sum += calResult.y;
}
if (abs(result - 0.0) < 0.00001) {
result = curDepth;
}
}
} else {
result = curDepth;
sum = 1.0;
}
return encodeFloatRGBA(result / sum);
}
AREngine中如何获取深度图,请参考我的另外一篇文章: 华为AREngine根据深度图获取深度信息。
我们看一下效果,有一定的效果。
最大值补洞效果:
最小值补洞效果:
平均值补洞效果:
参考文献: