点云处理【五】(点云特征提取)

第一章 点云数据采集
第二章 点云滤波
第三章 点云降采样


1.点云特征与关键点的区别?

关键点提取关键的一些点,旨在减少数据量;而特征提取旨在为每个点提供一个可用于后续任务的描述。
通常点云特征与关键点结合使用。

2.特征提取算法(本数据单位为mm,通常数据单位为m,取半径之类得参数要除1000)

2.1 法线估计

每一个点的位置都有垂直于点表面的的矢量,但是这种方式比较耗时。

PCL

#include 
#include 
#include 
#include 
#include 

int main() {
    // 1. Load Point Cloud from PCD file
    pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>());
    pcl::io::loadPCDFile("second_radius_cloud.pcd", *cloud);

    // 2. Setup the normal estimation
    pcl::NormalEstimation<pcl::PointXYZ, pcl::Normal> normal_estimation;
    normal_estimation.setInputCloud(cloud);
    pcl::search::KdTree<pcl::PointXYZ>::Ptr tree(new pcl::search::KdTree<pcl::PointXYZ>());
    normal_estimation.setSearchMethod(tree);
    normal_estimation.setRadiusSearch(30);
    
    // 3. Compute the normals
    pcl::PointCloud<pcl::Normal>::Ptr normals(new pcl::PointCloud<pcl::Normal>());
    normal_estimation.compute(*normals);

    // 4. Visualization
    pcl::visualization::PCLVisualizer viewer("Normals Viewer");
    viewer.setBackgroundColor(0, 0, 0);
    viewer.addPointCloud<pcl::PointXYZ>(cloud, "cloud");
    viewer.addPointCloudNormals<pcl::PointXYZ, pcl::Normal>(cloud, normals, 10, 50, "normals");
    viewer.initCameraParameters();
    viewer.saveScreenshot("screenshot.png");
    viewer.spin();

    return 0;
}

点云处理【五】(点云特征提取)_第1张图片

2.2 SHOT

每一个点的位置都有垂直于点表面的的矢量,但是这种方式比较耗时。

PCL
在这里可视化了shot的前三个维度。

#include 
#include 
#include 
#include 
#include 

int main() {
    // Load Point Cloud from PCD file
    pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>());
    pcl::io::loadPCDFile("second_radius_cloud.pcd", *cloud);

    // Compute Normals
    pcl::NormalEstimation<pcl::PointXYZ, pcl::Normal> normal_estimation;
    pcl::PointCloud<pcl::Normal>::Ptr normals(new pcl::PointCloud<pcl::Normal>());
    pcl::search::KdTree<pcl::PointXYZ>::Ptr tree(new pcl::search::KdTree<pcl::PointXYZ>());
    normal_estimation.setInputCloud(cloud);
    normal_estimation.setSearchMethod(tree);
    normal_estimation.setRadiusSearch(30);
    normal_estimation.compute(*normals);

    // Compute SHOT descriptors
    pcl::SHOTEstimation<pcl::PointXYZ, pcl::Normal, pcl::SHOT352> shot;
    pcl::PointCloud<pcl::SHOT352>::Ptr shot_descriptors(new pcl::PointCloud<pcl::SHOT352>());
    shot.setInputCloud(cloud);
    shot.setInputNormals(normals);
    shot.setRadiusSearch(3);
    shot.compute(*shot_descriptors);
    
    // Convert SHOT values to colors
    pcl::PointCloud<pcl::PointXYZRGB>::Ptr colored_cloud(new pcl::PointCloud<pcl::PointXYZRGB>());
    colored_cloud->resize(cloud->size());
    for (size_t i = 0; i < cloud->size(); ++i) {
        pcl::PointXYZRGB point;
        point.x = (*cloud)[i].x;
        point.y = (*cloud)[i].y;
        point.z = (*cloud)[i].z;

        // Use the first three dimensions of the SHOT descriptor to color the point
        point.r = static_cast<uint8_t>(255 * std::min(1.0f, shot_descriptors->points[i].descriptor[0]));
        point.g = static_cast<uint8_t>(255 * std::min(1.0f, shot_descriptors->points[i].descriptor[1]));
        point.b = static_cast<uint8_t>(255 * std::min(1.0f, shot_descriptors->points[i].descriptor[2]));

        colored_cloud->points[i] = point;
    }
    // Visualization
    pcl::visualization::PCLVisualizer viewer("SHOT Features Viewer");
    viewer.setBackgroundColor(0, 0, 0);
    viewer.addPointCloud<pcl::PointXYZRGB>(colored_cloud, "colored cloud"););
    viewer.spin();

    return 0;
}

