[点云分割] 基于法线差的分割

news2024/9/22 7:31:30

效果:

 

总体思路:

1、计算DoN特征

2、依据曲率进行过滤

3、依据欧式距离进行聚类

计算DoN特征的目的是为了提供准确的曲率信息。

其他:

计算DoN特征,这个算法是一种基于法线差异的尺度滤波器,用于点云数据。对于点云中的每个点,使用不同的搜索半径(sigma_s,sigma_l)估计两个法线,然后将这两个法线相减,得到一个基于尺度的特征。这个特征可以进一步用于过滤点云数据,类似于图像处理中的高斯差分(Difference of Gaussians)。但是,这个算法是在表面上进行的。当两个搜索半径相关时(sigma_l=10*sigma_s),可以获得最佳结果,两个搜索半径之间的频率可以被视为滤波器的带宽。对于适当的值和阈值,它可以用于表面边缘提取。

需要注意的是,输入的法线(通过setInputNormalsSmall和setInputNormalsLarge设置)必须与输入的点云(通过setInputCloud设置)相匹配。这与扩展FeatureFromNormals的特征估计方法的行为不同,后者将法线与搜索表面匹配。

这个算法的作者是Yani Ioannou,详细的介绍可以参考他的硕士论文《Automatic Urban Modelling using Mobile Urban LIDAR Data》。这个算法适用于点云数据的特征提取和滤波,特别适用于城市建模、环境感知和地理信息系统等领域。

代码:

/**
* @file don_segmentation.cpp
* Difference of Normals Example for PCL Segmentation Tutorials.
*
* @author Yani Ioannou
* @date 2012-09-24
 */
#include <string>

#include <pcl/point_types.h>
#include <pcl/io/pcd_io.h>
#include <pcl/search/organized.h>
#include <pcl/search/kdtree.h>
#include <pcl/features/normal_3d_omp.h>
#include <pcl/filters/conditional_removal.h>
#include <pcl/segmentation/extract_clusters.h>

#include <pcl/features/don.h>

using namespace pcl;

