曲线降采样之道格拉斯-普克算法Douglas–Peucker

曲线降采样之道格拉斯-普克算法Douglas–Peucker

该算法的目的是,给定一条由线段构成的曲线,找到一条点数较少的相似曲线,来近似描述原始的曲线,达到降低时间、空间复杂度和平滑曲线的目的。

image

附赠自动驾驶学习资料和量产经验:链接

示例(B中红色为降采样后的曲线)

image

算法流程

image

image

image

4. 此时算法已经完成了一个循环,后续按照递归的方式,分别对线段p1-p6和p6-p7进行同样的处理,p6-p7之间的点已经处理完,则直接结束;距离p1-p6线段最远的点为p5,p5到线段距离大于image,则p5也是需要保留的点;

image

image

5. 同理,p5-p6线段之间无待处理点,直接结束;距离p1-p5线段最远的点为p3,其到线段的距离仍大于image,则保留p3;

image

image

6. 距离线段p1-p3最远的点为p2,其距离小于image,将p1到p3中间所有的点标记为忽略;距离线段p3-p5最远的点为p4,其距离也小于image,将p3-p5之间所有待处理点标记为忽略;

7. 至此,算法结束,上述过程中,所有组成线段的端点即为降采样后曲线的点。

时间复杂度

引用:https://zh.wikipedia.org/wiki/%E9%81%93%E6%A0%BC%E6%8B%89%E6%96%AF-%E6%99%AE%E5%85%8B%E7%AE%97%E6%B3%95

image

代码

  • 定义基本结构和工具函数

    // 二维点
    struct Point2D {
    double x;
    double y;
    Point2D() : x(0.0), y(0.0) {}
    Point2D(double x, double y) : x(x), y(y) {}
    };

    // 计算点到线段的距离
    double DouglasPeucker::GetDistanceOnLine(const Point2D &start,
    const Point2D &end,
    const Point2D &point) {
    float a = end.y - start.y;
    float b = start.x - end.x;
    float c = end.x * start.y - start.x * end.y;
    return std::fabs(a * point.x + b * point.y + c) / std::sqrt(a * a + b * b);
    }

  • 核心处理函数

    std::vector
    DouglasPeucker::Process(const std::vector &points_in,
    const double delta) {
    std::vector result;
    // points为需要处理的点集,其中第一个和最后一个点为线段的端点,delta为误差阈值
    // step1. 找到距离线段最远的点
    double max_dist = -1;
    int max_idx = -1;
    // 两头的点默认是保留的, 不需要进行计算
    for (int i = 1; i < points_in.size() - 1; i++) {
    double d = GetDistanceOnLine(points_in[0], points_in[points_in.size() - 1],
    points_in[i]);
    if (d > max_dist) {
    max_dist = d;
    max_idx = i;
    }
    }
    // step2. 如果最远点的距离大于阈值,则将其作为新的线段端点,递归处理
    if (max_dist > delta) {
    std::vector left_pts, right_pts;
    left_pts.reserve(max_idx + 1);
    right_pts.reserve(points_in.size() - max_idx);
    for (int i = 0; i <= max_idx; i++) {
    left_pts.push_back(points_in[i]);
    }
    for (int i = max_idx; i < points_in.size(); i++) {
    right_pts.push_back(points_in[i]);
    }
    std::vector left_result = DouglasPeucker::Process(left_pts, delta);
    std::vector right_result =
    DouglasPeucker::Process(right_pts, delta);
    result.insert(result.end(), left_result.begin(), left_result.end() - 1);
    result.insert(result.end(), right_result.begin(), right_result.end());
    } else { // 两种情况到这里: 点到线段的最大距离小于阈值,或者只有两个点
    result.push_back(points_in[0]);
    result.push_back(points_in[points_in.size() - 1]);
    }
    return result;
    }

  • 运行,将上述p1… p7组成的曲线进行降采样, image

    int main()
    {
    std::vectorAD::Point2D points_in;
    points_in.push_back(AD::Point2D(0.0, 5.0)); // p1
    points_in.push_back(AD::Point2D(1.0, 4.0)); // p2
    points_in.push_back(AD::Point2D(2.0, 3.2)); // p3
    points_in.push_back(AD::Point2D(3.0, 4.5)); // p4
    points_in.push_back(AD::Point2D(4.0, 4.7)); // p5
    points_in.push_back(AD::Point2D(5.0, 1.0)); // p6
    points_in.push_back(AD::Point2D(7.0, 6.0)); // p7
    std::vectorAD::Point2D points_out;
    points_out = AD::DownSampling::DouglasPeucker::Process(points_in, 0.5);
    for (auto &point : points_out) {
    std::cout << "x: " << point.x << ", y: " << point.y << std::endl;
    }

    return 0;
    }

    // 输出
    x: 0, y: 5 // p1
    x: 2, y: 3.2 // p3
    x: 4, y: 4.7 // p5
    x: 5, y: 1 // p6
    x: 7, y: 6 // p7