点云处理【五】(点云特征提取)_第2张图片

2.3 PFH

PFH通过参数化查询点与邻域点之间的空间差异,并形成一个多维直方图对点的k邻域几何属性进行描述。直方图所在的高维超空间为特征表示提供了一个可度量的信息空间,对点云对应曲面的6维姿态来说它具有不变性,并且在不同的采样密度或邻域的噪音等级下具有鲁棒性。点特征直方图(PFH)表示法是基于点与其k邻域之间的关系以及它们的估计法线,简言之,它考虑估计法线方向之间所有的相互作用,试图捕获最好的样本表面变化情况,以描述样本的几何特征。

PCL

#include 
#include 
#include 
#include 
#include 
#include 

int main() {
    // 1. Load Point Cloud from PCD file
    pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>());
    pcl::io::loadPCDFile("second_radius_cloud.pcd", *cloud);

    // 2. Compute the normals
    pcl::NormalEstimation<pcl::PointXYZ, pcl::Normal> normal_estimation;
    normal_estimation.setInputCloud(cloud);
    pcl::search::KdTree<pcl::PointXYZ>::Ptr tree(new pcl::search::KdTree<pcl::PointXYZ>());
    normal_estimation.setSearchMethod(tree);
    normal_estimation.setRadiusSearch(30);
    pcl::PointCloud<pcl::Normal>::Ptr normals(new pcl::PointCloud<pcl::Normal>());
    normal_estimation.compute(*normals);
    // 3. Compute PFH descriptors
    pcl::PFHEstimation<pcl::PointXYZ, pcl::Normal, pcl::PFHSignature125> pfh_estimation;
    pfh_estimation.setInputCloud(cloud);
    pfh_estimation.setInputNormals(normals);
    pfh_estimation.setSearchMethod(tree);
    pfh_estimation.setRadiusSearch(80);
    pcl::PointCloud<pcl::PFHSignature125>::Ptr pfhs(new pcl::PointCloud<pcl::PFHSignature125>());
    pfh_estimation.compute(*pfhs);
    // 4. Convert PFH values to colors for visualization
    pcl::PointCloud<pcl::PointXYZRGB>::Ptr colored_cloud(new pcl::PointCloud<pcl::PointXYZRGB>());
    colored_cloud->resize(cloud->size());
    for (size_t i = 0; i < cloud->size(); ++i) {
        pcl::PointXYZRGB point;
        point.x = (*cloud)[i].x;
        point.y = (*cloud)[i].y;
        point.z = (*cloud)[i].z;

        // Use the first dimension of the PFH descriptor to color the point
        point.r = static_cast<uint8_t>(255 * std::min(1.0f, pfhs->points[i].histogram[0] / 100.0f));
        point.g = 0;
        point.b = 0;

        colored_cloud->points[i] = point;
    }
    // 5. Visualization
    pcl::visualization::PCLVisualizer viewer("PFH Visualization");
    viewer.setBackgroundColor(0, 0, 0);
    viewer.addPointCloud<pcl::PointXYZRGB>(colored_cloud, "colored cloud");
    viewer.spin();
    return 0;
}

2.4 FPFH

快速点特征直方图(Fast Point Feature Histograms, FPFH)是PFH计算方式的简化形式。它的思想在于分别计算查询点的k邻域中每一个点的简化点特征直方图(Simplified Point Feature Histogram,SPFH),再通过一个公式将所有的SPFH加权成最后的快速点特征直方图。FPFH把算法的计算复杂度降低到了O(nk) ,但是任然保留了PFH大部分的识别特性。

PCL

#include 
#include 
#include 
#include 
#include 
#include 

