从GitHub的代码版本库下载源代码https://github.com/PointCloudLibrary/pcl,用CMake生成VS项目,查看PCL的源码位于pcl_features项目下
1.Feature类:
template <typename PointInT, typename PointOutT>   class Feature : public PCLBase<PointInT>
注意 Feature是一个泛型类,有一个compute方法。
 template <typename PointInT, typename PointOutT> void pcl::Feature<PointInT, PointOutT>::compute (PointCloudOut &output)
{
if (!initCompute ())
{
output.width = output.height = ;
output.points.clear ();
return;
}
// Copy the header
output.header = input_->header;
// Resize the output dataset
if (output.points.size () != indices_->size ())
output.points.resize (indices_->size ());
// Check if the output will be computed for all points or only a subset
// If the input width or height are not set, set output width as size
if (indices_->size () != input_->points.size () || input_->width * input_->height == )
{
output.width = static_cast<uint32_t> (indices_->size ());
output.height = ;
}
else
{
output.width = input_->width;
output.height = input_->height;
}
output.is_dense = input_->is_dense;
// Perform the actual feature computation
computeFeature (output);
deinitCompute ();
}

2.注意computeFeature (output);方法 ,可以知道这是一个私有的虚方法。

 private:
      /** \brief Abstract feature estimation method.
        * \param[out] output the resultant features    */
      virtual void    computeFeature (PointCloudOut &output) = 0;
3.查看Feature的继承关系可以知道
template <typename PointInT, typename PointOutT>   class NormalEstimation: public Feature<PointInT, PointOutT>
NormalEstimation类是Feature模板类的子类,因此执行的是NormalEstimation类的computeFeature方法。查看computeFeature方法:
 template <typename PointInT, typename PointOutT> void pcl::NormalEstimation<PointInT, PointOutT>::computeFeature (PointCloudOut &output)
{
// Allocate enough space to hold the results
// \note This resize is irrelevant for a radiusSearch ().
std::vector< int> nn_indices (k_);
std::vector< float> nn_dists (k_);
output.is_dense = true;
// Save a few cycles by not checking every point for NaN/Inf values if the cloud is set to dense
if (input_->is_dense)
{
// Iterating over the entire index vector
for (size_t idx = ; idx < indices_->size (); ++idx)
{
if (this ->searchForNeighbors ((*indices_)[idx], search_parameter_, nn_indices, nn_dists) == ||
!computePointNormal (*surface_, nn_indices, output.points[idx].normal[], output.points[idx].normal[], output.points[idx].normal[], output.points[idx].curvature))
{
output.points[idx].normal[] = output.points[idx].normal[] = output.points[idx].normal[] = output.points[idx].curvature = std::numeric_limits<float >::quiet_NaN ();
output.is_dense = false;
continue;
} flipNormalTowardsViewpoint (input_->points[(*indices_)[idx]], vpx_, vpy_, vpz_, output.points[idx].normal[], output.points[idx].normal[], output.points[idx].normal[]);
}
}
else
{
// Iterating over the entire index vector
for (size_t idx = ; idx < indices_->size (); ++idx)
{
if (!isFinite ((*input_)[(*indices_)[idx]]) ||
this->searchForNeighbors ((*indices_)[idx], search_parameter_, nn_indices, nn_dists) == ||
!computePointNormal (*surface_, nn_indices, output.points[idx].normal[], output.points[idx].normal[], output.points[idx].normal[], output.points[idx].curvature))
{
output.points[idx].normal[] = output.points[idx].normal[] = output.points[idx].normal[] = output.points[idx].curvature = std::numeric_limits<float >::quiet_NaN (); output.is_dense = false;
continue;
}
flipNormalTowardsViewpoint (input_->points[(*indices_)[idx]], vpx_, vpy_, vpz_, output.points[idx].normal[], output.points[idx].normal[], output.points[idx].normal[]);
}
}
}

4.因此分析NormalEstimation的算法流程如下:

    (1)进行点云的初始化initCompute
  (2)初始化计算结果输出对象output
  (3)计算点云法向量,具体由子类的computeFeature方法实现。先搜索近邻searchForNeighbors ,然后计算computePointNormal
    采用的方法是PCA主成分分析法。
    参考文献:《Semantic 3D Object Maps for Everyday Manipulation in Human Living Environments》 P45-49
    点云的法向量主要是通过点所在区域的局部拟合的表面进行计算。平面通过一个点和法向量进行表示。对于每一个点Pi,对应的协方差矩阵C
    
    关于主成份分析的基本原理和算法流程参考:http://blog.csdn.net/lming_08/article/details/21335313
  (4)flipNormalTowardsViewpoint 法向量定向,采用方法是:使法向量的方向朝向viewpoint。
