《点云处理》 提取点云内点和外点

前言

关于内点(inliers)和外点(outliers)在点云处理方向上是个非常常见的名词。有时候,内点也会被称之为有效点,而外点会被称之为无效点。所谓有效和无效都是相对而言的,无效不一定是真的没有意义,并不等价于噪点,而有效也并不是绝对是想要的。有时候,可能既要内点,也要外点。之所以这么称呼,是想要从一整个大块的点云中将其分开来。通常,内点和外点具备不同的特征或者属性,根据这个属性,总能找到相应的算法将其分离。

举个例子,使用RANSAC进行平面拟合时,通常会设置一个距离阈值distance。RANSAC每次迭代都会从点云中任意取3个点,3个点在空间中确定了唯一的平面,可以得到平面方程。随即,遍历点云,计算每个点到该平面的欧氏距离,若距离大于设定的阈值distance,那么该点则是外点,这个点被认为是距离平面比较“远”的点,而点到平面的距离小于设定的阈值,则该点是内点,这个点被认为是距离平面比较“近”的点,或者干脆说在误差允许的范围内,该点在拟合的平面上。通常运行RANSAC算法后,会得到一个std::vector inliers动态数组,该数组中存放的一般就是内点的索引。

当然,除了拟合平面外,还有很多这样的例子,如欧式聚类。接下来就汇总一下,得到inliers之后,如何提取内点点云和外点点云。

方法一:

/// <summary>
/// 根据索引提取点云中的内点或者外点
/// </summary>
/// <param name="cloud">输入点云</param>
/// <param name="inliers">存放内点索引的数组</param>
/// <param name="cloud_out">输出点云</param>
/// <param name="is_true">输入true则提取内点点云,输入false则提取外点点云</param>
/// <returns>return true则表示提取成功,return false则表示提取失败</returns>
bool GetCloudByIndex(const pcl::PointCloud<pcl::PointXYZ>::Ptr& cloud, const std::vector<int>& inliers, pcl::PointCloud<pcl::PointXYZ>::Ptr& cloud_out, const bool& is_true)
{if (cloud == nullptr) return false;            // 判断输入点云是否为空if (cloud->points.size() < 10) return false;   // 判断输入点云的尺寸if (cloud_out == nullptr) cloud_out.reset(new pcl::PointCloud<pcl::PointXYZ>);  // 判断输出点云是否为空,如果为空则需要为其new出一个对象int PointSize = cloud->points.size();if (is_true){pcl::copyPointCloud(*cloud, inliers, *cloud_out);}else{std::vector<int> indices(PointSize);std::vector<int> outliers;std::iota(indices.begin(), indices.end(), 0);std::set_difference(indices.begin(), indices.end(), inliers.begin(), inliers.end(), std::back_inserter(outliers));pcl::copyPointCloud(*cloud, outliers, *cloud_out);}return true;
}

上述代码中,直接使用了pcl::copyPointCloud(*cloud, inliers, *cloud_out);提取点云,传入的第二个参数可以是inliers,也可以是outliers。输入点云cloud中所有点的索引或者说是下标肯定是0~n-1,0是第一个点的索引,n-1为最后一个点的索引,n是cloud包含的点数。

通常,想查看点云cloud中某个点的坐标,一般都会写成cloud->points[index],这个index的范围就是0到n-1。std::iota(indices.begin(), indices.end(), 0);这句代码运行之后,就会得到一个cloud点云索引的容器,存放着0,1,2,3,4,5 … n-3,n-2,n-1。而inliers则是存放输内点索引的容器,std::set_difference(indices.begin(), indices.end(), inliers.begin(), inliers.end(), std::back_inserter(outliers));这句代码就是将点云cloud的全部索引indices与内点索引inliers进行比较,其中indices中有但是inliers中没有的索引值则存放进outliers。最后,用pcl::copyPointCloud(*cloud, outliers, *cloud_out);就提取到了外点点云。

