我们都知道AREngine返回的深度图质量并不高,大概率是直接返回的tof深度图,跟ARCORE返回的深度图差距还是比较大的。在我们当前AR云渲染项目中,需要用到AREngine返回的深度图,这就需要提高深度图的质量。
所以就开始研究怎样优化AREngine的深度图的方法。本篇博客是对深度图进行补洞的常规方法。
两基带统计算法:首先遍历深度图,寻找深度图中的“白点”像素(候选像素),查找候选像素相邻的像素,滤波器把候选像素周围分两个个“带”,统计周围像素的非“白点”值,滤波器计算每个深度值的统计频率分布,并记录在每个频带中找到的值。然后,它将将这些值与每个频带的阈值进行比较,以确定是否应过滤候选像素。如果任一频带的阈值被打破,则频率最高的像素值作为候选像素的值。
在这我们统计两基带的给候选像素赋值时,没有使用非零像素的统计平均值,这是因为通过查看这些值,我们可以直观地识别滤波器矩阵中可能存在某些对象的边缘。如果我们将所有这些值的平均值应用于候选像素,它将从X、Y透视图中删除噪声,但将沿Z、Y透视图引入噪声;将候选像素的深度放置在两个单独特征之间的一半。通过使用统计模式,我们基本上可以保证为匹配滤波器矩阵中最主要特征的候选像素分配深度。
OPENGL代码实现:
vec4 twoBandFilter(vec2 texCoords) {
//获取得到图像的大小,以及步调的大小
ivec2 size = ivec2(0);
if (isSrcTexture) {
size = textureSize(srcTexture, 0);
} else {
size = textureSize(inTexture, 0);
}
vec2 tex_offset = 1.0 / vec2(size);
//存放统计频率
const int rad = 2;
int count = (rad * 2 + 1) * (rad * 2 + 1) - 1;
//注意,需要动态修改filterCollection的列数,跟count保持一致。
float filterCollection[24][2];
int bandPartion = 2;
//后面使用内频带计数和外频带计数与阈值进行比较
int innerBandCount = 0;
int outerBandCount = 0;
float curDepth = getDepth(texCoords);
float retDepth = curDepth;
//如果像素不是为白点,则直接返回原始的深度值
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;
}
for (int i = 0; i < count; i++) {
if (abs(filterCollection[i][0] - tempDepth) < 0.00001) {
filterCollection[i][1]++;
break;
} else if (abs(filterCollection[i][0] - 0.0) < 0.00001) {
filterCollection[i][0] = tempDepth;
filterCollection[i][1]++;
break;
}
}
if (y < bandPartion && y > -1 * bandPartion && x < bandPartion && x > -1 * bandPartion)
innerBandCount++;
else
outerBandCount++;
}
}
// Once we have determined our inner and outer band non-zero counts, and
// accumulated all of those values, we can compare it against the threshold
// to determine if our candidate pixel will be changed to the
// statistical mode of the non-zero surrounding pixels.
if (innerBandCount >= innerBandThreshold || outerBandCount >= outerBandThreshold)
{
float frequency = 0.0;
float depth = 0.0;
// This loop will determine the statistical mode
// of the surrounding pixels for assignment to
// the candidate.
for (int i = 0; i < count; i++)
{
// This means we have reached the end of our
// frequency distribution and can break out of the
// loop to save time.
if (abs(filterCollection[i][0] - 0.0) < 0.00001)
break;
if (abs(filterCollection[i][1] - frequency) > 0.00001)
{
depth = filterCollection[i][0];
frequency = filterCollection[i][1];
}
}
retDepth = depth;
}
}
return encodeFloatRGBA(retDepth);
}
AREngine深度图优化系列文章:
AREngine深度图优化之一基于最大/最小/平均值的补洞方法
opengl 利用高斯模糊(Gaussian blur/高斯滤波)对tof深度图像进行图像平滑处理
参考文献:
https://www.codeproject.com/Articles/317974/KinectDepthSmoothing