结构化的室内场景建模_过滤点云中红外光强度过高和过低的点

  • 2019 年 11 月 1 日
  • 筆記

上篇文章

在论文 “Structured Indoor Modeling” 的补充文档中,作者提到了数据集的预处理方法:Intensity-based FilteringConnected Component Filtering

Structured Indoor Modeling Project Website https://www2.cs.sfu.ca/~furukawa/sim/

我将会写两篇文章介绍这两个 Filter,并以继承 PCL 过滤工具 Filter 类的形式作为我的实现方式。

先看作者提到的第一个 Filter: Intensity-based Filtering

这个 Filter 的字面意思是按照光照强度来过滤点云。在我之前的一篇文章中提到,以深度摄像头为采集设备的数据集中有一个属性 intensity

intensity 值的理解 无雨森,公众号:无雨森的技术分享KinectAzureDK编程实战_用OpenCV、PCL操作和可视化Kinect数据

深度摄像头上的 “红外光投影仪” 投影 “红外光点” 到实际场景中。深度摄像头的 “红外光接收器” 接收实际场景反射过来的红外光。

这里没有找到 Azure Kinect 投影红外光点到实际场景的图,我们看一下 Kinect 1代的在夜视情况下看到的红外光点的情况[5]。

既然是光,对于镜面反射比较强的地方,比如光滑的桌面,镜子,显示器,玻璃窗户等等,就会出现光点很强或很暗的情况。

想象我拿着一个手电筒正面直直的照向一面镜子,强光会反射到我眼里。

换成红外光,深度摄像头的红外接收器很可能解析不了强红外光,给其一个 nan 值。如下图[1]所示。关于 nan 值的讲述,请参见我的上篇文章。

点云中 nan 值的理解 无雨森,公众号:无雨森的技术分享结构化的室内场景建模_预处理

或者给这些红外光点很高的 intensity 值。

如果红外光照向的是反光很强的物体,那么 “红外接收器” 接收到的红外光信号强度不够,则会使该深度图的像素示效,也会置一个 nan 值。或者给其一个很小的 intensity 值。如下图[2]所示。

Intensity-based Filtering 这个 Filter 的目的就是过滤掉这些过小和过大的 intensity 值。

在计算机图形学和计算机视觉算法中,常常使用 "高斯分布" 来描述一组点的分布。因为深度摄像头投影出的红外光照向实际场景时,光点足够多,红外光照向的场景是相互独立且随机的,所以可以把红外光点的强度值的分布近似的看作 ”高斯分布“。如下图[3]。

根据高斯分布的特性[4],以中值 mean 为中轴,向左向右扩展 1 个标准差,2 个标准差,3 个标准差分别对应 68%95%99.7%的数据(曲线下范围内的面积占曲线下总面积的比例)。

按照这个思想,我们只需要求出需要过滤的点云中所有点的光照强度 intensity 值的中值 mean 和 标准差 stddev。然后按照我们想过滤的范围,设定左右扩展的标准差的个数,即可过滤掉 intensity 值过高和过低的点。

继承自 PCL 的过滤工具类 FilterIndicesIntensityOutlierRemoval 类。

过滤工具类 FilterIndices 类继承自基类 Filter。比如 PCL 中众多的点云过滤类,比如 Voxel Grid FilterBilateral Filter 等。

这里实现的 IntensityOutlierRemoval 类似于 PCL 中的 Pass Through FilterPass Through Filter 类通过提供特定需要过滤的属性范围来过滤点云。比如,需要保留 z 值范围在 [0.1, 0.5] 之间的点云。

IntensityOutlierRemoval 过滤的是 intensity 特定范围外的点。

即上述代码中的 filter_field_name_。设定其

filter_field_name_ = "intensity";

另外,我们还需要设定中值左右扩展的标准差的个数 std_mul_

直接看过滤的函数 applyFilterIndices()

取出点云所有有效点的 intensity 值存储在一个数组中。

for (int iii = 0; iii < static_cast<int>(indices_->size()); ++iii)  {      const uint8_t *pt_data = reinterpret_cast<const uint8_t*>(&input_->points[iii]);      memcpy(&distances[iii], pt_data + fields[distance_idx].offset, sizeof(float));  }

然后求出点云所有点的 intensity 值的中值 mean 和标准差 stddev

并设定左右两个范围 distance_threshold_lowdistance_threshold_high

double mean = 0;  double stddev = 0;  pcl::getMeanStd(distances, mean, stddev);  distance_threshold_low  = mean - std_mul_ * stddev;  distance_threshold_high = mean + std_mul_ * stddev;

我们测试一下 IntensityOutlierRemoval。这里设定标准差扩展范围是 2 个标准差,读取的文件夹保存的是我上篇文章中提前处理成 organized 的点云。具体转换方式,详见上篇文章。

organized 点云转换方式 无雨森,公众号:无雨森的技术分享结构化的室内场景建模_预处理

在过滤点云前,我们需要先把 organized 点云中的所有 nan 点剔除。因为这些点的 intensity 值也是无效的。所以点云中的 nan 点都不能进入过滤以及将来的运算过程。

先看一下原始的所有点云叠加起来是什么样的效果。

本文片头说过,在镜面反射比较强的地方会出现大量这样的 intensity 值异常的点。比如窗户,镜子之类的。如下图。红外光在照向窗户时,会通过玻璃射向窗外,反射回来的光强会降低很多。这部分点云就是我们需要过滤的 intensity 值过低的点。

看一下过滤的效果。

如果红外光直射镜面反射强的地方,红外接收器也会接收到很高光强的红外光。如下图所示。红框标记出来的地方有几片点。很明显,这些就是需要过滤的 intensity 值过高的点。

看一下过滤的效果。红框标记出来的这几片点云过滤效果非常明显。

引用

[1] https://docs.microsoft.com/zh-cn/azure/Kinect-dk/media/concepts/depth-camera-invalidation-saturation.png

[2] https://docs.microsoft.com/zh-cn/azure/Kinect-dk/media/concepts/depth-camera-invalidation-low-signal.png

[3] https://www.statisticshowto.datasciencecentral.com/wp-content/uploads/2013/09/standard-normal-distribution.jpg

[4] https://www.mathsisfun.com/data/standard-normal-distribution.html

[5] https://www.buzzfeed.com/southafrican/kinect-filmed-with-a-night-vision-camera-17vf