int main (int argc, char *argv[])
{
    ///The smallest scale to use in the DoN filter.
    double scale1;

    ///The largest scale to use in the DoN filter.
    double scale2;

    ///The minimum DoN magnitude to threshold by
    double threshold;

    //segment scene into clusters with given distance tolerance using euclidean clustering
    double segradius;

    if (argc < 6)
    {
        std::cerr << "usage: " << argv[0] << " inputfile smallscale largescale threshold segradius" << std::endl;
        exit (EXIT_FAILURE);
    }

    /// the file to read from.
    td::string infile = argv[1];
    /// small scale
    std::istringstream (argv[2]) >> scale1;
    /// large scale
    std::istringstream (argv[3]) >> scale2;
    std::istringstream (argv[4]) >> threshold;   // threshold for DoN magnitude
    std::istringstream (argv[5]) >> segradius;   // threshold for radius segmentation

    // Load cloud in blob format
    pcl::PCLPointCloud2 blob;
    pcl::io::loadPCDFile (infile.c_str (), blob);
    pcl::PointCloud<PointXYZRGB>::Ptr cloud (new pcl::PointCloud<PointXYZRGB>);
    pcl::fromPCLPointCloud2 (blob, *cloud);

    // Create a search tree, use KDTreee for non-organized data.
    pcl::search::Search<PointXYZRGB>::Ptr tree;
    if (cloud->isOrganized ())
    {
        tree.reset (new pcl::search::OrganizedNeighbor<PointXYZRGB> ());
    }
    else
    {
        tree.reset (new pcl::search::KdTree<PointXYZRGB> (false));
    }

    // Set the input pointcloud for the search tree
    tree->setInputCloud (cloud);

    if (scale1 >= scale2)
    {
        std::cerr << "Error: Large scale must be > small scale!" << std::endl;
        exit (EXIT_FAILURE);
    }

    // Compute normals using both small and large scales at each point
    pcl::NormalEstimationOMP<PointXYZRGB, PointNormal> ne;
    ne.setInputCloud (cloud);
    ne.setSearchMethod (tree);

    /**
   * NOTE: setting viewpoint is very important, so that we can ensure
   * normals are all pointed in the same direction!
   */
    ne.setViewPoint (std::numeric_limits<float>::max (), std::numeric_limits<float>::max (), std::numeric_limits<float>::max ());

    // calculate normals with the small scale
    std::cout << "Calculating normals for scale..." << scale1 << std::endl;
    pcl::PointCloud<PointNormal>::Ptr normals_small_scale (new pcl::PointCloud<PointNormal>);

    ne.setRadiusSearch (scale1);
    ne.compute (*normals_small_scale);

    // calculate normals with the large scale
    std::cout << "Calculating normals for scale..." << scale2 << std::endl;
    pcl::PointCloud<PointNormal>::Ptr normals_large_scale (new pcl::PointCloud<PointNormal>);

    ne.setRadiusSearch (scale2);
    ne.compute (*normals_large_scale);

    // Create output cloud for DoN results
    PointCloud<PointNormal>::Ptr doncloud (new pcl::PointCloud<PointNormal>);
    copyPointCloud (*cloud, *doncloud);

    std::cout << "Calculating DoN... " << std::endl;
    // Create DoN operator
    pcl::DifferenceOfNormalsEstimation<PointXYZRGB, PointNormal, PointNormal> don;
    don.setInputCloud (cloud);
    don.setNormalScaleLarge (normals_large_scale);
    don.setNormalScaleSmall (normals_small_scale);

    if (!don.initCompute ())
    {
        std::cerr << "Error: Could not initialize DoN feature operator" << std::endl;
        exit (EXIT_FAILURE);
    }

    // Compute DoN
    don.computeFeature (*doncloud);

    // Save DoN features
    pcl::PCDWriter writer;
    writer.write<pcl::PointNormal> ("don.pcd", *doncloud, false);

    // Filter by magnitude
    std::cout << "Filtering out DoN mag <= " << threshold << "..." << std::endl;

    // Build the condition for filtering
    pcl::ConditionOr<PointNormal>::Ptr range_cond (
    new pcl::ConditionOr<PointNormal> ()
    );
    range_cond->addComparison (pcl::FieldComparison<PointNormal>::ConstPtr (
                            new pcl::FieldComparison<PointNormal> ("curvature", pcl::ComparisonOps::GT, threshold))
                            );
    // Build the filter
    pcl::ConditionalRemoval<PointNormal> condrem;
    condrem.setCondition (range_cond);
    condrem.setInputCloud (doncloud);

    pcl::PointCloud<PointNormal>::Ptr doncloud_filtered (new pcl::PointCloud<PointNormal>);

    // Apply filter
    condrem.filter (*doncloud_filtered);

    doncloud = doncloud_filtered;

    // Save filtered output
    std::cout << "Filtered Pointcloud: " << doncloud->size () << " data points." << std::endl;

    writer.write<pcl::PointNormal> ("don_filtered.pcd", *doncloud, false);

    // Filter by magnitude
    std::cout << "Clustering using EuclideanClusterExtraction with tolerance <= " << segradius << "..." << std::endl;

    pcl::search::KdTree<PointNormal>::Ptr segtree (new pcl::search::KdTree<PointNormal>);
    segtree->setInputCloud (doncloud);

    std::vector<pcl::PointIndices> cluster_indices;
    pcl::EuclideanClusterExtraction<PointNormal> ec;

    ec.setClusterTolerance (segradius);
    ec.setMinClusterSize (50);
    ec.setMaxClusterSize (100000);
    ec.setSearchMethod (segtree);
    ec.setInputCloud (doncloud);
    ec.extract (cluster_indices);

    int j = 0;
    for (const auto& cluster : cluster_indices)
    {
        pcl::PointCloud<PointNormal>::Ptr cloud_cluster_don (new pcl::PointCloud<PointNormal>);
        for (const auto& idx : cluster.indices)
            {
                cloud_cluster_don->points.push_back ((*doncloud)[idx]);
            }

        cloud_cluster_don->width = cloud_cluster_don->size ();
        cloud_cluster_don->height = 1;
        cloud_cluster_don->is_dense = true;

        //Save cluster
        std::cout << "PointCloud representing the Cluster: " << cloud_cluster_don->size () << " data points." << std::endl;
        std::stringstream ss;
        ss << "don_cluster_" << j << ".pcd";
        writer.write<pcl::PointNormal> (ss.str (), *cloud_cluster_don, false);
        ++j;
        }
    }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1245043.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