算法缺点

  • 需要调参,但通常参数也比较好确定;

  • 时间复杂度不稳定;

  • 自顶向下的递归优化,不一定能保证是全局最优,前面做出的选择会影响后续的结果。

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

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

相关文章

通过提交容器的方式修改ubuntu镜像的apt源

通过提交容器的方式修改ubuntu镜像的apt源 步骤总结 问题&#xff0c;每次创建容器之后&#xff0c;都要在容器内手动更改镜像源。 不如&#xff0c;干脆修改镜像的apt源&#xff0c;一次到位。 步骤 先创建一个容器&#xff0c;到容器内执行变更命令。 D:/sandbox> dock…

【Vue】vue3简介与环境配置

文章目录 项目编码规范什么是 Vue&#xff1f;安装node环境nvm针对node版本惊醒管理的工具 项目编码规范 组合式API Typescript setup(语法糖) 什么是 Vue&#xff1f; Vue 是一款用于构建用户界面的 JavaScript 框架。它基于标准 HTML、CSS 和 JavaScript 构建&#xff0c;…

【SQL】1633. 各赛事的用户注册率(COUNT函数 表达式用法)

题目描述 leetcode题目&#xff1a;1633. 各赛事的用户注册率 Code select contest_id, round(count(*)/(select count(*) from Users)*100, 2) as percentage from Register group by contest_id order by percentage desc, contest_id ascCOUNT()函数 COUNT函数用法&#…

docker容器之etcd安装

一、etcd介绍 1、etcd是什么 etcd是CoreOS团队于2013年6月发起的开源项目&#xff0c;它的目标是构建一个高可用的分布式键值(key-value)数据库。 2、etcd特点 简单的接口&#xff0c;通过标准的HTTP API进行调用&#xff0c;也可以使用官方提供的 etcdctl 操作存储的数据。…

1999-2022年上市公司员工人数数据

1999-2022年上市公司员工人数数据 1、时间&#xff1a;1999-2022年 2、指标&#xff1a;证券代码、时间、员工人数 3、来源&#xff1a;整理自csmar 4、范围&#xff1a;上市公司 5、指标解释&#xff1a; 上市公司员工人数是衡量公司规模和发展状的重要指标。该数据直接…

编程新手必看,python中的转义字符及注释!(4)

1、常见的转义字符 Python中的转义字符用于在字符串中表示一些特殊的字符&#xff0c;这些字符通常无法直接输入或具有特殊的意义。以下是一些常见的转义字符及其含义&#xff1a; 在Python中&#xff0c;可以使用转义字符来表示一些特殊的字符。以下是使用转义字符的几种常见…

VuePress基于 Vite 和 Vue 构建优秀框架

VitePress 是一个静态站点生成器 (SSG)&#xff0c;专为构建快速、以内容为中心的站点而设计。简而言之&#xff0c;VitePress 获取用 Markdown 编写的内容&#xff0c;对其应用主题&#xff0c;并生成可以轻松部署到任何地方的静态 HTML 页面。 VitePress 附带一个用于技术文档…

Java复习第十六天学习笔记(JSP、Servlet),附有道云笔记链接

【有道云笔记】十六 4.2 JSP、Servlet https://note.youdao.com/s/QccA5g1G 一、软件的结构 C/S (Client - Server 客户端-服务器端) 典型应用&#xff1a;QQ软件 &#xff0c;飞秋&#xff0c;印象笔记。 特点&#xff1a; 必须下载特定的客户端程序。服务器端升级&#…

保护Android应用安全:全面探究代码混淆在加固中的作用

Android APP 加固是优化 APK 安全性的一种方法&#xff0c;常见的加固方式有混淆代码、加壳、数据加密、动态加载等。下面介绍一下 Android APP 加固的具体实现方式。 混淆代码 使用 ipaguard工具可以对代码进行混淆&#xff0c;使得反编译出来的代码很难阅读和理解&#xff…

CSS面试题---基础

