【算法】AB3DMOT之Sutherland Hodgman多边形裁剪

news2024/12/29 7:39:45

在AB3MOT模型中有一个步骤为计算IOU时,需要先计算两个立体在地面的投影2D形状,然后计算两个投影的重叠部分,实际上为多边形的裁剪算法。

AB3MOT

@classmethod
def box2corners3d_camcoord(cls, bbox):
Takes an object's 3D box with the representation of [x,y,z,theta,l,w,h] and 
        convert it to the 8 corners of the 3D box, the box is in the camera coordinate
        with right x, down y, front z
        
        Returns:
            corners_3d: (8,3) array in in rect camera coord

        box corner order is like follows
                1 -------- 0         top is bottom because y direction is negative
               /|         /|
              2 -------- 3 .
              | |        | |
              . 5 -------- 4
              |/         |/
              6 -------- 7    
        
        rect/ref camera coord:
        right x, down y, front z

        x -> w, z -> l, y -> h

上面为作者定义了立方体的坐标系

def iou(box_a, box_b, metric='giou_3d'):
	''' Compute 3D/2D bounding box IoU, only working for object parallel to ground

	Input:
		Box3D instances
	Output:
	    iou_3d: 3D bounding box IoU
	    iou_2d: bird's eye view 2D bounding box IoU

	box corner order is like follows
            1 -------- 0 		 top is bottom because y direction is negative
           /|         /|
          2 -------- 3 .
          | |        | |
          . 5 -------- 4
          |/         |/
          6 -------- 7    
	
	rect/ref camera coord:
    right x, down y, front z
	'''	

	# compute 2D related measures
	boxa_bot, boxb_bot = compute_bottom(box_a, box_b)
	I_2D = compute_inter_2D(boxa_bot, boxb_bot)

	# only needed for GIoU
	if 'giou' in metric:
		C_2D = convex_area(boxa_bot, boxb_bot)

	if '2d' in metric:		 	# return 2D IoU/GIoU
		U_2D = box_a.w * box_a.l + box_b.w * box_b.l - I_2D
		if metric == 'iou_2d':  return I_2D / U_2D
		if metric == 'giou_2d': return I_2D / U_2D - (C_2D - U_2D) / C_2D

	elif '3d' in metric:		# return 3D IoU/GIoU
		overlap_height = compute_height(box_a, box_b)
		I_3D = I_2D * overlap_height	
		U_3D = box_a.w * box_a.l * box_a.h + box_b.w * box_b.l * box_b.h - I_3D
		if metric == 'iou_3d':  return I_3D / U_3D
		if metric == 'giou_3d':
			union_height = compute_height(box_a, box_b, inter=False)
			C_3D = C_2D * union_height
			return I_3D / U_3D - (C_3D - U_3D) / C_3D
	else:
		assert False, '%s is not supported' % space

其中

I_2D = compute_inter_2D(boxa_bot, boxb_bot)

def compute_inter_2D(boxa_bottom, boxb_bottom):
	# computer intersection over union of two sets of bottom corner points

	_, I_2D = convex_hull_intersection(boxa_bottom, boxb_bottom)

	# a slower version
	# from shapely.geometry import Polygon
	# reca, recb = Polygon(boxa_bottom), Polygon(boxb_bottom)
	# I_2D = reca.intersection(recb).area

	return I_2D

其中

_, I_2D = convex_hull_intersection(boxa_bottom, boxb_bottom)


def convex_hull_intersection(p1, p2):
	""" Compute area of two convex hull's intersection area.
		p1,p2 are a list of (x,y) tuples of hull vertices.
		return a list of (x,y) for the intersection and its volume
	"""
	inter_p = polygon_clip(p1,p2)
	if inter_p is not None:
		hull_inter = ConvexHull(inter_p)
		return inter_p, hull_inter.volume
	else:
		return None, 0.0  
其中	

inter_p = polygon_clip(p1,p2)