运行时间对比如下图所示,可以发现内点运行时间还长一点,而外点提取时间还短一点。这个其实跟点的数量有关系,如果内点的数量多,当然就更耗时。但是总的来说,无论是提取内点还是外点,使用上述方法都是比较快的,而且很方便。
在这里插入图片描述

方法二:
除了上述方法之外,PCL库中特意集成有相应的方法提取点云的内点或者外点。
代码:

/// <summary>
/// 使用PCL库中pcl::ExtractIndices方法进行内点和外点的提取
/// </summary>
/// <param name="cloud">输入点云</param>
/// <param name="inliers">内点的索引数组</param>
/// <param name="cloudout">输出点云</param>
/// <param name="is_in">输入true则提取内点点云,输入false则提取外点点云</param>
/// <returns>return true则表示提取成功,return false则表示提取失败</returns>
bool ExtractCloudByIndices(const pcl::PointCloud<pcl::PointXYZ>::Ptr& cloud, const std::vector<int>& inliers, pcl::PointCloud<pcl::PointXYZ>::Ptr& cloudout, const bool& is_in)
{if (cloud == nullptr) return false;if (cloud->points.size() < 10) return false;if (cloudout == nullptr) cloudout.reset(new pcl::PointCloud<pcl::PointXYZ>);pcl::PointIndices::Ptr pinliers(new pcl::PointIndices());pinliers->indices.assign(inliers.begin(), inliers.end());pcl::ExtractIndices<pcl::PointXYZ> extractor;extractor.setInputCloud(cloud);extractor.setIndices(pinliers);extractor.setNegative(!is_in); //如果设为true,可以提取指定index之外的点云extractor.filter(*cloudout);return true;
}

上述代码中extractor.setNegative(!is_in);就是设置提取内点还是外点的成员函数。如果extractor.setNegative(true);即输入的是true,则提取除了inliers以外的,也就是外点的点云,而extractor.setNegative(false);才是提取inliers索引的点云,与方法一中的习惯相反,为了调整成一致,所以传入的是!is_in,而不是is_in。这个时候就与方法一保持一样的习惯了。

此外,还有一点不同的是pcl::ExtractIndices所需要的传入的索引不是std::vector 而必须是pcl::PointIndices::Ptr。其实这两种数据结构是可以互相转化的,所以用 pinliers->indices.assign(inliers.begin(), inliers.end());这句代码进行了一次转化。当然,在使用PCL库中算法时,有时候得到的不一定是std::vector,而是pcl::PointIndices::Ptr。这个就看每个人的习惯和喜好去封装函数了,也可以封装成一个传参为pcl::PointIndices::Ptr数据的函数。

运行结果如下:
在这里插入图片描述
可以从结果看出,方法二的耗时要比方法一长“很多”。具体使用哪种方法进行点云内点或者外点的提取则是要看个人习惯了。

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

BAQ压缩原理

什么是BAQ? BAQ——Block Adaptive Quantization,块自适应量化 BAQ是一种数据压缩算法。 谁提出了BAQ压缩? BAQ压缩原理是由美国NASA JPL的R. Kwok和W.T.K. Johnson在1989年提出的。第一次被用于美国NASA的“麦哲伦金星探测”任务中。 BAQ压缩的目的是什么? 上世纪后半…

面试 Java 算法高频题五问五答第一期

面试 Java 算法高频题五问五答第一期 作者&#xff1a;程序员小白条&#xff0c;个人博客 相信看了本文后&#xff0c;对你的面试是有一定帮助的&#xff01; ⭐点赞⭐收藏⭐不迷路&#xff01;⭐ 1&#xff09;括号生成: 数字 n 代表生成括号的对数&#xff0c;请你设计一个…

动态规划——OJ题(一)

&#x1f4d8;北尘_&#xff1a;个人主页 &#x1f30e;个人专栏:《Linux操作系统》《经典算法试题 》《C》 《数据结构与算法》 ☀️走在路上&#xff0c;不忘来时的初心 文章目录 一、第N个泰波那契数1、题目讲解2、思路讲解3、代码实现 二、三步问题1、题目讲解2、思路讲解…