大数据分析与应用实验任务九

大数据分析与应用实验任务九 实验目的 进一步熟悉pyspark程序运行方式&#xff1b; 熟练掌握pysaprkRDD基本操作相关的方法、函数&#xff0c;解决基本问题。 实验任务 进入pyspark实验环境&#xff0c;打开命令行窗口&#xff0c;输入pyspark&#xff0c;完成下列任务&am…

视频剪辑达人分享:高效减片头时长并调整播放速度的技巧,提升视频品质

在视频剪辑的过程中&#xff0c;许多初学者经常会遇到一些问题&#xff0c;如片头过长、播放速度不适当等&#xff0c;这些问题不仅会影响观众的观看体验&#xff0c;还会对视频品质产生负面影响。在调整播放速度时&#xff0c;要根据视频内容来进行调整。一般来说&#xff0c;…

git的用法

目录 一、为什么需要git 二、git基本操作 2.1、初始化git仓库 2.2、配置本地仓库的name和email 2.3、认识工作区、暂存区、版本库 三、git的实际操作 3.1 提交文件 3.2 查看git状态以及具体的修改 3.3 git版本回退 git reset 3.1 撤销修改 四、git分支管理 4.…

洛谷 P1883 函数

P1883 函数 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) Error Curves - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 这两题是一模一样的&#xff0c;过一题水两题。 分析 主要难点在于证明F(x)是一个单峰函数可以被三分&#xff0c;但是我随便画了几个f(x)之后发现好像…

Shell循环:for(一)

语法结构&#xff1a; for 变量名 [ in 取值列表] do 循环体 done 示例1&#xff1a; 1、需求&#xff1a;自动循环创建10个用户 2、演示&#xff1a; [rootlocalhost ~]# vim for.sh #脚本编写 #!/bin/bash for i in {1..10} do useradd "user$…

Redis-Redis高可用集群之水平扩展

Redis3.0以后的版本虽然有了集群功能&#xff0c;提供了比之前版本的哨兵模式更高的性能与可用性&#xff0c;但是集群的水平扩展却比较麻烦&#xff0c;今天就来带大家看看redis高可用集群如何做水平扩展&#xff0c;原始集群(见下图)由6个节点组成&#xff0c;6个节点分布在三…

Android设计模式--装饰模式

千淘万漉虽辛苦&#xff0c;吹尽黄沙始到金 一&#xff0c;定义 动态地给一个对象添加一些额外的职责。就增加功能来说&#xff0c;装饰模式相比生成子类更为灵活。 装饰模式也叫包装模式&#xff0c;结构型设计模式之一&#xff0c;其使用一种对客户端透明的方式来动态地扩展…

性能相关的闪存特性

一、多Plane操作 上章提到若干个Plane组成Die或者叫LUN,即一个Die上有多个Plane 每次进行写操作时&#xff0c;控制器先将数据写入页缓存中&#xff0c;等同一个Die上另一个Plane也写数据的时候&#xff0c;再同时写入&#xff0c;原来单独操作一个Plane的时间变成了可以同时做…

Vue学习之路------指令

Vue指令 vue会根据不同的指令&#xff0c;针对标签实现不同的功能 指令:带有v-前缀的特殊标签属性 1&#xff1a;v-html&#xff1a;指令 <div v-html"msg"></div> 2&#xff1a;v-show 作用&#xff1a;控制元素显示隐藏 语法&#xff1a;v-show&quo…

AMESim|学习记录

此文记录AMESim学习过程中的各种情况。 目录 01 王佳. AUV 浮力调节系统设计及控制策略研究[D]. 天津大学, 2017.01 王佳. AUV 浮力调节系统设计及控制策略研究[D]. 天津大学, 2017. 01 王佳. AUV 浮力调节系统设计及控制策略研究[D]. 天津大学, 2017. 开始步入正文 01 王佳.…