def polygon_clip(subjectPolygon, clipPolygon):
	""" Clip a polygon with another polygon.
	Ref: https://rosettacode.org/wiki/Sutherland-Hodgman_polygon_clipping#Python

	Args:
		subjectPolygon: a list of (x,y) 2d points, any polygon.
		clipPolygon: a list of (x,y) 2d points, has to be *convex*
	Note:
		**points have to be counter-clockwise ordered**

	Return:
		a list of (x,y) vertex point for the intersection polygon.
	"""
	def inside(p):
		return (cp2[0] - cp1[0]) * (p[1] - cp1[1]) > (cp2[1] - cp1[1]) * (p[0] - cp1[0])
 
	def computeIntersection():
		dc = [cp1[0] - cp2[0], cp1[1] - cp2[1]]
		dp = [s[0] - e[0], s[1] - e[1]]
		n1 = cp1[0] * cp2[1] - cp1[1] * cp2[0]
		n2 = s[0] * e[1] - s[1] * e[0] 
		n3 = 1.0 / (dc[0] * dp[1] - dc[1] * dp[0])
		return [(n1 * dp[0] - n2 * dc[0]) * n3, (n1 * dp[1] - n2 * dc[1]) * n3]
 
	outputList = subjectPolygon
	cp1 = clipPolygon[-1]
 
	for clipVertex in clipPolygon:
		cp2 = clipVertex
		inputList = outputList
		outputList = []
		s = inputList[-1]
 
		for subjectVertex in inputList:
			e = subjectVertex
			if inside(e):
				if not inside(s): outputList.append(computeIntersection())
				outputList.append(e)
			elif inside(s): outputList.append(computeIntersection())
			s = e
		cp1 = cp2
		if len(outputList) == 0: return None
	return (outputList)

可以看到作者给了参考链接,Ref: https://rosettacode.org/wiki/Sutherland-Hodgman_polygon_clipping#Python我发现代码一模一样,也就是作者ctrl+c ctrl+v cv大法过来的,那么多边形的裁剪的原理是什么呢?

1.前言

多边形裁剪
Sutherland Hodgman算法
凸边形与凹边形的区别
相交点暴力求解(官方版)
相交点github优雅版

2.代码

根据参考链接官方提示,我用Python对代码进行了可视化如下:

import matplotlib.pyplot as plt
from pylab import mpl
mpl.rcParams['font.sans-serif'] = ['STZhongsong']    # 指定默认字体:解决plot不能显示中文问题
mpl.rcParams['axes.unicode_minus'] = False           # 解决保存图像是负号'-'显示为方块的问题

def clip(subjectPolygon, clipPolygon):
   def inside(p):
      return(cp2[0]-cp1[0])*(p[1]-cp1[1]) > (cp2[1]-cp1[1])*(p[0]-cp1[0])
      
   def computeIntersection():
      dc = [ cp1[0] - cp2[0], cp1[1] - cp2[1] ]
      dp = [ s[0] - e[0], s[1] - e[1] ]
      n1 = cp1[0] * cp2[1] - cp1[1] * cp2[0]
      n2 = s[0] * e[1] - s[1] * e[0] 
      n3 = 1.0 / (dc[0] * dp[1] - dc[1] * dp[0])
      return [(n1*dp[0] - n2*dc[0]) * n3, (n1*dp[1] - n2*dc[1]) * n3]

   outputList = subjectPolygon
   cp1 = clipPolygon[-1]
   
   for clipVertex in clipPolygon:
      cp2 = clipVertex
      inputList = outputList
      outputList = []
      s = inputList[-1]

      for subjectVertex in inputList:
         e = subjectVertex
         if inside(e):
            if not inside(s):
               outputList.append(computeIntersection())
            outputList.append(e)
         elif inside(s):
            outputList.append(computeIntersection())
         s = e
      cp1 = cp2
   return(outputList)

coord = [(50, 150), (200, 50), (350, 150), (350, 300), (250, 300), (200, 250), (150, 350), (100, 250), (100, 200)]
coord1 =  [(100, 100), (300, 100), (300, 300), (100, 300)]

out = clip(coord, coord1)
out.append(out[0]) #repeat the first point to create a 'closed loop'
xs2, ys2 = zip(*out) #create lists of x and y values

coord.append(coord[0]) #repeat the first point to create a 'closed loop'
coord1.append(coord1[0]) #repeat the first point to create a 'closed loop'

xs, ys = zip(*coord) #create lists of x and y values
xs1, ys1 = zip(*coord1) #create lists of x and y values

plt.figure()
plt.plot(xs, ys, label = "被裁剪凸边形", color = 'r') 
plt.plot(xs1, ys1, label = "裁剪凸边形", color = 'g', linestyle='--') 
plt.plot(xs2, ys2, label = "结果", color = 'b') 
plt.legend()
plt.show() # if you need...

在这里插入图片描述

图中我采用RGB顺序显示,其中红色代表被裁减多边形,绿色代表使用的裁剪框,蓝色代表最终裁剪结果。very amazing!发现结果确实这样,那么原理可以参考链接,就是一个迭代的过程。这里记录在学习原理几个难点。

判断是否在裁剪多边形内

