RoPs(Rotational Projection Statistics)
pcl官网地址
来自:
《pcl_点云从入门到精通》:详见这里
旋装投影特征
- 旋装平移不变性
- 抗干扰性良好
关键点
- 给定关键点 P P P和其支撑半径内 r r r内的点,得到 N N N个三角形和 M M M个顶点
- 对于第i个三角形见上图,三角形中任意一个顶点可以表示为:
p i ( s , t ) = p i 1 + s ( p i 2 − p i 1 ) + t ( p i 3 − p p i 1 ) ( 0 ≤ s , t ≤ 1 ; s + t ≤ 1 ) p_i(s,t)=p_{i1}+s(p_{i2}-p_{i1})+t(p_{i3}-p_{p_{i1}}) (0 \leq s,t \leq 1;s+t\leq 1) pi(s,t)=pi1+s(pi2−pi1)+t(pi3−ppi1)(0≤s,t≤1;s+t≤1) - 第i个三角形上的单点的散布矩阵
C
i
C_i
Ci为:
C i = 1 12 ∑ j = 1 3 ∑ k = 1 3 ( p i j − p ) ( p i k − p ) T + 1 12 ∑ j = 1 3 ( p i j − p ) ( p i j − p ) T C_i =\frac{1}{12}\sum_{j=1}^3\sum_{k=1}^3(p_{ij}-p)(p_{ik}-p)^T+\frac{1}{12}\sum_{j=1}^{3}(p_{ij}-p)(p_{ij}-p)^T Ci=121j=1∑3k=1∑3(pij−p)(pik−p)T+121j=1∑3(pij−p)(pij−p)T
总散布矩阵为:
w i 1 : w_{i1}: wi1:三角形面积与局部表面 S S S总面积的比值
w i 2 : w_{i2}: wi2:关键点到第i个三角形中心距离,形成的权值
C = ∑ i = 1 N w i 1 w i 2 C i w i 1 = ∣ ( p i 2 − p i 1 ) × ( p i 3 − p i 1 ) ∣ ∑ i = 1 N ∣ ( p i 2 − p i 1 ) × ( p i 3 − p i 1 ) ∣ ∣ w i 2 = ( r − ∣ p − p i 1 + p i 2 + p i 3 3 ∣ ) 2 C=\sum_{i=1}^{N}w_{i1}w_{i2}C_i\\ w_{i1}=\frac{|(p_{i2}-p_{i1})×(p_{i3}-p_{i1})|}{\sum^N_{i=1}|(p_{i2}-p_{i1})×(p_{i3}-p_{i1})||}\\ w_{i2}=(r-|p-\frac{p_{i1}+p_{i2}+p_{i3}}{3}|)^2 C=i=1∑Nwi1wi2Ciwi1=∑i=1N∣(pi2−pi1)×(pi3−pi1)∣∣∣(pi2−pi1)×(pi3−pi1)∣wi2=(r−∣p−3pi1+pi2+pi3∣)2 - 在对特征矩阵进行分解
E : E: E:特征值矩阵 降序排列
V : V: V:特征向量 对应特征值
C E = E V CE=EV CE=EV - 特征向量方向:
多数散布向量所指向的方向,可以根据特征向量与散布向量的内积得到一个模糊特征向量,其局部坐标为:
∼ v 1 = v 1 ∗ s i g n ( ∑ i = 1 N w i 1 w i 2 ( 1 6 ∑ j = 1 3 ( p i j − p ) v 1 ) ) \begin{array}{c} \sim\\ v_{1} \end{array}=v_1*sign(\sum_{i=1}^Nw_{i1}w_{i2}(\frac {1}{6}\sum_{j=1}^3(p_{ij}-p)v_1)) ∼v1=v1∗sign(i=1∑Nwi1wi2(61j=1∑3(pij−p)v1))
∼ v 3 = v 3 ∗ s i g n ( ∑ i = 1 N w i 1 w i 2 ( 1 6 ∑ j = 1 3 ( p i j − p ) v 3 ) ) \begin{array}{c} \sim\\ v_{3} \end{array}=v_3*sign(\sum_{i=1}^Nw_{i1}w_{i2}(\frac {1}{6}\sum_{j=1}^3(p_{ij}-p)v_3)) ∼v3=v3∗sign(i=1∑Nwi1wi2(61j=1∑3(pij−p)v3))
v 2 = v 1 × v 3 v_{2}=v_1×v_3 v2=v1×v3
描述符
输入点云或者其mesh,计算点
p
p
p及其支撑半径为
r
r
r的局部表面,再进算其局部参考坐标系,再将局部表面
S
S
S上的三角形顶点构成点云
Q
Q
Q,映射到局部参考坐标系
Q
′
Q'
Q′.
具体步骤:
Q
:
Q:
Q:原始点云
Q
′
:
Q':
Q′:转换到局部坐标系的点云
- 旋装点云 Q ′ Q' Q′绕x轴旋转 θ k \theta_k θk,得到旋转后的点云 Q ′ ( θ k ) Q'(\theta_k) Q′(θk),再将 Q ′ ( θ k ) Q'(\theta_k) Q′(θk)获得其的三视图 x y , x z , y z xy,xz,yz xy,xz,yz及其对应投影点云 Q i ′ ( θ k ) ~ ; i = 1 , 2 , 3 \tilde{Q_i'(\theta_k)};i=1,2,3 Qi′(θk)~;i=1,2,3
- 对于每个 Q i ′ ( θ k ) ~ ; i = 1 , 2 , 3 \tilde{Q_i'(\theta_k)};i=1,2,3 Qi′(θk)~;i=1,2,3,将其二位包围框均匀划分为 L × L L×L L×L个单元格,统计落入每个单元格点的个数,得到一个 L × L L×L L×L的矩阵 D D D,将矩阵 D D D归一化使所有单元格数量为1,使其对于分辨率具有不变性。
- 提取分布矩阵
D
D
D的中心矩和香农熵。
中心矩公式 u m n u_{mn} umn:
u m n = ∑ i = 1 L ∑ j = 1 L ( i − i ‾ ) m ( j − j ‾ ) n D ( i , j ) u_{mn}=\sum_{i=1}^L\sum_{j=1}^L(i-\overline i)^m(j-\overline j)^n D(i,j) umn=i=1∑Lj=1∑L(i−i)m(j−j)nD(i,j)
香农熵为 e e e:
e = − ∑ i = 1 L ∑ j = 1 L D ( i , j ) l o g ( D ( i , j ) ) e=-\sum_{i=1}^L\sum_{j=1}^LD(i,j)log(D(i,j)) e=−i=1∑Lj=1∑LD(i,j)log(D(i,j))
在将三视图 x y , x z , y z xy,xz,yz xy,xz,yz上的三个统计向量组合起来的得到 f x ( θ k ) , k : 表 示 绕 x 轴 旋 装 k 次 f_x{(\theta_k)},k:表示绕x轴旋装k次 fx(θk),k:表示绕x轴旋装k次 - 分别绕x轴旋主k次
k
=
1
,
.
.
,
T
k=1,..,T
k=1,..,T,其角度分别为
θ
k
\theta_k
θk,得到其k次的关于3个平面的投影
f
x
(
θ
k
)
,
f
y
(
θ
k
)
,
f
z
(
θ
k
)
f_x{(\theta_k)},f_y{(\theta_k)},f_z{(\theta_k)}
fx(θk),fy(θk),fz(θk),最终得到描述符:
f = { f x ( θ k ) , f y ( θ k ) , f z ( θ k ) } f=\{f_x{(\theta_k)},f_y{(\theta_k)},f_z{(\theta_k)}\} f={fx(θk),fy(θk),fz(θk)} - 上述参数中 L ( 划 分 区 域 ) = 5 L(划分区域)=5 L(划分区域)=5, T ( 旋 转 次 数 ) = 3 T(旋转次数)=3 T(旋转次数)=3,如果输入是点云需要将其三角化/采用其他算法的局部参考坐标模块
pcl中使用
其他文件详见pcl点云从入门到精通
#include <pcl/features/rops_estimation.h>
#include <pcl/io/pcd_io.h>
#include <pcl/visualization/histogram_visualizer.h>
#include <pcl/visualization/pcl_plotter.h>
#include <iostream>
using namespace pcl;
using namespace std;
int main(int argc, char const *argv[])
{
pcl::PointCloud<PointXYZ>::Ptr cloud(new pcl::PointCloud<PointXYZ>());//
pcl::io::loadPCDFile("/home/n1/notes/pcl/RoPS/test.pcd",*cloud);
pcl::PointIndicesPtr indices = boost::shared_ptr<PointIndices>(new pcl::PointIndices());
std::ifstream indices_file;
std::cout<<cloud->size()<<endl;
indices_file.open("/home/n1/notes/pcl/RoPS/indices.txt",std::ifstream::in);
//读取行数,并将索引添至队列
for(std::string line;std::getline(indices_file,line);)
{
std::istringstream in(line);
unsigned int index = 0;
in >> index;
indices->indices.push_back(index-1);
}
//关闭文件
indices_file.close();
std::vector<pcl::Vertices> triangles;// std::vector<uint32_t>
std::ifstream triangles_file;
triangles_file.open("/home/n1/notes/pcl/RoPS/triangles.txt",std::ifstream::in);//读取三角化信息
for(std::string line;std::getline(triangles_file,line);)
{
pcl::Vertices triangle;
std::istringstream in(line);
unsigned int vertex =0;//为每个id添加索引
in >>vertex;
triangle.vertices.push_back(vertex-1);
in >> vertex;
triangle.vertices.push_back(vertex-1);
in >> vertex;
triangle.vertices.push_back(vertex-1);
triangles.push_back (triangle);
}
float support_radius = 0.0285f;
unsigned int number_of_partition_bins = 5;//分块大小
unsigned int number_of_rotations =3;//旋转区域个数
pcl::search::KdTree<PointXYZ>::Ptr search_method(new pcl::search::KdTree<PointXYZ>());
search_method->setInputCloud(cloud);
pcl::ROPSEstimation <pcl::PointXYZ,pcl::Histogram<135> > Feature_estimator;//估计特征点
Feature_estimator.setSearchMethod(search_method); //设置搜索方法
Feature_estimator.setSearchSurface(cloud); //设置搜索平面
Feature_estimator.setInputCloud(cloud); //设置输入点云
Feature_estimator.setIndices(indices); //对应的id索引
Feature_estimator.setTriangles (triangles); //设置三角化
Feature_estimator.setRadiusSearch(support_radius); //查找半径
Feature_estimator.setNumberOfPartitionBins(number_of_partition_bins);//设置分块大小
Feature_estimator.setNumberOfRotations (number_of_rotations);//旋转次数
Feature_estimator.setSupportRadius(support_radius); //支撑半径
pcl::PointCloud<pcl::Histogram <135> >::Ptr histograms (new pcl::PointCloud <pcl::Histogram <135> > ());
Feature_estimator.compute(*histograms);
std::cout<<histograms->header<<endl;
pcl::visualization::PCLPlotter *plotter = new pcl::visualization::PCLPlotter ("test");
plotter->setShowLegend(true);
plotter->addFeatureHistogram<pcl::Histogram<135> >(*histograms,135,"rops");//点云,描述子长度,对应的id, 第0个点对应索引
plotter->spin();
return 0;
}
基于惯性矩和偏心率的描述子
官网链接
使用 pcl::MomentOfInertiaEstimation 类获取,惯性矩和偏心率描述子同时产生OBB(不一定为最小)和AABB边框
-
面积矩:来自
S Z : S_Z: SZ:平面图形对于z轴的面积距
A : A: A:图形面积,位于 y o z yoz yoz平面
y c : yc: yc:面积中心到z轴的距离
S Z = A × y c ( 单 位 m 3 ) S_Z=A×yc(单位m^3) SZ=A×yc(单位m3) -
惯性矩:
-
偏心率(离心率)
- 描述圆锥曲线轨道形状的数学量:详见
-
OBB(Oriented Bounding Box)方向包围盒,AaBB(Axis-Aligned Bounding Box)坐标对齐包围盒
简介:地址1,地址2
常用做作快速碰撞检测 -
PCL中的原理简介
- 先计算点云的协防差矩阵,分解求解特征值和特征向量(同时归一化)
- 建立坐标系:特征向量从大到小对应的特征向量为: X , Y , Z X,Y,Z X,Y,Z,同时符合右手定则
- X轴绕其他Y,Z轴旋转,一般是绕y轴旋转
0
−
90
0-90
0−90,绕z轴旋转
0
−
360
0-360
0−360,pcl可以设置,没旋转一次,
- 惯性矩:每旋转一次,以X作为当前轴计算一次
- 偏心率:每旋转一次,以X轴旋转后的正方向,作为假设平面的法向量,将点云投影到该假设平面,长轴与短轴由投影后点云的协防差矩阵得到
-
pcl中代码(来自pcl点云入门到精通)
#include <pcl/features/moment_of_inertia_estimation.h>
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
#include <pcl/visualization/cloud_viewer.h>
#include <pcl/point_cloud.h>
using namespace pcl;
using namespace std;
int main(int argc, char const *argv[])
{
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>());
pcl::io::loadPCDFile("/home/n1/notes/pcl/inertia/test.pcd",*cloud);
pcl::MomentOfInertiaEstimation<pcl::PointXYZ> feature_extractor;//特征提取
feature_extractor.setInputCloud(cloud); //输入点云
feature_extractor.compute (); //计算
std::vector<float> moment_of_inertia;//惯性值
std::vector<float> eccentricity; //偏心率
pcl::PointXYZ min_point_AABB; //AABB左下角坐标
pcl::PointXYZ max_point_AABB; //AABB右上角坐标
pcl::PointXYZ min_point_OBB; //OBB最小角坐标
pcl::PointXYZ max_point_OBB; //OBB右上角坐标
pcl::PointXYZ position_OBB; //OBB 局部坐标中心点
Eigen::Matrix3f rotational_matrix_OBB; //OBB方向
float major_value, middle_value, minor_value;//三个特征值
Eigen::Vector3f major_vector, middle_vector, minor_vector;//三个特征向量
Eigen::Vector3f mass_center; //质点
feature_extractor.getMomentOfInertia(moment_of_inertia); //获取惯性矩
feature_extractor.getEccentricity(eccentricity); //获得偏心率
feature_extractor.getAABB(min_point_AABB,max_point_AABB); //获取对应边框
feature_extractor.getOBB(min_point_OBB,max_point_OBB,position_OBB,rotational_matrix_OBB);//
feature_extractor.getEigenValues(major_value, middle_value, minor_value); //获取特征值
feature_extractor.getEigenVectors(major_vector, middle_vector, minor_vector); //获取特征向量
feature_extractor.getMassCenter(mass_center); //质心
//可视化
boost::shared_ptr<pcl::visualization::PCLVisualizer> viewer (new pcl::visualization::PCLVisualizer ("MomentOfInertiaEstimation"));
viewer->setBackgroundColor (1, 1, 1);
viewer->addCoordinateSystem (1.0);
viewer->initCameraParameters ();
viewer->addPointCloud<pcl::PointXYZ> (cloud,pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ>(cloud,0,255,0), "sample cloud");
viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE,5,"sample cloud");
viewer->addCube (min_point_AABB.x, max_point_AABB.x, min_point_AABB.y, max_point_AABB.y, min_point_AABB.z, max_point_AABB.z, 1.0, 0.0, 0.0, "AABB");
viewer->setShapeRenderingProperties(pcl::visualization::PCL_VISUALIZER_OPACITY,0.1,"AABB"); //不透明度
viewer->setShapeRenderingProperties(pcl::visualization::PCL_VISUALIZER_LINE_WIDTH,4,"AABB"); //线宽
Eigen::Vector3f position (position_OBB.x, position_OBB.y, position_OBB.z);
std::cout<<"局部坐标中心点: "<<position_OBB<<endl;
std::cout<<"质心: "<<mass_center<<endl;
Eigen::Quaternionf quat (rotational_matrix_OBB); //将方向转化为矢量
viewer->addCube (position, quat, max_point_OBB.x - min_point_OBB.x, max_point_OBB.y - min_point_OBB.y, max_point_OBB.z - min_point_OBB.z, "OBB");
viewer->setShapeRenderingProperties(pcl::visualization::PCL_VISUALIZER_COLOR,0,0,1,"OBB");
viewer->setShapeRenderingProperties(pcl::visualization::PCL_VISUALIZER_OPACITY,0.1,"OBB");
viewer->setShapeRenderingProperties(pcl::visualization::PCL_VISUALIZER_LINE_WIDTH,4,"OBB");
//viewer->setRepresentationToWireframeForAllActors(); //改变为线框表示
pcl::PointXYZ center (mass_center (0), mass_center (1), mass_center (2));
pcl::PointXYZ x_axis (major_vector (0) + mass_center (0), major_vector (1) + mass_center (1), major_vector (2) + mass_center (2));
pcl::PointXYZ y_axis (middle_vector (0) + mass_center (0), middle_vector (1) + mass_center (1), middle_vector (2) + mass_center (2));
pcl::PointXYZ z_axis (minor_vector (0) + mass_center (0), minor_vector (1) + mass_center (1), minor_vector (2) + mass_center (2));
viewer->addLine (center, x_axis, 1.0f, 0.0f, 0.0f, "major eigen vector");
viewer->addLine (center, y_axis, 0.0f, 1.0f, 0.0f, "middle eigen vector");
viewer->addLine (center, z_axis, 0.0f, 0.0f, 1.0f, "minor eigen vector");
std::cout<<"size of cloud :"<<cloud->points.size()<<endl;
std::cout<<"moment_of_inertia :"<<moment_of_inertia.size()<<endl;
std::cout<<"eccentricity :"<<eccentricity.size()<<endl;
while(!viewer->wasStopped())
{
viewer->spinOnce (100);
boost::this_thread::sleep (boost::posix_time::microseconds (100000));
}
return 0;
}