mysql 行转列 GROUP_CONCAT 试验

1.概要 很多时候需要用到行专列的方式做数据分析。比如对通讯数据的采集 数据采集结果如下&#xff1a; 变量值采集周期131251132272 我想要看的结果 变量1变量2采集周期351372 就是我想看到相关数据的周期变化情况。 2.试验 2.1创建数据如下&#xff08;表名 tb5&…

人工智能对网络安全的影响越来越大

如果问当前IT行业最热门的话题是什么&#xff0c;很少有人会回答除了人工智能&#xff08;AI&#xff09;之外的任何话题。 在不到 12 个月的时间里&#xff0c;人工智能已经从一项只有 IT 专业人员才能理解的技术发展成为从小学生到作家、程序员和艺术家的每个人都使用的工具…

案例025:基于微信小程序的移动学习平台的设计与实现

文末获取源码 开发语言&#xff1a;Java 框架&#xff1a;SSM JDK版本&#xff1a;JDK1.8 数据库&#xff1a;mysql 5.7 开发软件&#xff1a;eclipse/myeclipse/idea Maven包&#xff1a;Maven3.5.4 小程序框架&#xff1a;uniapp 小程序开发软件&#xff1a;HBuilder X 小程序…

Qt实现自定义IP地址输入控件(百分百还原Windows 10网络地址输入框)

在开发网络相关的程序时,我们经常需要输入IP地址,例如源地址和目标地址。Qt提供了一些基础的控件,如QLineEdit,但是它们并不能满足我们对IP地址输入的要求,例如限制输入的格式、自动跳转到下一个输入框、处理回车和退格键等。因此,我们需要自己编写一个自定义的IP地址输入…

深度学习技术前沿:探索与挑战

深度学习技术前沿&#xff1a;探索与挑战 一、引言 近年来&#xff0c;深度学习作为人工智能领域的重要分支&#xff0c;取得了令人瞩目的成就。它凭借强大的学习能力和出色的性能&#xff0c;在图像识别、语音识别、自然语言处理等众多任务中展现出巨大潜力。本文将深入探讨深…

预处理机制

跟着肯哥&#xff08;不是我&#xff09;学预处理机制 预处理类别 宏定义&#xff1a;#define 将文本替换为表达式或语句 条件编译&#xff1a;#ifdef、#ifndef和#if、#elif、#endif 根据标识符是否被定义选择编译代码 头文件包含&#xff1a;#include 将其他文件&#x…

YM5411 WIFI 5模块 完美替代AP6256

YM5411是沃特沃德推出的一款低成本&#xff0c;低功耗的模块&#xff0c;该模块具有Wi-Fi&#xff08;2.4GHz和5GHz IEEE 802.11 a/b/g/n/ac&#xff09;蓝牙&#xff08;BT5.0&#xff09;功能&#xff0c;并通过了SRRC认证&#xff0c;带mesh&#xff0c;完美替换AP6256。高度…

和数集团出席中科院上海高研院​第三十三期“高研交叉论坛”信息能源融合专场

2023年11月21日&#xff0c;中国科学院上海高等研究院第三十三期“高研交叉论坛”信息能源融合专场在上海高研院成功举办。本次论坛由中国科学院上海高等研究院智能信息通信技术研究与发展中心、中国科学院低碳转化科学与工程重点实验室、中科院和数智能区块链与能源系统应用联…

AndroidNDK开发之交叉编译

在Android studio2.2以及以上&#xff0c;构建原生库的默认工具是cmake。 CMake是一个跨平台的构建工具&#xff0c;可以使用简单的语句来描述所有平台的安装(编译过程)。 能够输出各种各样的makefile或者project文件。cmake并不直接构建出最终的软件&#xff0c;而是产生其他工…

MySQL错误之ONLY_FULL_GROUP_BY

报错信息&#xff1a; 翻译&#xff1a; 对该报错的解释 所以&#xff0c;实际上该报错是由于在SQL查询语句中有group by&#xff0c;而这个包含group by的SQL查询写的并不规范导致的&#xff0c;这个ONLY_FULL_GROUP_BY模式开启之后检查就会很严格&#xff0c;如果select列表…