道格拉斯普克算法(DP)的点云轮廓线简化

news2024/11/28 2:31:06

1、背景介绍

       由于点云无法精确刻画目标对象边缘信息,因此常规提取的边缘点直接相连所生成的轮廓线,锯齿现象显著,与真实情况相差甚远(图b所示)。

      道格拉斯-普克(Douglas-Peuker)抽稀算法是用来对大量冗余的图形数据点进行压缩以提取必要的数据点。利用DP算法实现的轮廓线简化结果,如图c,其真实反应了点云形状。因此,在实际点云三维重建中,DP算法常用于点云简化,进而用于后续三维重建。

(a)原始点云(b)边缘点直接相连(c)DP算法简化后轮廓

 2、DP原理介绍

        道格拉斯普克算法(Douglas-Peukcer)算法是一种简化线状要素的经典算法。对每一条曲线的首末点虚连一条直线,求所有点与直线的距离,并找出最大距离值dmax,用dmax与距离阈值D相比。若dmax<D,这条曲线上的中间点全部舍去;若dmax ≥D,保留dmax对应的坐标点,并以该点为界,把曲线分为两部分,对这两部分重复使用该方法。

         算法的详细步骤如下:

(1) 在散点首尾两点间连一条直线,求出其余各点到该直线的距离(如图1、3、5中红色直线)。

(2) 选其最大者与阈值相比较,若大于阈值,则离该直线距离最大的点保留,否则将直线两端点间各点全部舍去(如图2相对图1中增加的点、图4相对图3增加的点)

(3) 依据所保留的点,将已知曲线分成两部分处理,重复第1、2步操作,迭代操作,即仍选距离最大者与阈值比较,依次取舍,直到无点可舍去,最后得到满足给定精度限差的点,舍去其他点,即完成线的化简。如图6中最终剩下的点。

(1)(2)
(3)(4)
(5)(6)

3、程序编程思想

     通过对DP算法原理介绍,发现该算法是一种递归思想,将点云一直划分成左右两部分,类似构建二叉树过程。首先对输入的一组点,判断其是否需要分组。

判断是否需要分组

     当最大距离大于阈值时,需要进行划分成左右两部分(以4号点断开),如下图所示:

     对于每一部分,采用上边类似的思想,判断递归下去,直至不再分成左右两棵树。

    本程序编写过程:

3.1 边缘点提取

     使用alpha shapes提取轮廓点,并对其进行排序,得到有序轮廓点

boundExtract(cloud, r, bound, non_bound);

3.2 确定初始轮廓点分组    

    选取轮廓点中距离最远的两个点,依据这两个点确定是否需要将原始点进行分组。本程序采用x、y对应的最值(xmin、xmax、ymin、ymax)确定距离最远的两点。

GetTwoPointsMaxDis(bound, headpoint, endpoint, headindex, endindex);

相距最远两点

      其中划分组的策略如下:头部点对应的序列号(11)与尾部点序列号(62)之间的点(即11-62)化为一组,然后采62-93与1-11和起来分为一组。

3.3 对于每组点构造二叉树

     通过对点分组,确定头、尾节点。再根据位于头尾节点中的点,确定待要划分的关键点。节点示意如下:

struct DPNode
{
	pcl::PointXYZ HeadPoint;
	pcl::PointXYZ EndPoint;
	vector<pcl::PointXYZ> points;
	DPNode *Left_node;//左边节点
	DPNode *Right_node;//右边节点
	bool NodeType;//该节点是否可以继续划分,若可以则是true,否则为false
};

3.4 遍历二叉树寻找关键节点

   采用前序遍历的方式(即先遍历左结点),找到关键点,关键节点为将点云划分为2组的点。

if (maxds < thres_ds)//小于阈值的,不再分割
		{
			root->Left_node = NULL;
			root->Right_node = NULL;
			root->NodeType = false;//不能再划分
		}
		else
		{
			root->NodeType = true;//可以继续划分

			//将点划分成2部分,左边与右边
			vector<pcl::PointXYZ> Leftpointsvec, Rightpointsvec;
			for (int i = 0; i < points.size(); i++)
			{
				if (i <= maxindex)
				{
					Leftpointsvec.push_back(points[i]);//左边树包含的点
				}
			}

			for (int i = 0; i < points.size(); i++)
			{
				if (i >= maxindex)
				{
					Rightpointsvec.push_back(points[i]);//右边树包含的点
				}
			}
			//左边子树的头部点与尾部点
			pcl::PointXYZ left_headpoint = headpoint;
			pcl::PointXYZ left_endpoint = points[maxindex];

			//右边子树的头部点与尾部点
			pcl::PointXYZ right_headpoint = points[maxindex];
			pcl::PointXYZ right_endpoint = endpoint;

			//创建左、右树
			root->Right_node = new DPNode();
			BuildTree(root->Left_node, Leftpointsvec, left_headpoint, left_endpoint, thres_ds);
			BuildTree(root->Right_node, Rightpointsvec, right_headpoint, right_endpoint, thres_ds);
		}

