本文章参考Being_young,博客地址为http://blog.csdn.net/u013019296/article/
3D点云特征描述与提取是点云信息处理中的最基础也是最关键的一部分,点云的识别、分割、重采样、配准、曲面重建等处理大部分算法,都严重依赖特征描述与提取的结果。
从尺寸上来分,一般分为局部特征描述和全局特征描述,例如局部的法线、等几何形状特征的描述,全局的拓扑特征的描述,都属于3D点云特征描述与提取的范畴。
利用描述子建立曲面间的对应点在3D物体识别领域有广泛的应用,采用一个向量描述曲面上指定点及邻域的形状特征,通过匹配向量的值来建立不同曲面点的对应关系,此相邻则称为指定点的描述子,经典描述子的3D形状内容描述子结构简单,辨别力强,且对噪声不敏感。
Spin image是基于点云空间分布的最经典的特征描述方法。
自旋图是一种局部表面描述算子,他给出了在感兴趣点的局部环境中数据集的旋转平移不变量。
使用不规则三角形网格来描述三维物体形状。网格中的顶点连同该点的法向量称为有向点(Oriented point),一个有向点建立一个局部坐标系,使得周围的点可以向该坐标系投影。
Spin image的思想是将一定区域的点云分布转换为二维的spin image,然后对场景和模型的spin images进行相似性度量。原理图如下:
P--------三维网格某顶点P的切面
n--------p点的单位法向量
x--------p附近的三维网格上的另一个顶点
α--------x点在P上的投影与点p之间的距离
β--------x点与P的垂直距离
其中p和n定义为一个定向点(Oriented point)。
1.定义一个Oriented point
2. 以Oriented point为轴生成一个圆柱坐标系。
3. 定义Spin image的参数,Spin image是一个具有一定大小(行数列数)、分辨率(二维网格大小)的二维图像(或者说网格)。
4. 将圆柱体内的三维坐标投影到二维的Spin image,这一过程可以理解为一个Spin image绕着法向量n旋转360度,Spin image扫到的三维空间的点会落到Spin image的网格中。就是如下的公式:
当网格表面一定范围内的所有顶点都使用上式向有向点p定义的坐标系投影时,得到点p的自旋图。由于自旋图描述的是同一目标上不同点之间相对位置关系,它不受目标平移,旋转等变换的影响。
5. 根据spin image中的每个网格中落入的点不同,计算每个网格的强度I,显示spin image时以每个网格(也就是像素)I不同为依据。最直接的方法是直接计算每个网格中落入的点,然而为了降低对位置的敏感度降低噪音影响增加稳定性,Johnson论文中用双线性插值的方法将一个点分布到4个像素中。原理如下图:
上图中,默认的网格(像素)边长是1(真实边长的选择会在稍后讨论),当一个点落入网格(i,j)中时会被双线性插值分散到(i,j)、(i,j+1)、(i+1,j)、(i+1,j+1)四个网格中。
这样就获得了spin image,如下图所示。
1. 分辨率,即二维网格的也就是像素的实际尺寸,使用和三维网格相近的尺寸比较合适,因此通常是取三维网格所有边的平均值来作为spin image的每个网格尺寸,通常会把网格的长和宽定义成相等,即边长,边长的计算公式:
e为三维网格模型中的一条边,N为三维网格模型中的边的总数。
2.大小,即spin image的行数和列数,两者一般也相等。可以参考的大小10x10或20x20等。
3.support angle,即法向量夹角的大小限制。空间中顶点的法向量与创建圆柱坐标系所选点法向量之间的夹角。效果如下图:
可以看出,对角度限制以后,那些相当于切面的“凹点(大于90°)”被剔除,保留了主要信息,降低了后续的计算量。一般角度限制范围为60°–90°之间。
1.相似性度量
使用以下公式来计算两个spin images之间的相似性:
其中R的计算公式:
N为每个spin image像素数,atanh为反双曲正切函数,其输入的范围[-1,1],原文中解释为这是一种典型的统计学手段。R的取值范围是[-1,1],两个spin images越相似R越接近于1,完全一样时R的值为1。
可以看出C由两部分组成第一部分是经反双曲正切函数得出的值的平方,第二部分是一个权重λ乘以一个较小的数,当两个spin images相似时第二部分所占比重应较小,当不接近时第二部分所占比重应较大,λ起的作用是用来限制spin images低重合时匹配的情况。文中对λ的选择方式是将所有的spin images中的非空像素数按大小顺序列出来然后取中位数。这个中位数差不多是像素重叠的期望值。然后考虑到低重叠的情况,取这个中位数的一半来作为λ。
理论基础:
在原始表示形式之下,点的定义是用笛卡尔坐标系坐标 x, y, z 相对于一个给定的原点来简单表示的三维映射系统的概念,假定坐标系的原点不随着时间而改变,这里有两个点p1和p2分别在时间t1和t2捕获,有着相同的坐标,对这两个点作比较其实是属于不适定问题(ill—posed problem),因为虽然相对于一些距离测度它们是相等的,但是它们取样于完全不同的表面,因此当把它们和临近的其他环境中点放在一起时,它们表达着完全不同的信息,这是因为在t1和t2之间局部环境有可能发生改变。一些获取设备也许能够提供取样点的额外数据,例如强度或表面反射率等,甚至颜色,然而那并不能完全解决问题,单从两个点之间来 对比仍然是不适定问题。由于各种不同需求需要进行对比以便能够区分曲面空间的分布情况,应用软件要求更好的特征度量方式,因此作为一个单一实体的三维点概念和笛卡尔坐标系被淘汰了,出现了一个新的概念取而代之:局部描述子(locl descriptor)。文献中对这一概念的描述有许多种不同的命名,如:形状描述子(shape descriptors)或几何特征(geometric features),文本中剩余部分都统称为点特征表示。通过包括周围的领域,特征描述子能够表征采样表面的几何 性质,它有助于解决不适定的对比问题,理想情况下相同或相似表面上的点的特征值将非常相似(相对特定度量准则),而不同表面上的点的特征描述子将有明显差异。下面几个条件,通过能否获得相同的局部表面特征值,可以判定点特征表示方式的优劣:
(1) 刚体变换-----即三维旋转和三维平移变化 不会影响特征向量F估计,即特征向量具有平移选转不变性。
(2) 改变采样密度-----原则上,一个局部表面小块的采样密度无论是大还是小,都应该有相同的特征向量值,即特征向量具有抗密度干扰性。
(3) 噪声—数据中有轻微噪声的情况下,点特征表示在它的特征向量中必须保持相同或者极其相似的值,即特征向量对点云噪声具有稳定性。
通常,PCL中特征向量利用快速kd-tree查询 ,使用近似法来计算查询点的最近邻元素,通常有两种查询类型:K邻域查询,半径搜索两中方法
一旦确定邻域以后,查询点的邻域点可以用来估计一个局部特征描述子,它用查询点周围领域点描述采样面的几何特征,描述几何表面图形的一个重要属性, 首先是推断它在坐标系中的方位,也就是估计他的法线,表面法线是表面的一个重要的属性,在许多领域都有重要的应用,如果用光源来生成符合视觉效果的渲染等,
1. 以下代码:
(实现对输入点云数据集中的点估计一组表面法线)执行的操作是:对应点云P中每一个点p得到p点最近邻元素,计算p点的表面的法线N,检查N的方向是否指向视点如果不是则翻转。
#include
#include
#include //法线估计类头文件
#include
#include
#include
#include
#include
#include
#include
#include
#include
VTK_MODULE_INIT(vtkRenderingOpenGL);
using namespace std;
using namespace pcl;
//可视化点云法线
boost::shared_ptr<visualization::PCLVisualizer> normalsVis(PointCloud<PointXYZ>::ConstPtr cloud, PointCloud<Normal>::ConstPtr normals)
{
//创建可视化窗口
boost::shared_ptr<visualization::PCLVisualizer> viewer(new visualization::PCLVisualizer("3D Viewer"));
viewer->setBackgroundColor(0, 0, 0);
//添加数据
viewer->addPointCloud<PointXYZ>(cloud,"sample cloud");
//设置渲染模式
viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 3, "sample cloud");
//实现对点云法线的显示
viewer->addPointCloudNormals<PointXYZ, Normal>(cloud, normals, 10, 0.15, "normals");
viewer->addCoordinateSystem(1.0);
viewer->initCameraParameters();
return (viewer);
}
//点云显示
boost::shared_ptr<pcl::visualization::PCLVisualizer> simpleVis(pcl::PointCloud<pcl::PointXYZ>::ConstPtr cloud)
{
/*
open 3D viewer and add point cloud
*/
//创建视窗对象并给标题栏设置一个名称“3D Viewer”并将它设置为boost::shared_ptr智能共享指针,这样可以保证指针在程序中全局使用,而不引起内存错误。
boost::shared_ptr<visualization::PCLVisualizer> viewer(new visualization::PCLVisualizer("3D Viewer"));
//设置窗体的颜色
viewer->setBackgroundColor(0, 0, 0);
//将点云添加到视窗对象中
/*
将点云添加到视窗对象中,并定义一个唯一的字符串作为ID号,
利用此字符串保证在其他成员中也能标志引用该点云,多次调用addPointCloud可以实现多个点云的添加,每调用一次,就会创建一个新的ID号
如果想更新一个一已经显示的点云,必须先调用removePointCloud() ,并提供要更新的点云的ID号。
*/
viewer->addPointCloud<PointXYZ>(cloud, "sample cloud");
//用以改变显示点云的尺寸,利用该方法可以控制点云在视窗中的显示方式。
/** \brief Set the rendering properties of a PointCloud 设置点云的呈现属性
* \param[in] property the property type
* \param[in] value the value to be set
* \param[in] id the point cloud object id (default: cloud)
* \param[in] viewport the view port where the Point Cloud's rendering properties should be modified (default: all)
*/
viewer->setPointCloudRenderingProperties(visualization::PCL_VISUALIZER_POINT_SIZE, 1, "sample cloud");
/*
查看复杂的点云经常让人感觉没有方向感,为了保证正确的坐标判断,需要显示坐标系统方向,可以使用x(红色) Y(绿色) Z(蓝色)
圆柱体代表坐标轴的显示方式来解决。圆柱体的大小可以通过scale参数来控制,本例中scale设置为1.0
*/
viewer->addCoordinateSystem(1.0);
//通过设置照相机参数,使得从默认的角度和方向观察点云
viewer->initCameraParameters();
return viewer;
}
int main()
{
//定义点云
PointCloud<PointXYZ>::Ptr cloud(new PointCloud<PointXYZ>);
//载入点云数据
io::loadPCDFile("rabbit.pcd",*cloud);
//for (float z(-1.0); z <= 1.0; z += 0.05)
//{
// for (float angle(0.0); angle <= 360.0; angle += 5.0)
// {
// PointXYZ basic_point;
// basic_point.x = 0.5*cos(deg2rad(angle)); //cosf 求弧度值的余弦值。针对float型的
// basic_point.y = sin(deg2rad(angle));
// basic_point.z = z;
// cloud->points.push_back(basic_point);
// }
//}
//cloud->width = (int)cloud->points.size();
//cloud->height = 1;
//创建法线估计估计向量
NormalEstimation<PointXYZ, Normal> ne;
ne.setInputCloud(cloud);
//创建一个空的KDTree对象,并把它传递给法线估计向量
search::KdTree<PointXYZ>::Ptr tree(new search::KdTree<PointXYZ>());
ne.setSearchMethod(tree);
//存储输出的数据
PointCloud<Normal>::Ptr cloud_nomals(new PointCloud<Normal>);
//使用半径在查询点周围3厘米范围内的所有临近元素
ne.setRadiusSearch(0.8);
//计算特征值
ne.compute(*cloud_nomals);
//创建可视化窗口
boost::shared_ptr<visualization::PCLVisualizer> viewer;
viewer = normalsVis(cloud,cloud_nomals);
//viewer = simpleVis(cloud);
while (!viewer->wasStopped())
{
viewer->spinOnce(100);
boost::this_thread::sleep(boost::posix_time::microseconds(100000));
}
return 0;
}
(2)估计一个点云的表面法线
表面法线是几何体表面一个十分重要的属性,例如:在进行光照渲染时产生符合可视习惯的效果时需要表面法线的信息才能正常进行,对于一个已经已经知道的几何体表面,根据垂直于点表面的的矢量,因此推推处表面某一点的法线方向比较容易,然而由于我们获取的点云的数据集在真实的物体的表面表现为一组定点的样本,这样就会有两种方法解决:
1 . 使用曲面重建技术,从获取的点云数据中得到采样点对应的曲面,然后从曲面模型中计算出表面法线
2.直接从点云数据中近似推断表面法线
在确定表面一点法线的问题近似于估计表面的一个相切面法线的问题,因此转换过来就是求一个最小二乘法平面拟合的问题
(3) 使用积分图进行法线估计
使用积分图计算一个有序的点云的法线,此方法只适应于有序点云。
#include
#include
#include
#include
#include
#include
VTK_MODULE_INIT(vtkRenderingOpenGL);
using namespace std;
using namespace pcl;
int main()
{
//打开点云
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
pcl::io::loadPCDFile("table_scene_mug_stereo_textured.pcd", *cloud);
//创建法线估计向量
PointCloud<Normal>::Ptr normals(new PointCloud<Normal>);
IntegralImageNormalEstimation<PointXYZ, Normal> ne;
/*
三种法线估计方法:
COVARIANCE_MATRIX 模式从具体某个点的局部邻域的协方差矩阵创建9个积分,来计算这个点的法线
AVERAGE_3D_GRADIENT 模式创建6个积分图来计算水平方向和垂直方向的平滑后的三维梯度并使用两个梯度间的向量
积计算法线
AVERAGE_DEPTH——CHANGE 模式只创建了一个单一的积分图,从而平局深度变化计算法线
*/
ne.setNormalEstimationMethod(ne.AVERAGE_3D_GRADIENT); //设置法线估计方法为AVERAGE_3D_GRADIENT
ne.setMaxDepthChangeFactor(0.02f); //设置深度变化系数
ne.setNormalSmoothingSize(10.0f); //设置法线优化时考虑的邻域大小
ne.setInputCloud(cloud); //输入点云
ne.compute(*normals); //计算法线
//可视化
pcl::visualization::PCLVisualizer viewer("PCL Viewer"); //视口的名称
viewer.setBackgroundColor(0.0, 0.0, 0.0); //背景颜色的设置
viewer.addPointCloudNormals<pcl::PointXYZ, pcl::Normal>(cloud, normals); //将法线加入到点云中
while (!viewer.wasStopped())
{
viewer.spinOnce();
}
return 0;
}
点特征直方图(PFH)描述子:
正如点特征表示法所示,表面法线和曲率是某个点周围的几何特征基本表示法。虽然计算非常快速容易,但是无法获得太多信息,因为它们只使用很少的几个参数值来近似表示一个点的k邻域的几何特征。然而大部分场景中包含许多特征点,这些特征点有相同的或者非常相近的特征值,因此采用点特征表示法,其直接结果就减少了全局的特征信息。那么三维特征描述子中一位成员:点特征直方图(Point Feature Histograms),我们简称为PFH,从PCL实现的角度讨论其实施细节。PFH特征不仅与坐标轴三维数据有关,同时还与表面法线有关。