graham 算法计算平面投影点集的凸包

news2024/12/27 13:07:49

文章目录

  • 向量的内积(点乘)、外积(叉乘)
    • 确定旋转方向
    • numpy 的 cross 和 outer
      • `np.inner` 向量与矩阵计算示例
      • `np.outer` 向量与矩阵计算示例
  • python 示例
    • 生成样例散点数据图
    • 显示按极角排序的结果
    • 根据排序点计算向量转向并连成凸包
  • 基本思路

将三维空间中的点云使用 BEV 的方式多视角投影到某个平面之后,可能需要用到该平面投影图(光栅化之前)的点集的凸包,所以这里记录一下常见的 graham 凸包算法。

向量的内积(点乘)、外积(叉乘)

graham 算法模拟最外层点集包围的过程的关键思想是使用两个向量之间的外积来判断下一条连线的转角,如果向外拐了,那说明当前基点在本次连线之后会成为一块凹陷,注意“凸包”的定义,每个顶角的角度都小于 18 0 ∘ 180^\circ 180 才叫 “凸” ,如果有一个内凹顶点,那么它的内角是大于 18 0 ∘ 180^\circ 180 的,可以确定,它应该是包含在实际的最终计算出来的理想凸包之内才对,这个时候就需要调整连线的基点为上一个基点。

在二维平面上,叉积的结果与向量的顺时针或逆时针旋转方向有关。具体来说:

  • 对于二维平面上的两个向量 u = ( x 1 , y 1 ) u=(x_1,y_1) u=(x1,y1) v = ( x 2 , y 2 ) v=(x_2, y_2) v=(x2,y2) ,它们的叉积可以使用一个标量值来表示 u × v = x 1 y 2 − y 1 x 2 u\times v = x_1y_2 - y_1x_2 u×v=x1y2y1x2
  • 这个标量值表示了这两个向量所定义的平行四边形的有向面积,也可以用来判定向量的旋转方向。

确定旋转方向

  • 正值:当 叉积 的值为正时,向量 v v v 从向量 u u u 逆时针旋转到达 v v v,也就是说, v v v u u u 的左侧。
  • 负值:当 叉积 的值为负时,向量 v v v 从向量 u u u 顺时针旋转到达 v v v,也就是说, v v v u u u 的右侧。
  • 零值:当 叉积 的值为零时,两个向量是共线的,即它们之间没有旋转,或者说它们之间的旋转角度是 0 ∘ 0^\circ 0∘ 或 18 0 ∘ 180^\circ 180

numpy 的 cross 和 outer

示例 python 代码:

a = np.array([1, 1])
b = np.array([0, 1])

np.cross(a, b)

输出结果为 1 ,代表由向量 a 转动到向量 b 的转角是逆时针,符合右手螺旋。

numpy 库中有两个函数分别是 np.cross(a,b)np.outer(a,b) ,其中 np.cross 是我们常用所说的外积(叉乘),而 np.outer 实际的计算结果定义是一个张量中的每个元素对另一个张量中的每个元素的乘积。

np.inner 向量与矩阵计算示例

# Python Program illustrating 
# numpy.inner() method 
import numpy as np 
  
# Vectors 
a = np.array([2, 6]) 
b = np.array([3, 10]) 
print("Vectors :") 
print("a = ", a) 
print("\nb = ", b) 
  
# Inner Product of Vectors 
print("\nInner product of vectors a and b =") 
print(np.inner(a, b)) 
  
print("---------------------------------------") 
  
# Matrices 
x = np.array([[2, 3, 4], [3, 2, 9]]) 
y = np.array([[1, 5, 0], [5, 10, 3]]) 
print("\nMatrices :") 
print("x =", x) 
print("\ny =", y) 
  
# Inner product of matrices 
print("\nInner product of matrices x and y =") 
print(np.inner(x, y)) 

输出:

Vectors :
a =  [2  6]
b =  [3 10]

Inner product of vectors a and b =
66
---------------------------------------

Matrices :
x = [[2 3 4]
     [3 2 9]]

y = [[ 1  5  0]
     [ 5 10  3]]

Inner product of matrices x and y =
[[17 52]
 [13 62]]

