使用角坐标缩小多边形

7

我正在尝试仅使用多边形的角落坐标来缩小一个多边形。例如,如果我有以下形状,其角落坐标为[(0, 0), (0, 100), (20, 100), (30, 60), (40, 100), (60, 100), (60, 0), (40, 10), (40, 40), (20, 40), (20, 10)],则该形状如下所示:

enter image description here

我想找到这个多边形缩小一定宽度和高度因子后的角落坐标。例如,如果我想将其宽度缩小10%,高度缩小20%,则可以显示为:

enter image description here

我试图使用cv2.resize()来完成这个任务,但是在调整大小后无法获得角落。我一直在寻找多边形缩放或多边形收缩的算法,但是没有找到任何关于如何做到这一点的信息。是否存在任何算法或软件包可以做到这样的事情?

2
按照公式,这个问题更容易使用简单的解析几何方法来解决(编写直线方程,沿垂线偏移它们,确定新的交点),而不是使用关于视觉/识别的openCV。 - 9000
相关链接:https://dev59.com/iXNA5IYBdhLWcg3wC5Xh - Catree
在将您的对象点绕原点居中后,使用透视变换(perspectiveTransform)对所有点进行所需大小因子的操作。 - Micka
透视变换不会按照你想要的方式工作,但它与调整图像大小相同。 - Micka
4个回答

9

我已经在加利福尼亚州的1200个真实建筑物上测试了这个解决方案,它表现出色。

另外一件事是,同样的方法也适用于放大多边形,同样效果良好。 下面的方法可以直接使用:

def shrink_or_swell_shapely_polygon(my_polygon, factor=0.10, swell=False):
    ''' returns the shapely polygon which is smaller or bigger by passed factor.
        If swell = True , then it returns bigger polygon, else smaller '''
    from shapely import geometry

    #my_polygon = mask2poly['geometry'][120]

    shrink_factor = 0.10 #Shrink by 10%
    xs = list(my_polygon.exterior.coords.xy[0])
    ys = list(my_polygon.exterior.coords.xy[1])
    x_center = 0.5 * min(xs) + 0.5 * max(xs)
    y_center = 0.5 * min(ys) + 0.5 * max(ys)
    min_corner = geometry.Point(min(xs), min(ys))
    max_corner = geometry.Point(max(xs), max(ys))
    center = geometry.Point(x_center, y_center)
    shrink_distance = center.distance(min_corner)*0.10

    if swell:
        my_polygon_resized = my_polygon.buffer(shrink_distance) #expand
    else:
        my_polygon_resized = my_polygon.buffer(-shrink_distance) #shrink

    #visualize for debugging
    #x, y = my_polygon.exterior.xy
    #plt.plot(x,y)
    #x, y = my_polygon_shrunken.exterior.xy
    #plt.plot(x,y)
    ## to net let the image be distorted along the axis
    #plt.axis('equal')
    #plt.show()    
    
    return my_polygon_resized

enter image description here


8
据我所理解,您正在寻找与postgis中的ST_Buffer相同但分离的因素的功能。不幸的是,这并不容易实现(有关详细信息,请参见qgis-stack中的一个问题)。
但是,如果将x和y使用相同的因子进行操作(或作为更复杂算法的起点),则可以帮助您:
一种使ST_Buffer函数在python中可用的库是shapely
(如果您需要更多的地理数据特定功能,则geoalchemy2可能是更好的选择。请注意,在这种情况下crs / srid的变化)

from shapely import geometry
import matplotlib.pyplot as plt

# your variables
coords = [(0, 0), (0, 100), (20, 100), (30, 60), (40, 100), (60, 100), (60, 0), (40, 10), (40, 40), (20, 40), (20, 10)]
lines = [[coords[i-1], coords[i]] for i in range(len(coords))]

# your factor of 10%
# Note: with 20% the polygon becomes a multi-polygon, so a loop for plotting would be needed.
factor = 0.1

# code from nathan
xs = [i[0] for i in coords]
ys = [i[1] for i in coords]
x_center = 0.5 * min(xs) + 0.5 * max(xs)
y_center = 0.5 * min(ys) + 0.5 * max(ys)

min_corner = geometry.Point(min(xs), min(ys))
max_corner = geometry.Point(max(xs), max(ys))
center = geometry.Point(x_center, y_center)
shrink_distance = center.distance(min_corner)*factor

