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

2023-05-16

在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是用点表示的。知乎暴力版,推导过程就是因式分解,合并同类项的过程,思路不难,难得是简,正好对应起来了。
在这里插入图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【算法】AB3DMOT之Sutherland Hodgman多边形裁剪 的相关文章

  • AudioChannelManipulation

    Manipulating audio channels with ffmpeg Contents stereo mono streamstereo 2 mono filesstereo 2 mono streamsmono stereo2
  • sklearn数据集随机切分(train_test_split)

    sklearn学习 给定数据集X和类别标签y xff0c 将数据集按一定比例随机切分为训练集和测试集 代码 span class hljs comment usr bin env python span span class hljs co
  • 音频节奏检测(Onset Detection)

    1 前言 最近市场上出现一些多个视频拼接而成MV xff0c 其原理是根据音频的节拍变换切换视频 我在这里讲述下如何进行音频节拍检测 2 音频检测一般流程 3 3 1 原始音频频谱 以1024为窗口 xff08 即每次读取1024个采样点
  • 金融时间序列分析:6. AR模型实例(R语言)

    0 目录 金融时间序列分析 xff1a 9 ARMA自回归移动平均模型 金融时间序列分析 xff1a 8 MA模型实例 xff08 Python xff09 金融时间序列分析 xff1a 7 MA滑动平均模型 金融时间序列分析 xff1a
  • 比特率,帧率,分辨率对视频画质的影响

    0 前言 前几天和别人讨论视频编码参数对视频清晰度影响 xff0c 今日查查文献在此记录总结下 对最终用户而言 xff0c 其只关心视频的文件大小和画面质量 其中画面质量包括 xff1a 分辨率 xff0c 清晰度和流畅度 流畅度 xff1
  • 搭建Android Camera项目工程

    0 前言 这块内容非常简单 xff0c 需要注意的有两个 xff1a 需要申请相机权限需要一个Surface用来预览 1 申请相机权限 1 1 申请Camera权限 span class hljs tag lt span class hlj
  • 获取webshell权限的45种方法

    1 到GoogLe 搜索一些关键字 edit asp 韩国肉鸡为多 多数为MSSQL数据库 2 到Google site cq cn inurl asp 3 利用挖掘鸡和一个ASP木马 文件名是login asp 路径组是 manage 关
  • EGLContext: eglMakeCurrent详解

    1 前言 在完成EGL的初始化之后 xff0c 需要通过eglMakeCurrent 函数来将当前的上下文切换 xff0c 这样opengl的函数才能启动作用 boolean eglMakeCurrent EGLDisplay displa
  • UART串口通信 Verilog实现代码

    串行通信分为两种方式 xff1a 同步串行通信和异步串行通信 同步串行通信需要通信双方在同一时钟的控制下 xff0c 同步传输数据 xff1b 异步串行通信是指通信双方使用各自的时钟控制数据的发送和接收过程 UART 是一种采用异步串行通信
  • pytorch: 四种方法解决RuntimeError: CUDA out of memory. Tried to allocate ... MiB

    Bug xff1a RuntimeError CUDA out of memory Tried to allocate MiB 解决方法 xff1a 法一 xff1a 调小batch size xff0c 设到4基本上能解决问题 xff0c
  • Linux打开txt文件乱码的解决方法

    今天发现打开windows下的txt文本出现问题 xff0c 主要是编码问题 xff0c 所以这里我记录下这个问题的解决方法 Linux显示在 Windows 编辑过的中文就会显示乱码是由于两个操作系统使用的编码不同所致 Linux下使用的
  • ubuntu14.04安装cuda

    首先验证你是否有nvidia的显卡 xff08 http developer nvidia com cuda gpus这个网站查看你是否有支持gpu的显卡 xff09 xff1a lspci grep i nvidia 查看你的linux发
  • debian安装无线网卡驱动

    最近安装了debian8 xff0c 但是安装好了后发现不能连wifi 能连有线的 xff0c 笔记本不能连WIFI是个悲剧 xff0c 于是就度百度 xff0c 最后在一篇文章看到方法 xff0c 原文地址 xff1a https wik
  • 魔改Cmake系列:cmake中Boost找不到库的解决方法

    Begin finding boost libraries FindBoost cmake文件中 xff0c 在CMake share cmake 3 4 Modules 找到下面这几行代码 xff08 你可以搜索 xff09 messag
  • 关于softmax损失函数的推导

    关于softmax损失函数的推导 某人问我softamx损失函数的推导 索性就写一下 定义softmax损失函数的输入为 X N C 和 Y N C 其中N代表输入的数据的个数 C代表类别的个数 X指的是神经网络的输出 Y代表的是0 1矩阵
  • 手把手教你数据恢复编程(二)基础知识篇

    好了 接上一篇 xff0c 本篇 xff0c 我们将详细讲解NTFS文件系统的一些重要的数据结构 xff0c 闲话少叙 xff0c 咱们开讲 NTFS文件系统 一 NTFS简介 NTFS xff08 New Technology File
  • 数字图像基本处理算法

    数字图像基本处理算法 xizero00 常熟理工学院 xff08 CIT xff09 计算机科学与工程学院 下一代互联网实验室 NGIL Lab Email xizero00 64 163 com 由于SIFT算法需要用到很多算法 xff0
  • PyOpenPose编译与使用

    PyOpenPose编译 前言 PyOpenPose是一个OpenPose的python绑定 xff0c 你可以使用python来实现人体的姿态估计 用上python的openpose xff0c 想想就有点小激动呢 哈哈 PyOpenPo
  • torch系列:如何在torch内使用tensorboard

    torch也是可以使用tensorboard的 xff0c 通过安装crayon就可以 下面以ubuntu下的安装为例进行讲解 其实安装的过程还是会碰到不少曲折的过程的 主要为 安装crayon会提示找不到libssl so文件 xff0c
  • mask rcnn使用指南

    做姿态估计的小伙伴们肯定经常用检测器 xff0c 为了方便大家 xff0c 这里给出一个很方便的教程 让大家快速上手 xff0c 不用再纠结配置环境 xff01 欢迎加入我们的姿态估计群 xff1a 970029323 xff08 xff1

