結構化的室內場景建模_過濾點雲中紅外光強度過高和過低的點

  • 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