PCL - MLS代碼研讀(十五)- VOXEL_GRID_DILATION上採樣方法

  • 前言
  • 成員變數
  • MLSVoxelGrid
  • MLSVoxelGrid建構子
  • dilate函數
  • getter & setter
  • process函數
  • performUpsampling函數
  • 上採樣結果

前言

PCL - MLS代碼研讀(十一)- computeMLSPointNormal函數,PCL - MLS代碼研讀(十三)- RANDOM_UNIFORM_DENSITY上採樣方法及PCL - MLS代碼研讀(十四)- DISTINCT_CLOUD上採樣方法介紹了五種上採樣方法中的四種,本篇介紹的是最後一種上採樣方法VOXEL_GRID_DILATION

成員變數

以下是與VOXEL_GRID_DILATION上採樣方法相關的成員變數:

/** \brief Voxel size for the VOXEL_GRID_DILATION upsampling method */
//在performUpsampling中會把這個成員變數當作MLSVoxelGrid建構子的參數,用它來設定MLSVoxelGrid裡面的voxel_size_成員變數
float voxel_size_;/** \brief Number of dilation steps for the VOXEL_GRID_DILATION upsampling method */
//dilate次數
int dilation_iteration_num_;

其中voxel_size_代表一個voxel grid的寬度,dilation_iteration_num_代表要做幾次dilation(向外擴張)。

MLSVoxelGrid

MLSVoxelGrid為一代表voxel grids的數據結構。

/** \brief A minimalistic implementation of a voxel grid, necessary for the point cloud upsampling* \note Used only in the case of VOXEL_GRID_DILATION upsampling*/
class MLSVoxelGrid
{public:

voxel grids的葉子節點(有包含點雲中的點的節點):

    //擁有一個"valid"成員變數的structstruct Leaf { Leaf () : valid (true) {} bool valid; };

MLSVoxelGrid的建構子及dilate函數,這兩個函數將留到後面介紹。

    MLSVoxelGrid (PointCloudInConstPtr& cloud,IndicesPtr &indices,float voxel_size);voiddilate ();

索引有一維和三維兩種表示法,以下的兩個函數用於在他們之間做轉換。注意data_size_必須大於等於每個邊的voxel grid數量才能保證這兩個函數的計算結果正確。

    //索引三維轉一維,data_size_必須大於每個邊的voxel grid數量inline voidgetIndexIn1D (const Eigen::Vector3i &index, std::uint64_t &index_1d) const{index_1d = index[0] * data_size_ * data_size_ +index[1] * data_size_ + index[2];}//索引一維轉三維,data_size_必須大於每個邊的voxel grid數量inline voidgetIndexIn3D (std::uint64_t index_1d, Eigen::Vector3i& index_3d) const{index_3d[0] = static_cast<Eigen::Vector3i::Scalar> (index_1d / (data_size_ * data_size_));index_1d -= index_3d[0] * data_size_ * data_size_;index_3d[1] = static_cast<Eigen::Vector3i::Scalar> (index_1d / data_size_);index_1d -= index_3d[1] * data_size_;index_3d[2] = static_cast<Eigen::Vector3i::Scalar> (index_1d);}

用於在三維點坐標和voxel grid索引之間做轉換的函數:

    //查看點p是屬於哪一個voxelinline voidgetCellIndex (const Eigen::Vector3f &p, Eigen::Vector3i& index) const{//計算點p三個維度上各自落在第幾個voxelfor (int i = 0; i < 3; ++i)index[i] = static_cast<Eigen::Vector3i::Scalar> ((p[i] - bounding_min_ (i)) / voxel_size_);}//由voxel的索引得到voxel grid左上角點的位置inline voidgetPosition (const std::uint64_t &index_1d, Eigen::Vector3f &point) const{//先將一維的索引轉成三維Eigen::Vector3i index_3d;getIndexIn3D (index_1d, index_3d);for (int i = 0; i < 3; ++i)//point為index_1d所代表的voxel grid的左上(三個維度中較小的那一側)角點point[i] = static_cast<Eigen::Vector3f::Scalar> (index_3d[i]) * voxel_size_ + bounding_min_[i];}

MLSVoxelGrid的成員變數:

    typedef std::map<std::uint64_t, Leaf> HashMap;HashMap voxel_grid_;//所有voxel grids的邊界Eigen::Vector4f bounding_min_, bounding_max_;//最長邊有多少個voxel gridstd::uint64_t data_size_;//一個voxel grid的寬度float voxel_size_;PCL_MAKE_ALIGNED_OPERATOR_NEW
};

MLSVoxelGrid建構子

在initialization list中設定voxel_size_成員變數:

template <typename PointInT, typename PointOutT>
pcl::MovingLeastSquares<PointInT, PointOutT>::MLSVoxelGrid::MLSVoxelGrid (PointCloudInConstPtr& cloud,IndicesPtr &indices,float voxel_size) :voxel_grid_ (), data_size_ (), voxel_size_ (voxel_size)
{

計算輸入點雲cloud和索引indices的邊界,然後計算得到點雲包圍框的最長邊的邊長,再取data_size_static_cast<std::uint64_t> (1.5 * max_size / voxel_size_)。可以把它想成voxel grids每個維度的grid數量上限。在MLSVoxelGrid中用來做索引一維/三維表達方式轉換的函數(getIndexIn1DgetIndexIn3D)中,就用到了data_size_

  //輸入點雲的邊界為bounding_min_及bounding_max_pcl::getMinMax3D (*cloud, *indices, bounding_min_, bounding_max_);//輸入點雲在三個維度上的長度Eigen::Vector4f bounding_box_size = bounding_max_ - bounding_min_;//輸入點雲包圍框的最長邊const double max_size = (std::max) ((std::max)(bounding_box_size.x (), bounding_box_size.y ()), bounding_box_size.z ());// Put initial cloud in voxel grid//最長的邊有多少個grid,注意是乘上1.5?data_size_ = static_cast<std::uint64_t> (1.5 * max_size / voxel_size_);

遍歷點雲中的每一個點,在該處建立一個能把它包住的Leaf,然後把它加入voxel_grid_這個HashMap中。

  //遍歷點雲中的每一個點,在該處建立一個Leaf,把他們加入voxel_grid_這個HashMap中//注意是有點的地方才有leaf,所以voxel grids可能不是連續的for (std::size_t i = 0; i < indices->size (); ++i)if (std::isfinite ((*cloud)[(*indices)[i]].x)){Eigen::Vector3i pos;//查看點(*cloud)[(*indices)[i]]是屬於哪一個voxelgetCellIndex ((*cloud)[(*indices)[i]].getVector3fMap (), pos);std::uint64_t index_1d;//三維索引轉一維getIndexIn1D (pos, index_1d);Leaf leaf;//為對應的voxel grid加上Leafvoxel_grid_[index_1d] = leaf;}
}

dilate函數

對每一個有點的voxel grid,都往前後左右上下幾個方向擴張。

template <typename PointInT, typename PointOutT> void
pcl::MovingLeastSquares<PointInT, PointOutT>::MLSVoxelGrid::dilate ()
{//對每一個有點的voxel grid,都往前後左右上下共3*3*3-1=26個鄰居擴張.//因為voxel grids可能不是連續的,所以這裡讓存在的grid往外擴張,希望能把洞補起來?//HashMap:由voxel index對應到Leaf的數據結構HashMap new_voxel_grid = voxel_grid_;//遍歷voxel_grid_這個HashMap中存在的每一個格子/遍歷有點的每一個格子for (typename MLSVoxelGrid::HashMap::iterator m_it = voxel_grid_.begin (); m_it != voxel_grid_.end (); ++m_it){//三維的voxel grid索引Eigen::Vector3i index;getIndexIn3D (m_it->first, index);// Now dilate all of its voxels//在三個方向上往左右兩邊新增voxel gridfor (int x = -1; x <= 1; ++x)for (int y = -1; y <= 1; ++y)for (int z = -1; z <= 1; ++z)if (x != 0 || y != 0 || z != 0){//排除(x,y,z)=(0,0,0)的點Eigen::Vector3i new_index;//new_index:index周圍立方體上的點,應該不一定是新的,有可能會找到之前就存在的點?new_index = index + Eigen::Vector3i (x, y, z);std::uint64_t index_1d;getIndexIn1D (new_index, index_1d);Leaf leaf;new_voxel_grid[index_1d] = leaf;}}voxel_grid_ = new_voxel_grid;
}

getter & setter

這幾個MovingLeastSquares類別的public成員函數是voxel_size_dilation_iteration_num_的getter和setter。

/** \brief Set the voxel size for the voxel grid* \note Used only in the VOXEL_GRID_DILATION upsampling method* \param[in] voxel_size the edge length of a cubic voxel in the voxel grid*/
inline void
setDilationVoxelSize (float voxel_size) { voxel_size_ = voxel_size; }/** \brief Get the voxel size for the voxel grid* \note Used only in the VOXEL_GRID_DILATION upsampling method*/
inline float
getDilationVoxelSize () const { return (voxel_size_); }/** \brief Set the number of dilation steps of the voxel grid* \note Used only in the VOXEL_GRID_DILATION upsampling method* \param[in] iterations the number of dilation iterations*/
inline void
setDilationIterations (int iterations) { dilation_iteration_num_ = iterations; }/** \brief Get the number of dilation steps of the voxel grid* \note Used only in the VOXEL_GRID_DILATION upsampling method*/
inline int
getDilationIterations () const { return (dilation_iteration_num_); }