随机推荐

  • UML中的泛化、实现、依赖、关联、聚合、组合6种关系

    在UML中经常见到几种关系 xff1a 泛化 xff08 Generalization xff09 实现 xff08 Realization xff09 依赖 xff08 Dependency xff09 关联 xff08 Associat
  • RTOS系统与Linux系统的区别

    RTOS是实时操作系统 Linux是时分系统 xff0c 不过可以通过配置内核改成实时系统 实时操作系统 英文称Real Time Operating System xff0c 简称RTOS 1 实时操作系统定义 实时操作系统 xff08
  • 【Pytorch】学习笔记2023/2/28

    参考文献 Pytorch学习笔记 张贤同学 深度学习百科及面试资源 飞桨
  • k8s-kubernetes--网络策略、flannel网络插件和calico网络插件

    文章目录 一 k8s网络通信1 网络策略2 service和iptables的关系 二 pod间通信1 同节点之间的通信2 不同节点的pod之间的通信需要网络插件支持 详解 1 Flannel vxlan模式跨主机通信原理 2 vxlan模
  • 【Python】可视化figure

    1 Tensorboard静态显示 span class token keyword import span torch span class token keyword import span torch span class token
  • 【Python】绘制双Y轴折线与散点图

    span class token keyword import span matplotlib span class token punctuation span pyplot span class token keyword as spa
  • 【World】插入公式

    1创建样式 公式 2调整段落格式 行间距最小值 xff1a 防止公式显示不全 3根据纸张制作制表符 公式20字符左右 xff0c 居中对齐 标号40字符左右 xff0c 右对齐 确定 4在需要公式的一行 xff0c 点击创建的样式 xff0
  • 【Python】matplotlib替代cv画虚线矩形框

    span class token keyword import span cv2 span class token keyword as span cv span class token keyword import span matplo
  • 【造轮子】最小权完备匹配算法

    1 C 43 43 编程方法 矩阵方法 span class token macro property span class token directive hash span span class token directive keyw
  • 【LeetCode】两数之和

    1 两数之和 1 My solution span class token keyword class span span class token class name Solution span span class token punc
  • 【LeetCode】两数相加

    1 主要是链表先创建下一个对象 xff0c 再转移 xff0c 而不是先转移到空指针再赋值 t span class token operator 61 span span class token keyword new span span
  • 【算法】kalman运动状态估计不准确的思考

    前言 在仿真实验多目标跟踪时 xff0c 我采用了Kalman做跟踪 xff0c 在运动状态估计时位置可以很 准确 的估计 xff0c 但是速度与方向就偏差很大 xff0c 最近看到了一篇文献详细的介绍了原因 xff0c 之前考虑到时间间隔
  • 【LeetCode】无重复字符的最长子串

    尝试1 思路清晰但是耗时 span class token keyword class span span class token class name Solution span span class token punctuation
  • 【C++】vector释放内存之swap方法

    C 43 43 vector 容器浅析 在容器vector中 xff0c 其内存占用的空间是只增不减的 xff0c 比如说首先分配了10 000个字节 xff0c 然后erase掉后面9 999个 xff0c 则虽然有效元素只有一个 xff
  • Linux解决Tab键无法自动补全

    Linux解决Tab键无法自动补全的问题 安装bash completion包 这个包提供Tab键自动补全功能 yum install span class token operator span y bash span class tok
  • 【工具】Github Copilot感想

    前言 昨天是周五 xff0c 本想周末休息一下 xff0c 突然刷到Github Copilot X要发布 xff0c 看完挺期待 xff0c 就好奇搜了一下 xff0c 发现两年前Github Copilot发布了 xff0c 当时我在想
  • 【工具】pip安装不在当前虚拟环境中

    查看pip V与pip3 V是否只向当前虚拟环境如果没有需要手动指定 在安装ultralytics 61 61 8 0 20 时一直找不到包 xff0c 使用最新python 61 3 9 13就好了 使用 xff1a pip V pip
  • 【论文复现】AB3DMOT: A Baseline for 3D Multi-Object Tracking and New Evaluation Metrics

    1 前言 AB3MOT是经典的3D多目标跟踪框架 xff0c 将2D卡尔曼推广到了3D 并将2D IOU匹配推广到了3D 由于论文的原理基本上与2D相同所以作者在文中没有叙述很多细节 xff0c 要理解具体实现细节 xff0c 只能看代码
  • 【LeetCode】代码随想录之数组

    代码随想录 数组理论基础 C 43 43 的数组在内存空间中是连续的 xff0c 但有区别与Vector与Array xff0c Vector是一个容器 xff0c 它的底层实现为数组 其中二维数组的内存空间也是连续的 xff0c C 43
  • 【算法】AB3DMOT之Sutherland Hodgman多边形裁剪

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