我试图弄清楚如何仅使用其角的坐标来缩小多边形。例如,如果我在[(0, 0), (0, 100), (20, 100), (30, 60), (40, 100), (60, 100), (60, 0), (40, 10), (40, 40), (20, 40), (20, 10)]
处有以下形状的角,那么形状如下所示:
如果我将这个多边形缩小某个宽度和高度因子,我想找到角坐标。例如,如果我想将其宽度缩小10%,将高度缩小20%,那么可以显示如下:
我试图使用cv2.resize()
执行此操作,但在调整大小后无法获得角落。我一直试图找到一个多边形大小调整或多边形收缩的算法,但无法找到有关如何执行此操作的任何内容。是否存在用于执行此类操作的任何算法或包?
答案 0 :(得分:5)
我已经在加利福尼亚州的 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
答案 1 :(得分:2)
我误解了这个问题,我放弃了答案,因为它可能对某人有帮助,但我发现最终的输出不是理想的输出
要在缩小后获取多边形的新坐标,可以将所有坐标(position vectors)乘以收缩因子,如下所示:
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)
输出以下内容(蓝色为原始,绿色为收缩多边形)
答案 2 :(得分:2)
据我所知,您正在搜索ST_Buffer from postgis的功能,但有不同的因素。 不幸的是,这并不容易实现(有关更多信息,请参见one question in the 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()
答案 3 :(得分:0)
我认为在数学上不可能在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])))
我从this answer @Paul Draper获得了线路交叉码。