可以看到对于向量来说,外积在 numpy 中的 outer 不是我们说常说的叉乘计算方式,而是一个向量中的每个元素对另一个向量中的每个元素的乘积结果。

np.outer 向量与矩阵计算示例

# Python Program illustrating  
# numpy.outer() method  
import numpy as np 
  
# Vectors 
a = np.array([2, 6]) 
b = np.array([3, 10]) 
print("Vectors :") 
print("a = ", a) 
print("\nb = ", b) 
  
# Outer product of vectors  
print("\nOuter product of vectors a and b =") 
print(np.outer(a, b)) 
  
print("------------------------------------") 
  
# Matrices 
x = np.array([[3, 6, 4], [9, 4, 6]]) 
y = np.array([[1, 15, 7], [3, 10, 8]]) 
print("\nMatrices :") 
print("x =", x) 
print("\ny =", y) 
  
# Outer product of matrices 
print("\nOuter product of matrices x and y =") 
print(np.outer(x, y)) 

输出:

Vectors :
a =  [2  6]
b =  [3 10]

Outer product of vectors a and b =
[[ 6 20]
 [18 60]]
------------------------------------

Matrices :
x = [[3 6 4]
     [9 4 6]]

y = [[ 1 15  7]
     [ 3 10  8]]

Outer product of matrices x and y =
[[  3  45  21   9  30  24]
 [  6  90  42  18  60  48]
 [  4  60  28  12  40  32]
 [  9 135  63  27  90  72]
 [  4  60  28  12  40  32]
 [  6  90  42  18  60  48]]

这说明在 graham 凸包算法中计算两个向量的旋转方向还是需要 np.cross 而不能使用 np.outer 来计算。

python 示例

生成样例散点数据图

# Test the algorithm with an example set of points
points = [(0, 3), (1, 1), (2, 2), (4, 4), (0, 0), (1, 2), (3, 1), (3, 3)]

start = min(points, key=lambda p: (p[1], p[0]))

print(*zip(*points))

fig1 = plt.figure()
plt.scatter(*zip(*points), color='blue')
plt.scatter(*start, color="red")
plt.show()

在这里插入图片描述

graham 算法一般以最下最左(Lowest Then Leftest)的点作为基准点,图中以红色的点作为标识。

显示按极角排序的结果

sorted_points = sorted(points, key=lambda p: (p[1] - start[1]) / (p[0] - start[0] + 1e-9), reverse=False)

fig, axs = plt.subplots(2, 4)
for point, ax in zip(sorted_points, axs.flatten()):
    ax.scatter(*zip(*points), color="blue")
    ax.scatter(*start, color="red")
    ax.plot(*zip(*[start, point]), marker="o")
plt.show()

在这里插入图片描述

根据排序点计算向量转向并连成凸包

def cross_product(o, a, b)
    return (a[0] - o[0]) * (b[1] - o[1]) - (a[1] - o[1]) * (b[0] - o[0])
    
hull = []
for p in sorted_points:
    while len(hull) >= 2 and cross_product(hull[-2], hull[-1], p) <= 0:
        hull.pop()
    hull.append(p)
    

fig = plt.figure()
plt.scatter(*zip(*points), color="blue")
for i in range(len(hull)):
    p1 = hull[i]
    p2 = hull[(i + 1) % len(hull)]
    plt.plot([p1[0], p2[0]], [p1[1], p2[1]], 'r-')
plt.show()

在这里插入图片描述

