PCL点云学习 十二(RoPs 特征与惯性矩描述子)

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(pi2pi1)+t(pi3ppi1)(0s,t1;s+t1)
  • 第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=13k=13(pijp)(pikp)T+121j=13(pijp)(pijp)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=1Nwi1wi2Ciwi1=i=1N(pi2pi1)×(pi3pi1)(pi2pi1)×(pi3pi1)wi2=(rp3pi1+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=v1sign(i=1Nwi1wi2(61j=13(pijp)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=v3sign(i=1Nwi1wi2(61j=13(pijp)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:转换到局部坐标系的点云

  1. 旋装点云 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
  2. 对于每个 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,使其对于分辨率具有不变性。
  3. 提取分布矩阵 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=1Lj=1L(ii)m(jj)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=1Lj=1LD(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:xk
  4. 分别绕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)}
  5. 上述参数中 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边框

  1. 面积矩:来自
    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)

  2. 惯性矩:

    • 物理量:用作描述物体抵抗扭动转动的能力,单位( m 4 m^4 m4):地址
    • 详细定义:面积与与轴的距离(形心到坐标轴)的平方和的乘机:地址
    • I x : I_x: Ix:平面图形对于z轴的面积矩, I y : I_y: Iy:平面图形对于y轴的面积矩
      I x = ∫ A y 2 d A , I y = ∫ A x 2 d A I_x=\int_Ay^2dA,I_y=\int_Ax^2dA Ix=Ay2dA,Iy=Ax2dA
  3. 偏心率(离心率)

    • 描述圆锥曲线轨道形状的数学量:详见
  4. OBB(Oriented Bounding Box)方向包围盒,AaBB(Axis-Aligned Bounding Box)坐标对齐包围盒
    简介:地址1地址2
    常用做作快速碰撞检测

  5. PCL中的原理简介

    • 先计算点云的协防差矩阵,分解求解特征值和特征向量(同时归一化)
    • 建立坐标系:特征向量从大到小对应的特征向量为: X , Y , Z X,Y,Z X,Y,Z,同时符合右手定则
    • X轴绕其他Y,Z轴旋转,一般是绕y轴旋转 0 − 90 0-90 090,绕z轴旋转 0 − 360 0-360 0360,pcl可以设置,没旋转一次,
      • 惯性矩:每旋转一次,以X作为当前轴计算一次
      • 偏心率:每旋转一次,以X轴旋转后的正方向,作为假设平面的法向量,将点云投影到该假设平面,长轴与短轴由投影后点云的协防差矩阵得到
  6. 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;
}

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值