process函數

process函數中,僅將cache_mls_results_設為true後,就調用performProcessing (output)進行上採樣。

template <typename PointInT, typename PointOutT> void
pcl::MovingLeastSquares<PointInT, PointOutT>::process (PointCloudOut &output)
{//...switch (upsample_method_){// Initialize random number generator if necessarycase (RANDOM_UNIFORM_DENSITY):{//...}case (VOXEL_GRID_DILATION):case (DISTINCT_CLOUD):{if (!cache_mls_results_)PCL_WARN ("The cache mls results is forced when using upsampling method VOXEL_GRID_DILATION or DISTINCT_CLOUD.\n");cache_mls_results_ = true;break;}default:break;}//...// Perform the actual surface reconstructionperformProcessing (output);//...
}

performUpsampling函數

performUpsampling函數中實際進行上採樣。

template <typename PointInT, typename PointOutT> void
pcl::MovingLeastSquares<PointInT, PointOutT>::performUpsampling (PointCloudOut &output)
{//...// For the voxel grid upsampling method, generate the voxel grid and dilate it// Then, project the newly obtained points to the MLS surfaceif (upsample_method_ == VOXEL_GRID_DILATION){

corresponding_input_indices_是輸出時會用到的數據結構,在這裡進行reset:

    corresponding_input_indices_.reset (new PointIndices);

初始化MLSVoxelGrid物件並進行dilation_iteration_num_次dilation:

    MLSVoxelGrid voxel_grid (input_, indices_, voxel_size_);for (int iteration = 0; iteration < dilation_iteration_num_; ++iteration)voxel_grid.dilate ();

對每一個有包含點的voxel grid都做以下事情:

    for (typename MLSVoxelGrid::HashMap::iterator m_it = voxel_grid.voxel_grid_.begin (); m_it != voxel_grid.voxel_grid_.end (); ++m_it){

計算得到該voxel grid左上角點的位置:

      // Get 3D position of pointEigen::Vector3f pos;//由voxel的索引得到voxel grid左上角點位置voxel_grid.getPosition (m_it->first, pos);PointInT p;p.x = pos[0];p.y = pos[1];p.z = pos[2];

在輸入點雲中尋找距離該點最近的點,其索引為input_index

      pcl::Indices nn_indices;std::vector<float> nn_dists;tree_->nearestKSearch (p, 1, nn_indices, nn_dists);const auto input_index = nn_indices.front ();

如果該點的投影結果是無效的,則跳過:

      // If the closest point did not have a valid MLS fitting result// OR if it is too far away from the sampled pointif (mls_results_[input_index].valid == false)continue;

獲取該最近鄰的坐標,對它做投影,並加入outputnormals_corresponding_input_indices_等用於輸出的數據結構中:

      Eigen::Vector3d add_point = p.getVector3fMap ().template cast<double> ();MLSResult::MLSProjectionResults proj = mls_results_[input_index].projectPoint (add_point, projection_method_,  5 * nr_coeff_);addProjectedPointNormal (input_index, proj.point, proj.normal, mls_results_[input_index].curvature, output, *normals_, *corresponding_input_indices_);}}
}

上採樣結果

輸入點雲:

dilate次數為0,使用VOXEL_GRID_DILATION方法上採樣的結果:


dilate次數為1,使用VOXEL_GRID_DILATION方法上採樣的結果。相較於上面的結果,可以看到點變得密集些了。但是周圍卻多了一些預期之外的點(可能是bug?)

在更大的尺度下看同一個點雲:上面我們所看到的部分只是整個點雲的一小部分,下面這張圖還未將整個點雲展示完全,因為點雲的尺度是在1e+7這個數量級,相較之下,原始點雲只在1~10這個數量級(這是什麼原因造成的?)。

