結構化的室內場景建模_過濾點雲中紅外光強度過高和過低的點
- 2019 年 11 月 1 日
- 筆記
在論文 「Structured Indoor Modeling」 的補充文檔中,作者提到了數據集的預處理方法:Intensity-based Filtering 和 Connected 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 的過濾工具類 FilterIndices 的 IntensityOutlierRemoval 類。
過濾工具類 FilterIndices 類繼承自基類 Filter。比如 PCL 中眾多的點雲過濾類,比如 Voxel Grid Filter,Bilateral Filter 等。
這裡實現的 IntensityOutlierRemoval 類似於 PCL 中的 Pass Through Filter。Pass 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_low 和 distance_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