3.5 剔除重复关键点与排序

      利用先序遍历,获取所有的关键点,即头、尾点,再对重复的关键点剔除,得到最终精简的轮廓关键点。

4、测试验证

     根据上述原理,本程序基于PCL、C++进行实现。将“道格拉斯-普克 .cpp”文件放入原文件下,如下图所示:

cpp文件存放示意图

4.1 边缘提取测试

         可以发现,两个点云数据中边缘点,均被成功提取出,其中红色点为边缘点,白色点为非边缘点。

边缘提取示意图边缘提取示意图

4.2 边缘点有序测试

       直接将提取的边缘点进行相连,若能够刻画点云形状,则说明点云有序。如下图所示,虽然直接将点进行相连,锯齿现象比较明显,但是其仍大体刻画点云形状,证明提取的轮廓点为有序结构。

轮廓点相连轮廓点相连

4.3 DP简化点云测试

      使用各类不同形状的点云数据进行测试,可以发现点云边缘简化结果相当理想,比较简单,证明本程序能够正常运行,精简点云数据。

5、小结

    DP算法计算原理简单,精简点云效果理想,简化结果只与点到直线距离有关。理论上,当距离阈值设置越大,那么舍弃的点越多,关键点越少。因此,在实际使用过程中,需要根据需要设置参数。

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

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

相关文章

java 使用hh或者HH异常

故障描述 使用了HH或者hh使用时间format、DatetimeFormat注解时序列化失败 故障原因 当使用hh的时候&#xff0c;小时只能是1-24 使用KK的时候&#xff0c;小时只能是0-23 比如&#xff1a;凌晨0:30&#xff0c;使用hh就是0:30 am&#xff0c; kk就是12:30 24小时制的话,使…

01-02-4

1、中级阶段-day1作业 使用的代码 #include<stdio.h> typedef struct Student {int num;char name[20];char sex; }Stu; int main() {Stu s;scanf("%d%s %c", &s.num, s.name, &s.sex);//读取字符串时&#xff0c;scanf()的占位符用%s即可&#xff0c…

重大升级 | OpenSCA SaaS全面接入供应链安全情报!

结合社区用户反馈及研发小伙伴的积极探索&#xff0c; OpenSCA 项目组再次发力&#xff0c;SaaS版本重大升级啦&#xff01; 用户的需求是OpenSCA前进的动力&#xff0c;欢迎更多感兴趣的朋友们积极试用和反馈~ 更 新 内 容 1.全面接入云脉XSBOM供应链安全情报 2.强大的资产…

【异常】SpringBoot整合RabbitMQ-发送消息报错

错误信息 reply-code406, reply-textPRECONDITION_FAILED - inequivalent arg ‘x-message-ttl’ for queue ‘hello-queue’ in vhost ‘/lq’: received none but current is the value ‘10000’ of type ‘signedint’, class-id50, method-id10 错误原因 hello-queue这…

省公派访学|社科老师赴世界名校牛津大学开展研究

F老师已获某省公派出国访学半年的资助&#xff0c;希望落实的学校尽量知名。但因为F老师只是硕士毕业而无博士学位&#xff0c;专业方向又是社科类&#xff0c;所以申请到世界知名高校有一定难度。经过努力&#xff0c;最终我们获得了世界顶尖高校-英国牛津大学的访问学者邀请函…

C++常见十种排序方式

目录 前言 1、选择排序 介绍 参考代码 2、冒泡排序 介绍 参考代码 3、插入排序 介绍 参考代码 4、希尔排序 介绍 参考代码 5、快速排序 介绍 参考代码 6、并归排序 介绍 参考代码 7、堆排序 介绍 参考代码 8、基数排序 介绍 参考代码 9、计数排序 介绍 参考代…

用户需求甄别和筛选的6大标准

产品经理日常经常接收到大量的需求&#xff0c;并不是所有的需求都需要开发&#xff0c;需要进行甄别和筛选&#xff0c;这样有利于确保项目的成功、优化资源利用以及提高产品质量。 那么针对这些用户需求进行甄别或筛选的评判标准是什么&#xff1f;需求筛选可以说是初步的需求…

设计模式-工厂模式设计与详解

一、设计模式介绍 设计模式是我们开发中常常需要面对的核心概念&#xff0c;它们是解决特定问题的模板或者说是经验的总结。这些模式被设计出来是为了让软件设计更加清晰、代码更加可维护且能应对未来的变化。良好的设计模式不仅能解决重复代码的问题&#xff0c;还能使团队中…

关于修改ant-design-vue的table组件背景色遇到闪动的问题

项目中需要修改表格的背景色为以下样式 修改完之后发现表格行还有个hover的背景色&#xff0c;于是再次重置样式如下 .ant-table-tbody > tr {&:hover {td {// background: red !important;background: transparent !important;}}}这样重置之后&#xff0c;hover的样式…

