- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我有一个矩形列表的左上角和右下角的坐标,比如 (a,b) 和 (c,d)。我想检测并删除矩形内的矩形。重叠的矩形可以保留。
我有一个包含 10,000 个矩形的数据集,我想要一种有效的方法来解决这个问题。
目前我是这样做的,
import pandas
data = pd.read_csv('dataset.csv')
l = list(range(len(data)-1))
for i in range(len(data)):
length = len(l)
if i >= length:
break
for j in range(i+1, length):
if j >= len(l):
break
if (data.iloc[l[i]]['a'] >= data.iloc[l[j]]['a']) and (data.iloc[l[i]]['b'] <= data.iloc[l[j]]['b']) and (data.iloc[l[i]]['c'] <= data.iloc[l[j]]['c']) and (data.iloc[l[i]]['d'] >= data.iloc[l[j]]['d']):
l.pop(j)
我在按矩形面积的降序对数据集进行排序后实现了此算法,因为面积较大的矩形不适合面积较小的矩形。在这里,我在检测它是否在另一个矩形内后从列表 l 中弹出矩形的索引。每次弹出一个元素时,它都会减少迭代次数。
这需要几个小时才能解决,我需要一种有效的方法来解决它,即使是十万个样本也是如此。
请帮忙!
最佳答案
这是一个您可以尝试的分而治之的小算法。
我假设只要你能快速枚举出每一对碰撞矩形,您还可以检查一个是否完全在常数时间内包含在另一个中。
因此,我们只需找到碰撞的矩形。
首先,概括如下:假设你有两个集合矩形 A
和 B
,并且您只想找到对 (a, b)
这样的矩形 a
来自A
, b
来自B
,和 a
和 b
相交。
首先,理念。考虑以下示例两组A
和 B
部分矩形用水平线分隔 L
:
+----+ +-----+
| A1 | | B1 |
| | +-----+ +-----+
+----+ | A2 |
+-----+ +-----+
| A3 |
_____________________________|_____|________ L
| |
+-------------------+##+ |
| |##| |
| B2 +##|--+
| |
+----------------------+
行L
分割集合 A
和 B
分为三个子集:
A above L: {A1, A2} (short: A>L)
A intersects L: {A3} (short: A=L)
A below L: {} (short: A<L)
B above L: {B1} (B>L)
B intersects L: {} (B=L)
B below L: {B2} (B<L)
观察只有来自以下组的矩形可以碰撞:
A<L A=L A>L
B<L y y N
B=L y y y
B>L N y y
也就是说,如果我们想找到 A
之间的所有碰撞和 B
, 一旦我们已经找到合适的线路L
,我们可以忽略之间的碰撞 A<L
与 B>L
和 A>L
与 B<L
.因此,我们得到以下分治算法: while A
和 B
不为空,找到一条合适的线(大致)最大化消除碰撞检查的数量,分割 A
和 B
每组分成三组,递归进行七个子组碰撞,忽略两个子组组合。
假设如果矩形是“小的”,并且组 A=L
和 B=L
大部分都是空的,这将(粗略地)在每一步中将集合的大小减半,因此我们获得了一个平均运行类似于 O(n*log(n))
的算法。而不是 O(n*n)
.
一旦你有了任意 A
的一般情况和 B
, 取整组矩形 R
并使用 A = R; B = R
运行算法.
这是 Python 中的粗略草图:
def isSubinterval(aStart, aEnd, bStart, bEnd):
return aStart >= bStart and aEnd <= bEnd
def intersects(aStart, aEnd, bStart, bEnd):
return not (aEnd < bStart or aStart > bEnd)
class Rectangle:
def __init__(self, l, r, b, t):
self.left = l
self.right = r
self.bottom = b
self.top = t
def isSubrectangle(self, other):
return (
isSubinterval(self.left, self.right, other.left, other.right) and
isSubinterval(self.bottom, self.top, other.bottom, other.top)
)
def intersects(self, other):
return (
intersects(self.left, self.right, other.left, other.right) and
intersects(self.bottom, self.top, other.bottom, other.top)
)
def __repr__(self):
return ("[%f,%f]x[%f,%f]" % (self.left, self.right, self.bottom, self.top))
def boundingBox(rects):
infty = float('inf')
b = infty
t = - infty
l = infty
r = - infty
for rect in rects:
b = min(b, rect.bottom)
l = min(l, rect.left)
r = max(r, rect.right)
t = max(t, rect.top)
return Rectangle(l, r, b, t)
class DividingLine:
def __init__(self, isHorizontal, position):
self.isHorizontal = isHorizontal
self.position = position
def isAbove(self, rectangle):
if self.isHorizontal:
return rectangle.bottom > self.position
else:
return rectangle.left > self.position
def isBelow(self, rectangle):
if self.isHorizontal:
return rectangle.top < self.position
else:
return rectangle.right < self.position
def enumeratePossibleLines(boundingBox):
NUM_TRIED_LINES = 5
for i in range(1, NUM_TRIED_LINES + 1):
w = boundingBox.right - boundingBox.left
yield DividingLine(False, boundingBox.left + w / float(NUM_TRIED_LINES + 1) * i)
h = boundingBox.top - boundingBox.bottom
yield DividingLine(True, boundingBox.bottom + h / float(NUM_TRIED_LINES + 1) * i)
def findGoodDividingLine(rects_1, rects_2):
bb = boundingBox(rects_1 + rects_2)
bestLine = None
bestGain = 0
for line in enumeratePossibleLines(bb):
above_1 = len([r for r in rects_1 if line.isAbove(r)])
below_1 = len([r for r in rects_1 if line.isBelow(r)])
above_2 = len([r for r in rects_2 if line.isAbove(r)])
below_2 = len([r for r in rects_2 if line.isBelow(r)])
# These groups are separated by the line, no need to
# perform all-vs-all collision checks on those groups!
gain = above_1 * below_2 + above_2 * below_1
if gain > bestGain:
bestGain = gain
bestLine = line
return bestLine
# Collides all rectangles from list `rects_1` with
# all rectangles from list `rects_2`, and invokes
# `onCollision(a, b)` on every colliding `a` and `b`.
def collideAllVsAll(rects_1, rects_2, onCollision):
if rects_1 and rects_2: # if one list empty, no collisions
line = findGoodDividingLine(rects_1, rects_2)
if line:
above_1 = [r for r in rects_1 if line.isAbove(r)]
below_1 = [r for r in rects_1 if line.isBelow(r)]
above_2 = [r for r in rects_2 if line.isAbove(r)]
below_2 = [r for r in rects_2 if line.isBelow(r)]
intersect_1 = [r for r in rects_1 if not (line.isAbove(r) or line.isBelow(r))]
intersect_2 = [r for r in rects_2 if not (line.isAbove(r) or line.isBelow(r))]
collideAllVsAll(above_1, above_2, onCollision)
collideAllVsAll(above_1, intersect_2, onCollision)
collideAllVsAll(intersect_1, above_2, onCollision)
collideAllVsAll(intersect_1, intersect_2, onCollision)
collideAllVsAll(intersect_1, below_2, onCollision)
collideAllVsAll(below_1, intersect_2, onCollision)
collideAllVsAll(below_1, below_2, onCollision)
else:
for r1 in rects_1:
for r2 in rects_2:
if r1.intersects(r2):
onCollision(r1, r2)
这是一个小演示:
rects = [
Rectangle(1,6,9,10),
Rectangle(4,7,6,10),
Rectangle(1,5,6,7),
Rectangle(8,9,8,10),
Rectangle(6,9,5,7),
Rectangle(8,9,1,6),
Rectangle(7,9,2,4),
Rectangle(2,8,2,3),
Rectangle(1,3,1,4)
]
def showInterestingCollision(a, b):
if a is not b:
if a.left < b.left:
print("%r <-> %r collision" % (a, b))
collideAllVsAll(rects, rects, showInterestingCollision)
至少在这种情况下,它确实检测到了所有有趣的碰撞:
[1.000000,6.000000]x[9.000000,10.000000] <-> [4.000000,7.000000]x[6.000000,10.000000] collision
[1.000000,5.000000]x[6.000000,7.000000] <-> [4.000000,7.000000]x[6.000000,10.000000] collision
[4.000000,7.000000]x[6.000000,10.000000] <-> [6.000000,9.000000]x[5.000000,7.000000] collision
[6.000000,9.000000]x[5.000000,7.000000] <-> [8.000000,9.000000]x[1.000000,6.000000] collision
[7.000000,9.000000]x[2.000000,4.000000] <-> [8.000000,9.000000]x[1.000000,6.000000] collision
[2.000000,8.000000]x[2.000000,3.000000] <-> [8.000000,9.000000]x[1.000000,6.000000] collision
[2.000000,8.000000]x[2.000000,3.000000] <-> [7.000000,9.000000]x[2.000000,4.000000] collision
[1.000000,3.000000]x[1.000000,4.000000] <-> [2.000000,8.000000]x[2.000000,3.000000] collision
这是一个更真实的演示:
from random import random
from matplotlib import pyplot as plt
def randomRect():
w = random() * 0.1
h = random() * 0.1
centerX = random() * (1 - w)
centerY = random() * (1 - h)
return Rectangle(
centerX - w/2, centerX + w/2,
centerY - h/2, centerY + h/2
)
randomRects = [randomRect() for _ in range(0, 500)]
for r in randomRects:
plt.fill(
[r.left, r.right, r.right, r.left],
[r.bottom, r.bottom, r.top, r.top],
'b-',
color = 'k',
fill = False
)
def markSubrectanglesRed(a, b):
if a is not b:
if a.isSubrectangle(b):
plt.fill(
[a.left, a.right, a.right, a.left],
[a.bottom, a.bottom, a.top, a.top],
'b-',
color = 'r',
alpha = 0.4
)
plt.fill(
[b.left, b.right, b.right, b.left],
[b.bottom, b.bottom, b.top, b.top],
'b-',
color = 'b',
fill = False
)
collideAllVsAll(randomRects, randomRects, markSubrectanglesRed)
plt.show()
该图以红色显示所有消除的矩形,以蓝色显示封闭矩形:
这是一个具有单次碰撞的小示例的准二元空间划分的边界框(黄色)和选择的分界线(青色)的可视化:
对于 10000 个“合理大小”的随机矩形(相交率与图像中大致相同),它会在 18 秒内计算出所有碰撞,即使代码远未优化。
关于python - 如何检测矩形中的矩形?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49566288/
我正在尝试将外框内的框(坐标)放入。我已经使用交集联合方法完成了工作,并且我希望其他方法也可以这样做。 另外,能否请您告诉我如何比较这两个内盒? 最佳答案 通过比较边界框和内部框的左上角和右下角的坐标
我希望输出看起来像这样: 如何安排这些循环以获得两个三角形数字模式?我该如何改进我的代码。 JAVA 中的新功能:-) for (int i = 1; icount; num--) {
我需要将 map 边界存储在 MySQL 数据库中。我花了一些时间在地理空间扩展的文档上,但是学习所有相关信息(WKT、WKB 等)很困难,而且就我而言没有必要。我只需要一种方法来存储坐标矩形并稍后将
在 gnuplot 中,我可以通过绘制一个矩形 set object rect from x0,y0 to x1,y1 如何从文件中读取坐标 x0,x1,y0,y1? 最佳答案 一种方法是将设置矩形的
我正在尝试创建一个填充了水平线或垂直线的矩形。 矩形的宽度是动态的,所以我不能使用图像刷。 如果有人知道任何解决方案,请告诉我。 最佳答案 我想出了一个直接的方法来做到这一点;最后,我使用以下视觉画笔
这个 SVG 在所有浏览器中看起来都很模糊,在所有缩放级别。 在 Chrome、Safari 和 Firefox 中,它看起来像这样: 如果放大,您可以看到笔画有两个像素的宽度,即使默认笔画
我正在尝试在ggplot2图上添加多个阴影/矩形。在这个可重现的示例中,我只添加了3,但是使用完整数据可能需要总计一百。 这是我的原始数据的子集-在名为temp的数据框中-dput在问题的底部:
我有一个包含驻留在 Viewport3D 中的 3D 对象的应用程序,我希望用户能够通过在屏幕上拖动一个矩形来选择它们。 我尝试在 Viewport3D 上应用 GeometryHitTestPara
如何才能使 WPF 矩形的顶角变成圆角? 我创建了一个边框并设置了 CornerRadius 属性,并在边框内添加了矩形,但它不起作用,矩形不是圆角的。 最佳答案 您遇到的问题是矩形“溢
我正在尝试使用此 question 中的代码旋转 Leaflet 矩形。 rotatePoints (center, points, yaw) { const res = [] const a
我有以下图像。 this image 我想删除数字周围的橙色框/矩形,并保持原始图像干净,没有任何橙色网格/矩形。 以下是我当前的代码,但没有将其删除。 Mat mask = new Mat(); M
我发现矩形有些不好笑: 比方说,给定的是左、上、右和下坐标的值,所有这些坐标都旨在包含在内。 所以,计算宽度是这样的: width = right - left + 1 到目前为止,一切都很合乎逻辑。
所以,我一直在学习 Java,但我还是个新手,所以请耐心等待。我最近的目标是图形化程序,这次是对键盘控制的测试。由于某种原因,该程序不会显示矩形。通常,paint() 会独立运行,但由于某种原因它不会
我正在阅读 website 中的解决方案 3 (2D)并试图将其翻译成java代码。 java是否正确请评论。我使用的是纬度和经度坐标,而不是 x 和 y 坐标(注意:loc.getLongitude
我似乎无法删除矩形上的边框!请参阅下面的代码,我正在使用 PDFannotation 创建链接。这些链接都有效,但每个矩形都有一个边框。 PdfAnnotation annotation; Recta
如何在保持原始位图面积的同时将位图旋转给定的度数。即,我旋转宽度:100,高度:200 的位图,我的最终结果将是一个更大的图像,但旋转部分的面积仍然为 100*200 最佳答案 图形转换函数非常适合这
我创建了矩形用户控件,我在我的应用程序中使用了这个用户控件。在我的应用程序中,我正在处理图像以进行不同的操作,例如从图像中读取条形码等。这里我有两种处理图像的可能性,一种正在处理整个图像,另一个正在处
好的,我该如何开始呢? 我有一个应用程序可以在屏幕上绘制一些形状(实际上是几千个)。它们有两种类型:矩形和直线。矩形有填充,线条有描边 + 描边厚度。 我从两个文件中读取数据,一个是顶部的数据,一个是
简而言之: 我正在致力于使用 AI 和 GUI 创建纸牌游戏。用户的手显示在游戏界面上,我尚未完成界面,但我打算将牌面图像添加到屏幕上的矩形中。我没有找到 5 种几乎相同的方法,而是找到了一篇类似的文
我遇到了麻烦。我正在尝试使用用户输入的数组列表创建条形图。我可以创建一个条,但只会创建一个条。我需要所有数组输入来创建一个条。 import java.awt.Color; import java.a
我是一名优秀的程序员,十分优秀!