基本思路

  1. 选取基点(最左最下)
  2. 所有点与基点形成的向量进行极角排序,从小到大
  3. 从当前点(初始时是基点 p 0 p_0 p0 p i p_i pi 出发连接极角排序好的点序列中的下一个点 p i + 1 p_{i+1} pi+1
  4. 从第一个点 p 1 p_1 p1 连接第二个点 p 2 p_2 p2 ,判断前一个向量 p 0 p 1 → \overrightarrow{p_0p_1} p0p1 与新的向量 p 1 p 2 → \overrightarrow{p_1p_2} p1p2 的转向是否是往内拐,如果是外拐的话说明这个地方会形成一个凹陷,不是凸包连线,所以弹出这个新加入的点 p 2 p_2 p2 ,准备下一个点的测试

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

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

相关文章

linux中关于环境变量的常用的设置方法

一. linux中设置环境变量的方式 1.使用/etc/environment, 是一个全局的环境变量设置文件&#xff0c;它会影响到所有用户和所有进程。当你需要设置一个全局的环境变量时&#xff0c;应该使用这个文件。这个文件的格式是 KEYvalue&#xff0c;每行一个环境变量。 2. 使用/etc/…

Spring Data Redis + Redis数据缓存学习笔记

文章目录 1 Redis 入门1.1 简介1.2 Redis服务启动与停止&#xff08;Windows&#xff09;1.2.1 服务启动命令1.2.2 客户端连接命令1.2.3 修改Redis配置文件1.2.4 Redis客户端图形工具 2. Redis数据类型2.1 五种常用数据类型介绍 3. Redis常用命令3.1 字符串操作命令3.2 哈希操作…

【学习笔记】虚幻SkeletalMesh学习(一)基础介绍

文章目录 零、前言一、资源介绍1.1 骨架资源1.2 骨架网格体资源 二、UE4中的定义2.1 骨骼数据2.2 模型网格数据 三、渲染3.1 RenderData的初始化3.2 渲染对象的创建3.3 渲染对象的更新3.3.1 游戏线程的更新&#xff08;*FSkeletalMeshObjectGPUSkin::Update*&#xff09;3.3.2 …

大模型“重构”教育:解构学习奥秘,推动教育普惠

大模型“重构”千行百业系列选题 生成式人工智能的热潮&#xff0c;为AI领域的发展注入新的活力&#xff0c;而“赋能千行百业”已经成为人们普遍对于人工智能和大模型的全新理解。 人工智能和大模型技术的迅猛发展正在以前所未有的速度深刻改变着各个行业。正如专家所预测&a…

《昇思25天学习打卡营第23天|onereal》

第23天学习内容简介&#xff1a; ----------------------------------------------------------------------------- 本案例基于MindNLP和ChatGLM-6B实现一个聊天应用。 1 环境配置 配置网络线路 2 代码开发 下载权重大约需要10分钟 ------------------------------- 运…

汇总国内镜像提供了Redis的下载地址

文章目录 1. 清华大学开源软件镜像站&#xff1a;2. 中国科技大学开源软件镜像&#xff1a;3. 阿里云镜像&#xff1a;4. 华为云镜像&#xff1a;5. 腾讯云镜像&#xff1a;5. 官方GitHub仓库&#xff08;虽然不是镜像&#xff0c;但也是一个可靠的下载源&#xff09;&#xff…

XX2104 培训【C++解决】

描述 某培训机构的学员有如下信息&#xff1a; 姓名&#xff08;字符串&#xff09; 年龄&#xff08;周岁&#xff0c;整数&#xff09; 去年 NOIP 成绩&#xff08;整数&#xff0c;且保证是 5 的倍数&#xff09; 经过为期一年的培训&#xff0c;所有同学的成绩都有所提高&…

【数据结构与算法】数据结构(Data Structure)的基本概念及其研究对象

什么是程序 算法数据结构程序 —— Nicklaus Wirth(尼古拉斯沃斯) Niklaus Wirth是一位著名的计算机科学家&#xff0c;他提出了"程序算法数据结构"的观点。他认为&#xff0c;程序不仅仅是执行特定任务的一段代码&#xff0c;而是由算法和数据结构两部分组成的。算法…

Linux--线程同步

目录 0.上篇 1. 线程同步概念 2.认识条件变量 2.1条件变量的概念 2.2认识接口 2.3写一个测试代码 3.生产者消费者模型 3.1概念部分 1.基本概念 2.主要问题 3.优点 4.思考切入点&#xff08;321原则&#xff09; 3.2编写基于BlockingQueue的生产者消费者模型&…

js执行机制----事件循环

前言 问题 一般情况下,我们都认为js是顺序执行的 但是遇到下列情况 setTimeout(function(){console.log(定时器开始啦) });new Promise(function(resolve){console.log(马上执行for循环啦);for(var i 0; i < 10000; i){i 99 && resolve();} }).then(function(…

MySQL数据库查询索引失效场景

在连表情况下,如果排序字段涉及到了两个表,排序字段将无法走索引. 加上第二个排序字段之后,走全表扫描了. 或者尽量让两次排序都用同一个表的字段,这样可以建联合索引让排序也能走索引.&#xff08;不想建联合索引的话&#xff0c;可以第二次排序用表id&#xff0c;这样单个的…

天池AI大模型技术提升营火热上线,四重好礼等你来拿!

目标锁定&#xff0c;加速成长&#xff0c;四大活动玩法助您提升技术&#xff0c;赢取四重好礼&#xff1a; 【活动一】完成3步学习任务&#xff0c;赢取定制加湿器 【活动二】邀请好友报名指定学习赛&#xff0c;累计助力赢苹果iPad、大疆无人机、韶音蓝牙耳机等好礼 【活动三…

华为1000人校园实验记录

在这里插入代码片1000人校园区网设计 1、配置Eth-trunk实现链路冗余 vlan 900 管理WLAN #接入SW8 操作&#xff1a;sys undo in en sysname JR-SW8 int Eth-Trunk 1 mode lacp-static trunkport g0/0/1 0/0/2 port link-type trunk port trunk allow-pass vlan 200 900 qu vla…

NSSCTF-Web题目26(PHP弱比较)

目录 [SWPUCTF 2022 新生赛]funny_php 1、题目 2、知识点 3、思路 [ASIS 2019]Unicorn shop 4、题目 5、知识点 6、思路 [SWPUCTF 2022 新生赛]funny_php 1、题目 2、知识点 弱比较、双写绕过 3、思路 出现源代码&#xff0c;我们进行审计 第一个if 这里要我们GET方…

OPC UA S7-1500客户端学习

OPC UA S7-1500 OPC UA服务器功能 浏览PLC&#xff0c;服务器中的数据是是一个个节点&#xff0c;上下有联系&#xff0c;浏览请求是请求一个节点&#xff0c;展开上一级或者下一节数据。 符号方式读访问PLC数据。客户端发一条读请求&#xff0c;服务器回应。 写也是一样的 注…

永久删除的文件如何恢复?文件恢复,3种方法任君选择!

“我不小心把回收站清空了&#xff0c;把里面的所有文件都永久删除了&#xff0c;里面一些重要的文件还能恢复吗&#xff1f;” 当我们在清理电脑的时候&#xff0c;一些重要的文件有时会夹杂着垃圾文件一起被我们清理干净&#xff0c;我们只能回想着刚刚窗口弹出来“永久删除…

Spring Boot集成Activity7实现简单的审批流

由于客户对于系统里的一些新增数据&#xff0c;例如照片墙、照片等&#xff0c;想实现上级逐级审批通过才可见的效果&#xff0c;于是引入了Acitivity7工作流技术来实现&#xff0c;本文是对实现过程的介绍讲解&#xff0c;由于我是中途交接前同事的这块需求&#xff0c;所以具…

ospf的MGRE实验

第一步&#xff1a;配IP [R1-GigabitEthernet0/0/0]ip address 12.0.0.1 24 [R1-GigabitEthernet0/0/1]ip address 21.0.0.1 24 [R1-LoopBack0]ip address 192.168.1.1 24 [ISP-GigabitEthernet0/0/0]ip address 12.0.0.2 24 [ISP-GigabitEthernet0/0/1]ip address 21.0.0.2 24…

Python | Leetcode Python题解之第238题除自身以外数组的乘积

题目&#xff1a; 题解&#xff1a; class Solution:def productExceptSelf(self, nums: List[int]) -> List[int]:length len(nums)# L 和 R 分别表示左右两侧的乘积列表L, R, answer [0]*length, [0]*length, [0]*length# L[i] 为索引 i 左侧所有元素的乘积# 对于索引为…

C4D各版本软件下载+自学C4D 从入门到精通【学习视频教程全集】+【素材笔记】

下载链接&#xff1a; 迅雷网盘https://pan.xunlei.com/s/VO1tydOxEo-Az_QCM-Jz2R4RA1?pwdvxg4# 夸克网盘https://pan.quark.cn/s/fe7450b02d80 百度网盘https://pan.baidu.com/s/1Omj4WL93F1DNdA2iP4SiMQ?pwdwmb8