assert abs(shrink_distance - center.distance(max_corner)) < 0.0001

my_polygon = geometry.Polygon(coords)
my_polygon_shrunken = my_polygon.buffer(-shrink_distance)


x, y = my_polygon.exterior.xy
plt.plot(x,y)
x, y = my_polygon_shrunken.exterior.xy
plt.plot(x,y)

# to net let the image be distorted along the axis
plt.axis('equal')

plt.show()


enter image description here


3
我误读了问题,但我保留答案以便帮助他人。但我意识到最终输出结果并不是所需的。
要获得多边形收缩后的新坐标,您可以像这样将所有坐标(位置向量)与收缩因子相乘:
x_shrink = 0.1
y_shrink = 0.2

coords = [(0, 0), (0, 100), (20, 100), (30, 60), (40, 100), (60, 100), (60, 0), (40, 10), (40, 40), (20, 40), (20, 10)]
xs = [i[0] for i in coords]
ys = [i[1] for i in coords]

# simplistic way of calculating a center of the graph, you can choose your own system
x_center = 0.5 * min(xs) + 0.5 * max(xs)
y_center = 0.5 * min(ys) + 0.5 * max(ys)

# shrink figure
new_xs = [(i - x_center) * (1 - x_shrink) + x_center for i in xs]
new_ys = [(i - y_center) * (1 - y_shrink) + y_center for i in ys]

# create list of new coordinates
new_coords = zip(new_xs, new_ys)

这将输出以下内容(蓝色为原始图形,绿色为缩小后的多边形)。

enter image description here


这也是我最初尝试做的事情。可惜,它没有成功,因为缩小版本实际上会在多边形的凹陷区域重叠,例如在您尝试的底部。 - TheStrangeQuark
@greenthumbtack 如果你指定几个中心,一个用于左边,一个用于右边,一个用于中间,那么它可能会起作用。不过这样会变得非常大或需要很多手工操作... - Nathan
是的,但那将是另一个问题。这些多边形是由用户创建的,我无法预先确定它们的形状。我需要编写一种方法来确定许多不同的属性,我想象中的。 - TheStrangeQuark

1

我认为在x轴和y轴上同时进行百分比缩小并且不使布局超出原始布局是数学上不可能的。但这只是我的猜测。

此代码将所有线条向中心移动一定距离,然后找到所有线条的新交点:

import matplotlib.pyplot as plt

def det(a, b):
        return a[0] * b[1] - a[1] * b[0]

def line_intersection(line1, line2):
    xdiff = (line1[0][0] - line1[1][0], line2[0][0] - line2[1][0])
    ydiff = (line1[0][1] - line1[1][1], line2[0][1] - line2[1][1]) #Typo was here

    div = det(xdiff, ydiff)
    if div == 0:
       raise Exception('lines do not intersect')

    d = (det(*line1), det(*line2))
    x = det(d, xdiff) / div
    y = det(d, ydiff) / div
    return x, y

# how much the coordinates are moved as an absolute value
shrink_value_x = 3
shrink_value_y = 1.5

# coords must be clockwise
coords = [(0, 0), (0, 100), (20, 100), (30, 60), (40, 100), (60, 100), (60, 0), (40, 10), (40, 40), (20, 40), (20, 10)]
lines = [[coords[i-1], coords[i]] for i in range(len(coords))]

new_lines = []
for i in lines:
    dx = i[1][0] - i[0][0]
    dy = i[1][1] - i[0][1]

    # this is to take into account slopes
    factor = 1 / (dx*dx + dy*dy)**0.5
    new_dx = dy*shrink_value_x * factor
    new_dy = dx*shrink_value_y * factor

    new_lines.append([(i[0][0] + new_dx, i[0][1] - new_dy),
                      (i[1][0] + new_dx, i[1][1] - new_dy)])

# find position of intersection of all the lines
new_coords = []
for i in range(len(new_lines)):
    new_coords.append((line_intersection(new_lines[i-1], new_lines[i])))

我从Paul Draper那里得到了线段相交的代码。

这将输出输出图示


请参考 https://dev59.com/iXNA5IYBdhLWcg3wC5Xh 获取进行多边形偏移的库。 - Catree

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接