Python 找出给定多边形边的两个区域是否相交
这个问题一直困扰着我一段时间了。 我确实找到了一个解决方案,我可以找到每个多边形中的每个点,然后检查交点。然而,这在计算上是昂贵的,而且根本不实用 下图中有四行;两条红线和两条蓝线。我想检查两条红线之间的区域是否与两条蓝线之间的区域相交 已知以下变量:Python 找出给定多边形边的两个区域是否相交,python,opencv,python-imaging-library,computational-geometry,intersection,Python,Opencv,Python Imaging Library,Computational Geometry,Intersection,这个问题一直困扰着我一段时间了。 我确实找到了一个解决方案,我可以找到每个多边形中的每个点,然后检查交点。然而,这在计算上是昂贵的,而且根本不实用 下图中有四行;两条红线和两条蓝线。我想检查两条红线之间的区域是否与两条蓝线之间的区域相交 已知以下变量: 每行开始的点 每条线的角度 线条结束的位置(始终位于图像的边缘) 我在考虑使用斜率公式来检查红线的原点相对于每条蓝线落在哪里。但我不确定这是否是最好的方法 提前感谢。如果每种颜色都有两条线,且在图像边界上有一个共同的起点和不同的终点,则只需创建
提前感谢。如果每种颜色都有两条线,且在图像边界上有一个共同的起点和不同的终点,则只需创建一个遮罩,绘制这些线,计算两个端点之间的中点,并将该中点用作某些整体填充的种子点。由于您有一个闭合多边形,因此该中点保证位于多边形内部。根据这两个遮罩,确定交点(逻辑与),并检查至少一个像素重叠 下面是一些使用OpenCV和NumPy的代码:
导入cv2
将numpy作为np导入
#树立形象
w、 h=(400300)
img=np.one((h,w,3),np.uint8)*255
#设置颜色
颜色={
“红色”:(0,0255),
“蓝色”:(255,0,0)
}
#设置每种颜色的线条,第一个元素是公共点
行={
"红色":[(200150),(380,0),(200150),(200,0)],,
“蓝色”:[((100100),(399100)),((100100),(300,0))]
}
#设置每种颜色的遮罩
面具={
“红色”:np.0((h,w),np.uint8),
“蓝色”:np.0((h,w),np.uint8)
}
#对于每种颜色。。。
对于['Red','Blue']中的c:
对于第[c]行中的第行:
# ... 在图像中画彩色线。。。
img=cv2.行(img,行[0],行[1],颜色[c],2)
# ... 在面具上画白线。。。
掩码[c]=cv2.行(掩码[c],行[0],行[1],255,1)
# ... 找到两个端点之间的中点,然后。。。
mid=tuple(np.int0(np.sum(np.array(lines[c])[:,1,:],axis=0)/2))
# ... 使用中点作为种子点的整体填充遮罩
遮罩[c]=cv2.泛洪填充(遮罩[c],无,中,255)[1]
#逻辑和所有遮罩,并检查至少一个像素重叠
inter=np.all(np.array(list(masks.values())),axis=0.astype(np.uint8)*255
打印('Is intersection:',inter.max()>0)
#输出
cv2.imshow(“图像”,img)
cv2.imshow('红色遮罩',遮罩['红色']))
cv2.imshow(“蓝色遮罩”,遮罩[“蓝色”])
cv2.imshow(“交叉口”,中间)
cv2.等待键(0)
cv2.destroyAllWindows()
图片:
红色面具:
蓝色面具:
交叉口:
intersection = np.logical_and(red_poly, blue_poly)
# plt.imshow(intersection)
决定:
是否为交点:True
该代码可以很容易地推广到添加更多的颜色(或多边形)
----------------------------------------
系统信息
----------------------------------------
平台:Windows-10-10.0.16299-SP0
Python:3.9.1
皮查姆:2021.1
NumPy:1.20.2
OpenCV:4.5.1
----------------------------------------
解决此问题主要有两种方法:
1.线性规划
将问题表示为线性不等式组,并将其作为线性规划问题求解,如下所述:。在你的例子中,不等式的形式是(x-ox[i])*sin(a[i])-(y-oy[i])*cos(a[i])>0
或(x-ox[i])*sin(a[i])-(y-oy[i])*cos(a[i])<0
,这取决于你如何定义第i条线的角度a[i]
,以及该线的哪一侧放置多边形<代码>(ox[i],oy[i])是第i个顶点的坐标。如果不等式严格与否,则取决于如何处理多边形与顶点或边接触的边界情况。这是一个很好的、易于推广的方法,但它可能很慢
2.交叉测试
在一般情况下(没有顶点和边重合),有4种可能性:(1)一些边相交;(2) 多边形1在多边形2内;(3) 多边形2在多边形1内;(4) 多边形不相交。您需要测试前3个案例
对于案例1,您需要执行此处所述的线段相交测试,并尝试将多边形1的每条边与多边形2的每条边相交,这在您的案例中不是问题,因为最多会有2*2=4
测试。如果检测到至少一个交叉口,则完成
对于情况2和3,需要测试多边形1的顶点是否在多边形2内,反之亦然。可以使用中所述的相同测试IsOnLeft
和IsOnRight
:如果一个点位于右线的左侧和左线的右侧,则该点位于内部
在任何情况下,都应该特别注意退化和边界情况:如果多边形的边重合,或者一个多边形的顶点位于另一个多边形的边上,或者不同多边形的边重合,该怎么办。根据您的特殊目的,您可能会对此类情况进行不同的检测和处理。这是一个使用小型单通道图像10x10像素的示例
basic_img = np.zeros([10, 10], dtype=np.uint8)
一旦你有了点的坐标,让我们说:
pts_red = np.array([(9, 0), (9, 6), (4, 2), (4, 0)], dtype=np.int32)
pts_blue = np.array([(9, 0), (9, 1), (0, 8), (6, 0)], dtype=np.int32)
可以使用绘制线之间包含的多边形:
red_poly = basic_img.copy()
cv2.fillPoly(red_poly, [pts_red], 1)
# plt.imshow(red_poly)
及
然后使用以获取交叉点:
intersection = np.logical_and(red_poly, blue_poly)
# plt.imshow(intersection)
最后,检查任何真值以获得布尔结果:
np.any(intersection) #=> True
这里是本例的打印图像。 蓝色保利 红色保利 十字路口
这里有一个枕头版本的,包含了相同的想法。然而,此版本仅限于两种颜色。添加更多颜色(或多边形)需要额外的工作(基本上是一些循环)
从PIL导入Ima
import cv2
import numpy as np
def intersected(img, masks):
img_hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
for lower, upper in masks:
mask = cv2.inRange(img_hsv, np.array(lower), np.array(upper))
blur = cv2.GaussianBlur(mask, (5, 5), 0)
canny = cv2.Canny(blur, 0, 0)
contours, _ = cv2.findContours(canny, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
count = 0
for cnt in contours:
if cv2.contourArea(cnt) > 50:
cv2.drawContours(img, [cnt], -1, (0, 255, 0), 1)
cv2.imshow("Test", img)
count += 1
if count == 2:
return True
img = cv2.imread("shapes.png")
blue_mask = [1, 0, 0], [178, 255, 255]
red_mask = [0, 1, 0], [179, 254, 255]
if intersected(img, (blue_mask, red_mask)):
print("Intersection detected!")
else:
print("No intersection detected.")
Intersection detected!
import cv2
import numpy as np
def intersected(img, masks):
img_hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
for lower, upper in masks:
mask = cv2.inRange(img_hsv, np.array(lower), np.array(upper))
blur = cv2.GaussianBlur(mask, (5, 5), 0)
canny = cv2.Canny(blur, 0, 0)
contours, _ = cv2.findContours(canny, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
count = 0
for cnt in contours:
if cv2.contourArea(cnt) > 50:
cv2.drawContours(img, [cnt], -1, (0, 255, 0), 1)
cv2.imshow("Test", img)
count += 1
if count == 2:
return True
img = cv2.imread("shapes.png")
blue_mask = [1, 0, 0], [178, 255, 255]
red_mask = [0, 1, 0], [179, 254, 255]
if intersected(img, (blue_mask, red_mask)):
print("Intersection detected!")
else:
print("No intersection detected.")