【中级软件设计师】上午题16-算法(应试考试简略版)

上午题16-算法 1 回溯法1.1 n皇后问题 2 分治法3 动态规划3.1 0-1背包问题3.2 最长公共子序列3.3 矩阵连乘 4 贪心算法5 分支限界法总结 1 回溯法 深度优先方法搜索 1.1 n皇后问题 2 分治法 一般来说&#xff0c;分治算法在每一层递归上都有3个步骤 &#xff08;1&#xff…

【C++】详解STL的适配器容器之一:优先级队列 priority_queue

目录 堆算法 概述 向下调整建堆 向上调整建堆 建堆算法 仿函数 概述 使用介绍 emtpy size top push pop 模拟实现 仿函数 框架 向下调整算法 向上调整算法 pop push empty top 要理解优先级队列&#xff0c;需要有如下知识 STL容器之一的vector&#xf…

嵌入式:基于STM32的RFID访问控制系统

在商业和住宅建筑中&#xff0c;访问控制系统是确保安全的关键组件。使用射频识别&#xff08;RFID&#xff09;技术&#xff0c;我们可以创建一个安全、方便的门禁系统。本教程将详细说明如何使用STM32微控制器实现RFID基础的门禁系统&#xff0c;该系统能够控制电子锁并记录访…

品鉴中的品鉴笔记:如何记录和分享自己的品鉴心得

品鉴云仓酒庄雷盛红酒的过程&#xff0c;不仅是品尝美酒&#xff0c;更是一次与葡萄酒深度对话的旅程。为了更好地记录和分享自己的品鉴心得&#xff0c;养成写品鉴笔记的习惯是十分必要的。 首先&#xff0c;选择一个适合的记录工具。可以是传统的笔记本&#xff0c;也可以是…

爆!1688「搜索推广」实操打法,8大要点快速上手!

想要1688平台上提高商品的搜索排名和曝光率&#xff0c;吸引更多的潜在客户并提升销量&#xff0c;店雷达将尽量具体地介绍相关操作方法和运营思路&#xff0c;建议大家收藏起来慢慢看。 一、了解1688平台搜索方式 1、品搜&#xff1a;这是买家最常用的搜索方式&#xff0c;通…

消息中间件是什么?有什么用?常见的消息中间件有哪些?

1.什么是消息中间件&#xff1f; 消息中间件基于队列模型在网络环境中为应用系统提供同步或异步、可靠的消息传输的支撑性软件系统。 2.现实中的痛点&#xff1a; 1.Http请求基于请求与响应的模型&#xff0c;在高并发的情况下&#xff0c;客户端发送大量的请求达到服务器端…

C# WinForm —— 19 PictureBox 介绍

1. 简介 PictureBox 主要用于显示图像&#xff0c;也可以给它注册单击事件&#xff0c;来把它变成一个按钮 2. 常用属性 属性解释(Name)控件ID&#xff0c;在代码里引用的时候会用到,一般以 pixB 开头BackColor控件的背景色BackgroundImage控件的背景图像BorderStylePictur…

开放式耳机什么品牌最好?2024五款新晋爆款产品推荐!

​如今的耳机市场天下三分&#xff0c;有线入耳式耳机、蓝牙无线入耳式耳机以及开放式耳机&#xff0c;传统的有线入耳式耳机戴着不稳就算了&#xff0c;线很容易揉成一团&#xff0c;看着就头大&#xff1b;无线入耳式的耳机&#xff0c;同样面临着戴着不稳的问题&#xff0c;…

如何在群晖NAS中开启FTP并实现使用公网地址远程访问传输文件

文章目录 1. 群晖安装Cpolar2. 创建FTP公网地址3. 开启群晖FTP服务4. 群晖FTP远程连接5. 固定FTP公网地址6. 固定FTP地址连接 本文主要介绍如何在群晖NAS中开启FTP服务并结合cpolar内网穿透工具&#xff0c;实现使用固定公网地址远程访问群晖FTP服务实现文件上传下载。 Cpolar内…

Nginx内网环境开启https

文章目录 前言一、open-ssl1. 验证2. 安装3.生成ssl证书 一、nginx1. 验证支持模块2. 安装必要模块2.1 重新编译nginx2.2 替换原文件 3. 配置https 总结 前言 nginx开启https前提&#xff1a; 服务器支持open-sslnginx 包含--with-http_ssl_module --with-stream --with-stre…

JavaScript原理篇——Promise原理及笔试题实战演练

Promise 是 JavaScript 中用于处理异步操作的对象&#xff0c;它代表了一个可能还没有完成的操作的最终完成或失败&#xff0c;以及其结果值。Promise 对象有三种状态&#xff1a; Pending&#xff08;进行中&#xff09;&#xff1a;初始状态&#xff0c;既不是成功&#xff0…