5.NormalEstimation模板类的重载方法computeFeature分析,computePointNormal分析。
  inline bool computePointNormal (const pcl::PointCloud<PointInT> &cloud, const std::vector<int> &indices,
float &nx, float &ny, float &nz, float &curvature)
{
if (indices.size () < ||
computeMeanAndCovarianceMatrix (cloud, indices, covariance_matrix_, xyz_centroid_) == )
{
nx = ny = nz = curvature = std::numeric_limits<float>::quiet_NaN ();
return false;
} // Get the plane normal and surface curvature
solvePlaneParameters (covariance_matrix_, nx, ny, nz, curvature);
return true;
}
computeMeanAndCovarianceMatrix主要是PCA过程中计算平均值和协方差矩阵,在类centroid.hpp中。
而solvePlaneParameters方法则是为了求解特征值和特征向量。代码见feature.hpp。具体实现时采用了pcl::eigen33方法。
 inline void pcl::solvePlaneParameters (const Eigen::Matrix3f &covariance_matrix,
float &nx, float &ny, float &nz, float &curvature)
{
// Avoid getting hung on Eigen's optimizers
// for (int i = 0; i < 9; ++i)
// if (!pcl_isfinite (covariance_matrix.coeff (i)))
// {
// //PCL_WARN ("[pcl::solvePlaneParameteres] Covariance matrix has NaN/Inf values!\n");
// nx = ny = nz = curvature = std::numeric_limits<float>::quiet_NaN ();
// return;
// }
// Extract the smallest eigenvalue and its eigenvector
EIGEN_ALIGN16 Eigen::Vector3f::Scalar eigen_value;
EIGEN_ALIGN16 Eigen::Vector3f eigen_vector;
pcl::eigen33 (covariance_matrix, eigen_value, eigen_vector);

nx = eigen_vector [];
ny = eigen_vector [];
nz = eigen_vector []; // Compute the curvature surface change
float eig_sum = covariance_matrix.coeff () + covariance_matrix.coeff () + covariance_matrix.coeff ();
if (eig_sum != )
curvature = fabsf (eigen_value / eig_sum);
else
curvature = ;
}

6.法向量定向

见normal_3d.h文件中,有多个覆写方法。摘其一:

  /** \brief Flip (in place) the estimated normal of a point towards a given viewpoint
* \param point a given point
* \param vp_x the X coordinate of the viewpoint
* \param vp_y the X coordinate of the viewpoint
* \param vp_z the X coordinate of the viewpoint
* \param nx the resultant X component of the plane normal
* \param ny the resultant Y component of the plane normal
* \param nz the resultant Z component of the plane normal
* \ingroup features
*/
template <typename PointT> inline void
flipNormalTowardsViewpoint (const PointT &point, float vp_x, float vp_y, float vp_z,
float &nx, float &ny, float &nz)
{
// See if we need to flip any plane normals
vp_x -= point.x;
vp_y -= point.y;
vp_z -= point.z; // Dot product between the (viewpoint - point) and the plane normal
float cos_theta = (vp_x * nx + vp_y * ny + vp_z * nz); // Flip the plane normal
if (cos_theta < )
{
nx *= -;
ny *= -;
nz *= -;
}
}

运行的实例结果:

[PCL]2 点云法向量计算NormalEstimation的更多相关文章

  1. 29 基于PCL的点云平面分割拟合算法技术路线(针对有噪声的点云数据)

    0 引言 最近项目中用到了基于PCL开发的基于平面的点云和CAD模型的配准算法,点云平面提取采用的算法如下. 1 基于PCL的点云平面分割拟合算法 2 参数及其意义介绍 (1)点云下采样 1. 参数: ...

  2. [CC]点云密度计算

    包括两种计算方法:精确计算和近似计算(思考:local density=单位面积的点数 vs  local density =1/单个点所占的面积) 每种方法可以实现三种模式的点云密度计算,CC里面的 ...

  3. 阿里云流计算专场-GitHub上相关文档

    阿里云流计算专场-GitHub路径:https://github.com/Alibaba-Technology/hangzhouYunQi2017ppt

  4. 荣获“5G MEC优秀商用案例奖”,阿里云边缘计算发力新零售

    4月24日,在中国联通合作伙伴大会的 “5G MEC(Mobile Edge Computing,移动边缘计算)边缘云赋能行业数字化转型”分论坛上,阿里云“基于5G边缘计算的新零售应用案例”荣获201 ...

  5. 阿里云函数计算 .NET Core 初体验

    体验了一波阿里云函数计算, 已支持 .NET Core 2.1, 那么按照惯例, 来写个 "Hello World" 吧. 作者注: 开发环境 Windows 10 & V ...

  6. 阿里云函数计算上部署.NET Core 3.1

    使用阿里云ECS或者其他常见的VPS服务部署应用的时候,需要手动配置环境,并且监测ECS的行为,做补丁之类的,搞得有点复杂.好在很多云厂商(阿里云.Azure等)提供了Serverless服务,借助于 ...

  7. 阿里云函数计算 VSCode 使用,及部署 Docusaurus

    代码: https://github.com/ikuokuo/start-serverless 使用简介 产品页开通服务.使用流程,如下: 新手示例,如下: 创建函数 阿里云提供了如下几种方式创建函数 ...

  8. 对端边缘云网络计算模式:透明计算、移动边缘计算、雾计算和Cloudlet

    对端边缘云网络计算模式:透明计算.移动边缘计算.雾计算和Cloudlet 概要 将数据发送到云端进行分析是过去几十年的一个突出趋势,推动了云计算成为主流计算范式.然而,物联网时代设备数量和数据流量的急 ...

  9. 独家对话阿里云函数计算负责人不瞋:你所不知道的 Serverless

    作者 | 杨丽 出品 | 雷锋网产业组 "Serverless 其实离我们并没有那么遥远". 如果你是一名互联网研发人员,那么极有可能了解并应用过 Serverless 这套技术体 ...

随机推荐

  1. Git Shell使用笔记

    1,首次打开Git shell错误(以前打开过gethub客户端) 警告: git command could not be found. Please create an alias or add ...

  2. 查找文件是否安装以及安装路径(Ubuntu 下 )

    参考:<linux下如何查看某个软件 是否安装??? 安装路径在哪???> 原文: 如果你使用rpm -ivh matlab装的, 用rpm -qa | grep matlab肯定是能够找 ...

  3. vi 编辑器常用命令

    VI编辑器可以分为3种状态,它们分别是命令模式.输入模式以及末行模式,VI运行后默认进入命令模式. 命令模式:控制屏幕光标的移动,字符.单词或行的删除.替换,复制粘贴数据以及由此进入插入模式和末行模式 ...

  4. ios-指纹识别

    - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event { //1. 判断系统版本 if ( ...

  5. 大话数据结构(十二)java程序——KMP算法及改进的KMP算法实现

    1.朴素的模式匹配算法 朴素的模式匹配算法:就是对主串的每个字符作为子串开头,与要连接的字符串进行匹配.对主串做大循环,每个字符开头做T的长度的小循环,直到成功匹配或全部遍历完成为止. 又称BF算法 ...

  6. OpenGL 完全教程(写给Delphi的开发者) 前言

    前言 在开发了许多2D图形程序之后,许多人开始对3D图形编程产生了兴趣.学习一套3D API,是进行3D图形编程的基础.在有趣的3D图形编程中,3D API只不过充当着一种低级的工具而已.因此,在这里 ...

  7. js 和 jquery 获取页面和滚动条的高度 视口高度文档高度

    js 和 jquery 获取页面和滚动条的高度 //页面位置及窗口大小 function GetPageSize() { var scrW, scrH; if(window.innerHeight & ...

  8. nRF51822之app_button控制uart的开启和关闭

    为什么要使用app_button来控制uart的开启和关闭 还是先上datesheet中uart开启的时候需要HFCLK,需要消耗大量大电流.所以在我们需要的时候需要通过io来通知nrf51822开启 ...

  9. zepto源码--init--学习笔记

    先展示init函数,由于笔记本屏幕太小,删掉了部分源码注释,才能在一屏内截图. 当我们调用$()的时候,便会直接调用zepto.init()生成zepto对象,跟jquery生成jquery对象类似. ...

  10. android通过pc脚本执行sqlite3脚本

    最近在调研市面上的一些android db框架,需要经常重复的输入一堆比如 adb shell cd /data/data/com.example.testandroiddb/databases sq ...