1、css选择器及优先级 选择器优先级&#xff1a;内联样式>id选择器>类选择器、属性选择器、伪类选择器>标签选择器、微元素选择器 注意&#xff1a; !important优先级最高&#xff1b; 如果优先级相同&#xff0c;则最后出现的样式生效&#xff1b; 继承得到的样式优先…

腾讯云2024年4月优惠券及最新活动入口

腾讯云是腾讯集团倾力打造的云计算品牌&#xff0c;提供全球领先的云计算、大数据、人工智能等技术产品与服务。为了吸引用户上云&#xff0c;腾讯云经常推出各种优惠活动。本文将为大家分享腾讯云优惠券及最新活动入口&#xff0c;助力大家轻松上云&#xff01; 一、优惠券领取…

大模型prompt技巧——思维链(Chain-of-Thought)

1、Zero-shot、One-shot、Few-shot 与fintune prompt的时候给出例子答案&#xff0c;然后再让模型回答。 2、zero-shot-CoT “Let’s think step by step”有奇迹效果 3、多数投票提高CoT性能——自洽性&#xff08;Self-consistency&#xff09; 多个思维链&#xff0c;然后取…

浪潮分布式存储AS13000G6-M36改扩配后管理界面不能识别和标记硬盘的处理方法

AS13000G6 改配出问题的场景 浪潮分布式存储AS13000G6-M36渠道备货的分布式存储通常是流量机型&#xff0c;实际出货可能会涉及改配 集群部署完以后建议在系统视图下查看一下盘是否能识别 这个是正常的情况&#xff0c;可以正确管理到盘,硬盘侧边有绿色的指示灯。 如图是管理…

如果符合这7点,说明你经历过职场PUA。

今天聊聊在职场中比较普遍&#xff0c;但又容易被忽视的问题——职场PUA。 工作是为了更好的生活&#xff0c;但有时候可能会发现&#xff0c;这份工作怎么越做越不对劲&#xff0c;感觉像是偏航了。 简单来说&#xff0c;职场PUA就是一种精神控制&#xff0c;常常以批评和否…

java的警示之有危险的行为

&#x1f468;‍&#x1f4bb;作者简介&#xff1a;&#x1f468;&#x1f3fb;‍&#x1f393;告别&#xff0c;今天 &#x1f4d4;高质量专栏 &#xff1a;☕java趣味之旅 欢迎&#x1f64f;点赞&#x1f5e3;️评论&#x1f4e5;收藏&#x1f493;关注 &#x1f496;衷心的希…

MATLAB科研绘图与学术图表绘制从入门到精通

&#x1f482; 个人网站:【 摸鱼游戏】【神级代码资源网站】【工具大全】&#x1f91f; 一站式轻松构建小程序、Web网站、移动应用&#xff1a;&#x1f449;注册地址&#x1f91f; 基于Web端打造的&#xff1a;&#x1f449;轻量化工具创作平台&#x1f485; 想寻找共同学习交…

vue-ueditor-wrap上传图片报错:后端配置项没有正常加载,上传插件不能正常使用

如图所示,今天接收一个项目其中富文本编辑器报错 此项目为vue2项目,富文本编辑器为直接下载好的资源存放在public目录下的 经过排查发现报错的函数在ueditor.all.min.js文件内,但是ueditor.all.min.js文件夹是经过压缩的 所以直接,将index.html中的引用路径修改为ueditor…

C++算法——滑动窗口

一、长度最小的子数组 1.链接 209. 长度最小的子数组 - 力扣&#xff08;LeetCode&#xff09; 2.描述 3.思路 本题从暴力求解的方式去切入&#xff0c;逐步优化成“滑动窗口”&#xff0c;首先&#xff0c;暴力枚举出各种组合的话&#xff0c;我们先让一个指针指向第一个&…

“探秘数据结构:栈的奇妙魔力“

每日一言 兰有秀兮菊有芳&#xff0c;怀佳人兮不能忘。 —刘彻- 栈 栈的概念及结构 栈(Stack) &#xff1a;一种特殊的线性表&#xff0c;其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶&#xff0c;另一端称为栈底。栈中的数据元素遵守…

Python深度学习034:cuda的环境如何配置

文章目录 1.安装nvidia cuda驱动CMD中看一下cuda版本:下载并安装cuda驱动2.创建虚拟环境并安装pytorch的torch_cuda3.测试附录1.安装nvidia cuda驱动 CMD中看一下cuda版本: 注意: 红框的cuda版本,是你的显卡能装的最高的cuda版本,所以可以选择低于它的版本。比如我的是11…