主要是利用两个向量的叉乘:由于叉乘采用的是右手坐标系,而代码中又采用逆时针裁剪,所以只要叉乘大于0.就说明在向量的右边也就是裁剪边向量的右边,注意是向量的右边是指符合右手定则,不是真的指右边。
在这里插入图片描述

左图 v 1 ⃗ \vec{v_1} v1 x v 2 ⃗ \vec{v_2} v2 = ∣ v 1 ∣ ∣ v 2 ∣ s i n ( θ ) |v_1||v_2|sin(\theta) v1∣∣v2sin(θ)符合右手定则,右图因为按照右手定则夹角为大的角,所以叉乘是负数

计算交点

源代码为

   def computeIntersection():
      dc = [ cp1[0] - cp2[0], cp1[1] - cp2[1] ]
      dp = [ s[0] - e[0], s[1] - e[1] ]
      n1 = cp1[0] * cp2[1] - cp1[1] * cp2[0]
      n2 = s[0] * e[1] - s[1] * e[0] 
      n3 = 1.0 / (dc[0] * dp[1] - dc[1] * dp[0])
      return [(n1*dp[0] - n2*dc[0]) * n3, (n1*dp[1] - n2*dc[1]) * n3]

看了半天没看懂,不如优雅版清晰
后来发现源代码采用了最暴力的求解方式,就是两条直线求交点,列一个等式,只不过斜率k与截距b是用点表示的。知乎暴力版,推导过程就是因式分解,合并同类项的过程,思路不难,难得是简,正好对应起来了。
在这里插入图片描述

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

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

相关文章

懒人式迁移服务器深度学习环境(完全不需要重新下载)

换服务器了?想迁移原来服务器上的深度学习环境,但又觉得麻烦懒得重新安装一遍anaconda、pytorch?有没有办法能不费吹灰之力直接迁移?接下来跟着我一起,懒汉式迁移。   本方法适用于在同一内网下的两台服务器之间互相…

【深度强化学习】(8) iPPO 模型解析,附Pytorch完整代码

大家好,今天和各位分享一下多智能体深度强化学习算法 ippo,并基于 gym 环境完成一个小案例。完整代码可以从我的 GitHub 中获得:https://github.com/LiSir-HIT/Reinforcement-Learning/tree/main/Model 1. 算法原理 多智能体的情形相比于单智…

SpringCloud GateWay与Nacos使用

网关就相当于一个内网与外网的出入口,起着 安全、验证的功能,如果没有网关,那么如果需要实现验证的功能,除非 SpringCloud GateWay 作为微服务的网关,起着如下作用 ① 作为所有API接口服务请求的接入点 ② 作为所有后端业务服务…

SpringBoot 整合 RabbitMQ (四十一)

二八佳人体似酥,腰间仗剑斩愚夫。虽然不见人头落,暗里教君骨髓枯。 上一章简单介绍了SpringBoot 实现 Web 版本控制 (四十),如果没有看过,请观看上一章 关于消息中间件 RabbitMQ, 可以看老蝴蝶之前的文章: https://blog.csdn.net/yjltx1234csdn/categor…

还不懂如何与AI高效交流?保姆级且全面的chatGPT提示词工程教程来啦!(一)基础篇

还不懂如何与chatGPT高效交流?保姆级且全面的chatGPT提示词工程教程来啦!(一)基础篇 文章目录还不懂如何与chatGPT高效交流?保姆级且全面的chatGPT提示词工程教程来啦!(一)基础篇一&…

CDH6.3.2大数据集群生产环境安装(七)之PHOENIX组件安装

添加phoenix组件 27.1. 准备安装资源包 27.2. 拷贝资源包到相应位置 拷贝PHOENIX-1.0.jar到/opt/cloudera/csd/ 拷贝PHOENIX-5.0.0-cdh6.2.0.p0.1308267-el7.parcel.sha、PHOENIX-5.0.0-cdh6.2.0.p0.1308267-el7.parcel到/opt/cloudera/parcel-repo 27.3. 进入cm页面进行分发、…

【AIGC】9、BLIP-2 | 使用 Q-Former 连接冻结的图像和语言模型 实现高效图文预训练

文章目录一、背景二、方法2.1 模型结构2.2 从 frozen image encoder 中自主学习 Vision-Language Representation2.3 使用 Frozen LLM 来自主学习 Vision-to-Language 生成2.4 Model pre-training三、效果四、局限性论文:BLIP-2: Bootstrapping Language-Image Pre-…

unity 序列化那些事,支持Dictionary序列化