数据结构与算法—哈希表

哈希表 文章目录 哈希表1. 问题引出2. 基本介绍3. 应用实例 1. 问题引出 看一个实际需求&#xff0c;google公司的一个上机题:有一个公司&#xff0c;当有新的员工来报道时&#xff0c;要求将该员工的信息加入(id,性别&#xff0c;年龄等)&#xff0c;当输入该员工的id时&#…

关于MySQL的bigint问题

MySQL的bigint(8)能存多大数值&#xff1f; MySQL的BIGINT(8)可以存储的数值范围是从-9,223,372,036,854,775,808到9,223,372,036,854,775,807。这是因为BIGINT数据类型在MySQL中使用8字节进行存储&#xff0c;每个字节有8位&#xff0c;所以总共可以表示2^64个不同的整数。 …

C语言复习之结构体指针 ; 函数指针

结构体指针 不可以这样定义&#xff1a; 应该这样定义&#xff1a;加上指针&#xff0c;因为指针是4个字节&#xff0c;这样的话&#xff0c;他的大小就确定下来了。 一个是表示结构体&#xff0c;一个是表示结构体的指针。 很容易理解&#xff0c;脑子里要有内存图。 结构…

Yoast SEO Premium v21.7 Premium WordPress 插件Yoast +子插件介绍

什么是Yoast SEO&#xff1f; Yoast SEO 是 WordPress 的 SEO 插件&#xff0c;可帮助网站所有者针对搜索引擎优化他们的网站。该插件由 Joost de Valk 于 2008 年创建&#xff0c;旨在让每个人都能访问 SEO。今天&#xff0c;Yoast SEO 是全球数百万 WordPress 用户使用的最受…

目标跟踪 MOT数据集和可视化

目录 MOT15数据集格式简介 gt可视化 本人修改的GT可视化代码&#xff1a; MOT15数据集格式简介 以下内容转自&#xff1a;【目标跟踪】MOT数据集GroundTruth可视化-腾讯云开发者社区-腾讯云 MOT15数据集下载&#xff1a;https://pan.baidu.com/s/1foGrBXvsanW8BI4eybqfWg?…

数据结构之---- 分治算法

数据结构之---- 分治算法 什么是分治算法&#xff1f; 分治&#xff0c;全称分而治之&#xff0c;是一种非常重要且常见的算法策略。 分治通常基于递归实现&#xff0c;包括 分 和 治 两个步骤&#xff1a; 分&#xff08;划分阶段&#xff09;&#xff1a;递归地将原问题分…

数据高可用架构设计与实现

大型企业如何实现 MySQL 到 Redis 的同步 前面曾提到过 Read/Write Through 和 Cache Aside 这几种更新缓存的模式或者说策略&#xff0c;这几种策略都存在缓存不命中的可能性&#xff0c;如果缓存没有命中&#xff0c;就需要直接访问数据库以获取数据。—般情况下&#xff0c…

Y4M视频文件格式

什么是Y4M 以YUV4Mpeg格式创建的视频文件;这个视频文件存储了一组未压缩的YCbCr图像&#xff0c;这些图像逐帧组成视频;在压缩成MPEG-2或Matroska等更流行的视频格式之前&#xff0c;用作原始的彩色视频格式 Y4M文件是一个纯文本格式的header开始&#xff0c;header有0或多个…

【经典LeetCode算法题目专栏分类】【第2期】组合与排列问题系列

《博主简介》 小伙伴们好&#xff0c;我是阿旭。专注于人工智能、AIGC、python、计算机视觉相关分享研究。 ✌更多学习资源&#xff0c;可关注公-仲-hao:【阿旭算法与机器学习】&#xff0c;共同学习交流~ &#x1f44d;感谢小伙伴们点赞、关注&#xff01; 组合总和1 class So…