曲线降采样之道格拉斯-普克算法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

算法缺点

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

  • 时间复杂度不稳定;

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【与C++的邂逅】---- 函数重载与引用

关注小庄 顿顿解馋(▿) 喜欢的小伙伴可以多多支持小庄的文章哦 &#x1f4d2; 数据结构 &#x1f4d2; C 引言 : 上一篇博客我们了解了C入门语法的一部分&#xff0c;今天我们来了解函数重载&#xff0c;引用的技术&#xff0c;请放心食用 ~ 文章目录 一. &#x1f3e0; 函数重…

windows搭建ftp实现局域网共享文件

一、开启ftp服务 1.使用 win Q 键&#xff0c;快捷打开搜索框 2.搜索框内搜索 “控制面板” 3. 进入控制面板内选择 ”程序“ 4. 单击进入 “启用或关闭windows功能” 5. 找到并展开“internet information services”、 6. 建议展开后全选 “FTP服务器” 和 “web管理工…

OpenHarmony实战:轻量系统芯片移植

本文从芯片适配的端到端视角&#xff0c;为芯片/模组制造商提供基于OpenHarmony的芯片适配指导。典型的芯片架构&#xff0c;例如cortex-m、risc-v系列都可以按照本文档进行适配移植。 约束与限制 本文档适用于OpenHarmony LTS 3.0.1及之前版本的轻量系统的适配。 说明&#…

Redis中的复制功能(三)

复制 服务器运行ID 除了复制偏移量和复制积压缓冲区之外&#xff0c;实现部分重同步还需要用到服务器运行ID(run ID): 1.每隔Redis服务器&#xff0c;不论主服务器还是从服务&#xff0c;都会有自己的运行ID2.运行ID在服务器启动时自动生成&#xff0c;由40个随机的十六进制…

ndk ffmpeg

报错&#xff1a; 解决办法&#xff1a; 报错 解决办法&#xff1a;

大模型量化技术-GPTQ

大模型量化技术-GPTQ 2022年,Frantar等人发表了论文 GPTQ:Accurate Post-Training Quantization for Generative Pre-trained Transformers。 这篇论文详细介绍了一种训练后量化算法,适用于所有通用的预训练 Transformer模型,同时只有微小的性能下降。 GPTQ算法需要通过…

vscode安装通义灵码

作为vscode的插件&#xff0c;直接使用 通义灵码-灵动指间&#xff0c;快码加编&#xff0c;你的智能编码助手 通义灵码&#xff0c;是一款基于通义大模型的智能编码辅助工具&#xff0c;提供行级/函数级实时续写、自然语言生成代码、单元测试生成、代码注释生成、代码解释、研…

性能测试?

一、什么是性能测试 先看下百度百科对它的定义 性能测试是通过自动化的测试工具模拟多种正常、峰值以及异常负载条件来对系统的各项性能指标进行测试。我们可以认为性能测试是&#xff1a;通过在测试环境下对系统或构件的性能进行探测&#xff0c;用以验证在生产环境下系统性…

苹果手表Apple Watch录了两个半小时的录音,却只能播放4秒,同步到手机也一样,还能修复好吗?

好多人遇到这个情况&#xff0c;用苹果手表Apple Watch录音&#xff0c;有的录1个多小时&#xff0c;有的录了3、4小时&#xff0c;甚至更长时间&#xff0c;因为手表没电&#xff0c;忘记保存等原因造成录音损坏&#xff0c;都是只能播放4秒&#xff0c;同步到手机也一样&…

Java8 Stream API全面解析——高效流式编程的秘诀

文章目录 什么是 Stream Api?快速入门流的操作创建流中间操作filter 过滤map 数据转换flatMap 合并流distinct 去重sorted 排序limit 限流skip 跳过peek 操作 终结操作forEach 遍历forEachOrdered 有序遍历count 统计数量min 最小值max 最大值reduce 聚合collect 收集anyMatch…

git源码泄露

Git 源码泄露 开发人员会使用 git 进行版本控制&#xff0c;对站点自动部署。但如果配置不当&#xff0c;可能会将 .git 文件夹直接部署到线上环境&#xff0c;这就引起了 git 泄露漏洞&#xff0c;我们可以利用这个漏洞直接获得网页源码。 确定是否存在泄漏 &#xff08;1&…

java项目基于Springboot和Vue的高校心理教育辅导系统的设计与实现

今天要和大家聊的是基于Springboot和Vue的高校心理教育辅导系统的设计与实现 &#xff01;&#xff01;&#xff01; 有需要的小伙伴可以通过文章末尾名片咨询我哦&#xff01;&#xff01;&#xff01; &#x1f495;&#x1f495;作者&#xff1a;李同学 &#x1f495;&…

大模型之路3:趟到了Llama-Factory,大神们请指点

各种AI工具和框架层出不穷&#xff0c;为开发者和研究者提供了前所未有的便利。当然了&#xff0c;也有困扰。尤其是对于动手能力越来越弱的中年油腻老程序员来说&#xff0c;更是难上加难。据说&#xff0c;嗯&#xff0c;据师弟说&#xff0c;说LlamaFactory凭借其独特的功能…

实验:基于Red Hat Enterprise Linux系统的创建磁盘和磁盘分区(一)

目录 一. 实验目的 二. 实验内容 三. 实验设计描述及实验结果 fdisk [参数] [设备] 1. 为虚拟机添加1块大小为3-5G的硬盘nvme&#xff0c;将该硬盘划分1个主分区和两个逻辑分区分别为600MB。 partprobe [选项] [设备] 2. 将主分区格式化为ext4文件系统并挂载到/自己名字命名…

Screeps Arena 游戏基础教程

一. 游戏内教程汉化1. 循环和导入&#xff08;Loop and Import&#xff09;2. 简单移动&#xff08;Simple move&#xff09;3. 首次攻击&#xff08;First Attack&#xff09;4. 爬虫的身体部分&#xff08;Creeps Bodies&#xff09;5. 存储和转移 &#xff08;Store and Tra…

合并两个单链表

归纳编程学习的感悟&#xff0c; 记录奋斗路上的点滴&#xff0c; 希望能帮到一样刻苦的你&#xff01; 如有不足欢迎指正&#xff01; 共同学习交流&#xff01; &#x1f30e;欢迎各位→点赞 &#x1f44d; 收藏⭐ 留言​&#x1f4dd; 但行前路&#xff0c;不负韶华&#…

dataloader numworkers

numworkers是加载数据的额外cpu数量&#xff08;也可以看成额外的进程&#xff09;。可以理解是&#xff1a; dataset中的getitem只能得到单个数据&#xff0c; 而numworker设置后是同时加载numwork个数据到RAM中&#xff0c;当需要数据时&#xff0c;不会重新执行getiem的方法…

代码随想录算法训练营第四十二天 | 卡码网46. 携带研究材料、416. 分割等和子集

代码随想录算法训练营第四十二天 | 卡码网46. 携带研究材料、416. 分割等和子集 卡码网46. 携带研究材料题目解法 416. 分割等和子集题目解法 感悟 卡码网46. 携带研究材料 题目 解法 题解链接 二维数组 # include <bits/stdc.h> using namespace std;int n, bagweig…

读取信息boot.bin和xclbin命令

bootgen读Boot.bin命令 johnjohn-virtual-machine:~/project_zynq/kv260_image_ubuntu22.04$ bootgen -read BOOT-k26-starter-kit-202305_2022.2.bin xclbinutil读xclbin命令 johnjohn-virtual-machine:~/project_zynq/kv260_image_ubuntu22.04$ xclbinutil -i kv260-smartca…

【Vue】vue3简介与环境配置

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