目录 一、普通类型和UnityEngine空间类型序列化 二、数组、list的序列化 三、自定义类的序列化支持 四、自定义asset 五、在inspector面板中支持Dictionary序列化 1、在MonoBehaviour中实现Dictionary序列化 2、自定义property,让其在inpsector能够显示 3、Mo…

【从零开始学Skynet】实战篇《球球大作战》(七):gateway代码设计(下)

1、确认登录接口 在完成了登录流程后,login会通知gateway(第⑧阶段),让它把客户端连接和新agent(第⑨阶段)关联起来。 sure_agent代码如下所示: s.resp.sure_agent function(source, fd, play…

[Gitops--1]GitOps环境准备

GitOps环境准备 1. 主机规划 序号主机名主机ip主机功能软件1dev192.168.31.1开发者 项目代码 apidemogit,golang,goland2gitlab192.168.31.14代码仓库,CI操作git-lab,git,golang,docker,gitlab-runner3harbor192.168.31.104管理和存储镜像docker,docker-compose,harbor4k8s-m…

基础排序算法【计数排序】非比较排序

基础排序算法【计数排序】非比较排序⏰【计数排序】🕐计数🕦排序🕓测试⏰总结:⏰【计数排序】 计数排序又称为鸽巢原理,是对哈希直接定址法的变形应用 > 基本思路: 1.统计数据出现的次数 2.根据统计的结…

并行分布式计算 并行算法与并行计算模型

文章目录并行分布式计算 并行算法与并行计算模型基础知识定义与描述复杂性度量同步和通讯并行计算模型PRAM 模型异步 PRAM 模型 (APRAM)BSP 模型LogP 模型层次存储模型分层并行计算模型并行分布式计算 并行算法与并行计算模型 基础知识 定义与描述 并…

15个最适合初创公司创始人使用的生产力工具

创业是一段激动人心且收获颇丰的旅程,同时也伴随着一些挑战。创始人往往要面对长时间的工作、紧迫的期限和大量的压力时刻。因此,初创公司创始人必须最大限度地利用他们的时间并利用他们可用的生产力工具——不仅是为了发展他们的业务,而且是…

Cron表达式简单介绍 + Springboot定时任务的应用

前言 表达式是一个字符串,主要分成6或7个域,但至少需要6个域组成,且每个域之间以空格符隔开。 以7个域组成的,从右往左是【年 星期 月份 日期 小时 分钟 秒钟】 秒 分 时 日 月 星期 年 以6个域组成的,从右往左是【星…

【精华】表格识别技术-MI

表格识别是指将图片中的表格结构和文字信息识别成计算机可以理解的数据格式,在办公、商务、教育等场景中有着广泛的实用价值,也一直是文档分析研究中的热点问题。围绕这个问题,我们研发了一套表格识别算法,该算法高效准确地提取图…

RabbitMq 的消息可靠性问题(二)---MQ的消息丢失和consumer消费问题

前言 RabbitMq 消息可靠性问题(一) — publisher发送时丢失 前面我们从publisher的方向出发解决了发送时丢失的问题,那么我们在发送消息到exchange, 再由exchange转存到queue的过程中。如果MQ宕机了,那么我们的消息是如何确保可靠性的呢?当消…

SQL的函数

文章目录一、SQL MIN() Function二、SQL SUM() 函数三、SQL GROUP BY 语句四、SQL HAVING 子句五、SQL EXISTS 运算符六、SQL UCASE() 函数总结一、SQL MIN() Function MIN() 函数返回指定列的最小值。 SQL MIN() 语法 SELECT MIN(column_name) FROM table_name;演示数据库 …

Numba witch makes Python code fast

一. 前言:numba,让python速度提升百倍 python由于它动态解释性语言的特性,跑起代码来相比java、c要慢很多,尤其在做科学计算的时候,十亿百亿级别的运算,让python的这种劣势更加凸显。 办法永远比困难多&a…

ASP.NET Core MVC 从入门到精通之接化发(二)

随着技术的发展,ASP.NET Core MVC也推出了好长时间,经过不断的版本更新迭代,已经越来越完善,本系列文章主要讲解ASP.NET Core MVC开发B/S系统过程中所涉及到的相关内容,适用于初学者,在校毕业生&#xff0c…

4.13实验 加测试题目

今天是个好日子,要搞栈的实验 没啥就是链栈和顺序栈 和出栈入栈,强大都是从最基本开始的 来和我一起写写吧 //顺序栈 typedef struct node{int *base;int *top;int sizer; }shed;//链栈 typedef struct Node{ int data; struct Node* next; }*stact,link; //顺序栈的初始化…