PCL - MLS代碼研讀(十五)- VOXEL_GRID_DILATION上採樣方法相关推荐

  1. TensorRT/samples/common/argsParser.h源碼研讀

    TensorRT/samples/common/argsParser.h源碼研讀 argsParser.h namespace struct的繼承 caffe特有參數 UFF格式 不需要typedef ...

  2. 三十五例网络故障排除方法

    上网时,我们经常会碰到这样.那样的网络故障,如何应付呢?今天,我们就针对一些常见的故障给大家分析一下! 1.故障现象:网络适配器(网卡)设置与计算机资源有冲突. 分析.排除:通过调整网卡资源中的IRQ ...

  3. 精通Android自定义View(十五)invalidate方法和postInvalidate方法

    1 概述 invalidate方法和postInvalidate方法都是用于进行View的刷新,invalidate方法应用在UI线程中,而postInvalidate方法应用在非UI线程中,用于将线 ...

  4. [C# 基础知识系列]专题十五:全面解析扩展方法

    引言:  C# 3中所有特性的提出都是更好地为Linq服务的, 充分理解这些基础特性后.对于更深层次地去理解Linq的架构方面会更加简单,从而就可以自己去实现一个简单的ORM框架的,对于Linq的学习 ...

  5. SELinux系列(十五)—auditd日志使用方法详解

    auditd 会把 SELinux 的信息都记录在 /var/log/auditd/auditd.log 中. 这个文件中记录的信息会非常多,如果手工查看, 则效率将非常低下.比如笔者的 Linux ...

  6. pd15不能连接oracle11g,PowerDesigner15 使用时的十五个问题附解决方法

    15个问题列表: 一般常用的有CDM,PDM,UML建模,CDM可以转为PDM. 支持正向[生成数据库]和逆向工程[从数据库中生成],并直接关联到到数据库中,PDM可以直接和数据库进行关联,并将数据库 ...

  7. STM32学习心得三十五(上):VS1053实验之RAM测试及正弦测试

    记录一下,方便以后翻阅~ 主要内容: 1) 硬件连接: 2) VS1053简介: 3) 相关实验及其代码解读. 实验功能:程序开启后,系统先进行RAM测试,再进行正弦测试,可以接耳机听到所设的单频声音 ...

  8. suma++[代碼分析一]: 主入口visualizer.cpp

    最近在復現suma++,發現網上沒有相關的注釋和解析suma++,可謂荒漠,看的也是一頭霧水.所以想着看一點記錄一點;   今天嘗試着看代碼,個人認爲首先應該看visualizer目錄的visuali ...

  9. 代沐研:渡尽劫波非农在,空头有望脱苦海

    代沐研:渡尽劫波非农在,空头有望脱苦海 有所不为才能有所为,有时候行动多并不一定就效果好.有时什么也不做,就是一种最好的选择.不要担心错失机会,善猎者必善等待.在没有大机会的时候,要安静的如一块石头. ...

最新文章

  1. vector/list/map/set的插入、删除、遍历 - remove\erase函数
  2. FB接连出事儿?上亿用户记录在亚马逊云服务器上就公之于众了……下滑到第七?领英说苹果怎么就不受雇员欢迎了呢? | 极客头条...
  3. 泥鳅般的const(一个小Demo彻底搞清楚)
  4. 从电子电路到嵌入式系统(开篇)
  5. Leetcode106 由中序序列和后序序列构建二叉树
  6. ArcView Image Analyst v1.0.rar
  7. 手机三十分钟熄屏如何一直亮_如何让手机屏幕常亮
  8. 用友T1商贸宝批发零售版SQL SERVER数据库恢复
  9. iframe自动播放
  10. ReentrantLock使用及其原理解析
  11. 无法解析的外部符号 _transfer_8to16copy_3dne
  12. 自然语言处理hanlp------8AC自动机
  13. 一篇文章从0搞定计算机网络,面试小case
  14. 关于ASP使用服务器采集文章及图片
  15. 第十三届蓝桥杯大赛软件类国赛 C/C++ 大学B组 试题 G: 故障
  16. 使用Python,OpenCV获取、更改像素,修改图像通道,剪裁ROI
  17. 【ChatGPT】| 最全七大场景50+小场景应用指南合集——内部指导版本(AI训练师必备,带案例)
  18. 虚拟机配置windows7+office2010
  19. R语言patchwork包将多个ggplot2可视化结果组合起来、使用plot_annotation函数以及tag_level参数为组合图添加自定义编码序列(字符向量列表)
  20. linux 共享内存 shmget

热门文章

  1. Python 自动控制原理 control
  2. 古币杂谈:清十二帝之 清文宗 爱新觉罗·奕詝【咸丰】
  3. ElasticSearch学习_陶文1_时间序列数据库的秘密(1)—— 介绍
  4. 自动驾驶(三十七)---------视觉SLAM(资料介绍)
  5. c语言从txt文本读取数据
  6. 慢行优先—老城区道路改造中的设计适配与转向
  7. Elasticsearch最佳实践之Index与Shard设计
  8. 爱你所爱,行你所行,听从你心
  9. torch的Variable
  10. 【程序员】区区英语算什么,还搞不定了?