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. 分享一个基于 Shiro 的权限管理系统,亮点是支持 restful 风格 URL.
  2. 谨记!怎么样的编程会让你进监狱?
  3. Python编程基础:第八节 判断语句If Statements
  4. linux 文本编辑命令grep sed awk
  5. 指针和引用的区别和联系
  6. webserver之使用数组实现阻塞队列
  7. Bootstrap3 滚动监听插件的调用方式
  8. UI设计素材模板|wireframe线框图设计要点
  9. 深度神经网络训练过程中为什么验证集上波动很大_图神经网络的新基准
  10. SAP ERP与国内ERP系统的对比,为什么建议选SAP
  11. 另类SEO优化推广之百度下拉词框优化推广是怎么做的?
  12. spellcheck 属性 html5的新属性,对元素内容进行拼写检查
  13. sql在select中添加内容为空的字段
  14. 2019年-2020年计划
  15. 专升本第一讲(计算机的“前世今生”)
  16. Windows 撤销快捷键“ctrl+z“失效解决方法
  17. 如何修改word2016模板
  18. I. chino with mates
  19. springcontext.xml 中方言是红色的_人文黄岩 魅力方言
  20. 日语动词活用之假定形

热门文章

  1. 计算机使用计划任务,使用任务计划设置电脑定时关机的方法
  2. 毕业设计之 --- 基于机器视觉的手势检测和识别算法
  3. postgre函数007—to_char使用
  4. csdn涨薪技术之Docker 使用教程
  5. 【JS】1531- 20 个 JS 工具函数助力高效开发
  6. C 语言三棱锥体积的代码,山西省太原市2018届高三3月模拟考试数学(理)试题(一)含答案...
  7. 织梦各个文件/文件夹的介绍
  8. 上海注册合伙公司相关规定和材料
  9. mysql groupBy 按日期分组
  10. P3493 [POI2009]WSP-Island(贪心,半平面交)