int main() {
    // 1. Load Point Cloud from PCD file
    pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>());
    pcl::io::loadPCDFile("second_radius_cloud.pcd", *cloud);

    // 2. Compute the normals
    pcl::NormalEstimation<pcl::PointXYZ, pcl::Normal> normal_estimation;
    normal_estimation.setInputCloud(cloud);
    pcl::search::KdTree<pcl::PointXYZ>::Ptr tree(new pcl::search::KdTree<pcl::PointXYZ>());
    normal_estimation.setSearchMethod(tree);
    normal_estimation.setRadiusSearch(300);
    pcl::PointCloud<pcl::Normal>::Ptr normals(new pcl::PointCloud<pcl::Normal>());
    normal_estimation.compute(*normals);

    // 3. Compute FPFH descriptors
    pcl::FPFHEstimation<pcl::PointXYZ, pcl::Normal, pcl::FPFHSignature33> fpfh_estimation;
    fpfh_estimation.setInputCloud(cloud);
    fpfh_estimation.setInputNormals(normals);
    fpfh_estimation.setSearchMethod(tree);
    fpfh_estimation.setRadiusSearch(500);
    pcl::PointCloud<pcl::FPFHSignature33>::Ptr fpfhs(new pcl::PointCloud<pcl::FPFHSignature33>());
    fpfh_estimation.compute(*fpfhs);

    // 4. Convert FPFH values to colors for visualization
    pcl::PointCloud<pcl::PointXYZRGB>::Ptr colored_cloud(new pcl::PointCloud<pcl::PointXYZRGB>());
    colored_cloud->resize(cloud->size());
    for (size_t i = 0; i < cloud->size(); ++i) {
        pcl::PointXYZRGB point;
        point.x = (*cloud)[i].x;
        point.y = (*cloud)[i].y;
        point.z = (*cloud)[i].z;

        // Use the first dimension of the FPFH descriptor to color the point
        point.r = static_cast<uint8_t>(255 * std::min(1.0f, fpfhs->points[i].histogram[0] / 100.0f));
        point.g = 0;
        point.b = 0;

        colored_cloud->points[i] = point;
    }

    // 5. Visualization
    boost::shared_ptr<pcl::visualization::PCLVisualizer> viewer(new pcl::visualization::PCLVisualizer("FPFH Visualization"));
    viewer->setBackgroundColor(0, 0, 0);
    viewer->addPointCloud<pcl::PointXYZRGB>(colored_cloud, "colored cloud");
    viewer->spin();

    return 0;
}

2.5 VFH

FPFH有很好的速度和辨别能力,VFH在此基础上添加视点方差,同时保持尺度不变性。

PCL

#include 
#include 
#include 
#include 
#include 
#include 

int main() {
    // 1. Load Point Cloud from PCD file
    pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>());
    pcl::io::loadPCDFile("second_radius_cloud.pcd", *cloud);

    // 2. Compute the normals
    pcl::NormalEstimation<pcl::PointXYZ, pcl::Normal> normal_estimation;
    normal_estimation.setInputCloud(cloud);
    pcl::search::KdTree<pcl::PointXYZ>::Ptr tree(new pcl::search::KdTree<pcl::PointXYZ>());
    normal_estimation.setSearchMethod(tree);
    normal_estimation.setRadiusSearch(30);
    pcl::PointCloud<pcl::Normal>::Ptr normals(new pcl::PointCloud<pcl::Normal>());
    normal_estimation.compute(*normals);

    // 3. Compute VFH descriptors
    pcl::VFHEstimation<pcl::PointXYZ, pcl::Normal, pcl::VFHSignature308> vfh_estimation;
    vfh_estimation.setInputCloud(cloud);
    vfh_estimation.setInputNormals(normals);
    vfh_estimation.setSearchMethod(tree);
    pcl::PointCloud<pcl::VFHSignature308>::Ptr vfhs(new pcl::PointCloud<pcl::VFHSignature308>());
    vfh_estimation.compute(*vfhs);

    // 4. Visualization
    boost::shared_ptr<pcl::visualization::PCLVisualizer> viewer(new pcl::visualization::PCLVisualizer("VFH Visualization"));
    viewer->setBackgroundColor(0, 0, 0);
    viewer->addPointCloud<pcl::PointXYZ>(cloud, "cloud");

    // Display some VFH dimensions as text
    for (size_t i = 0; i < 5; ++i) {
        std::stringstream ss;
        ss << "VFH value at dim " << i << ": " << vfhs->points[0].histogram[i];
        viewer->addText(ss.str(), 10, 20 + i * 20, 20, 1.0, 1.0, 1.0, "vfh_val" + std::to_string(i));
    }
    viewer->spin();

    return 0;
}

你可能感兴趣的:(点云处理,点云,3D,pcl,open3d,特征提取)