138 lines
4.9 KiB
Python
138 lines
4.9 KiB
Python
|
import numpy as np
|
||
|
|
||
|
|
||
|
def fit_line(p1, p2):
|
||
|
# fit a line ax+by+c = 0
|
||
|
if p1[0] == p1[1]:
|
||
|
return [1., 0., -p1[0]]
|
||
|
else:
|
||
|
[k, b] = np.polyfit(p1, p2, deg=1)
|
||
|
return [k, -1., b]
|
||
|
|
||
|
|
||
|
def line_cross_point(line1, line2):
|
||
|
# line1 0= ax+by+c, compute the cross point of line1 and line2
|
||
|
if line1[0] != 0 and line1[0] == line2[0]:
|
||
|
print('Cross point does not exist')
|
||
|
return None
|
||
|
if line1[0] == 0 and line2[0] == 0:
|
||
|
print('Cross point does not exist')
|
||
|
return None
|
||
|
if line1[1] == 0:
|
||
|
x = -line1[2]
|
||
|
y = line2[0] * x + line2[2]
|
||
|
elif line2[1] == 0:
|
||
|
x = -line2[2]
|
||
|
y = line1[0] * x + line1[2]
|
||
|
else:
|
||
|
k1, _, b1 = line1
|
||
|
k2, _, b2 = line2
|
||
|
x = -(b1-b2)/(k1-k2)
|
||
|
y = k1*x + b1
|
||
|
return np.array([x, y], dtype=np.float32)
|
||
|
|
||
|
|
||
|
def line_verticle(line, point):
|
||
|
# get the verticle line from line across point
|
||
|
if line[1] == 0:
|
||
|
verticle = [0, -1, point[1]]
|
||
|
else:
|
||
|
if line[0] == 0:
|
||
|
verticle = [1, 0, -point[0]]
|
||
|
else:
|
||
|
verticle = [-1./line[0], -1, point[1] - (-1/line[0] * point[0])]
|
||
|
return verticle
|
||
|
|
||
|
|
||
|
|
||
|
def rectangle_from_parallelogram(poly):
|
||
|
'''
|
||
|
fit a rectangle from a parallelogram
|
||
|
:param poly:
|
||
|
:return:
|
||
|
'''
|
||
|
p0, p1, p2, p3 = poly
|
||
|
angle_p0 = np.arccos(np.dot(p1-p0, p3-p0)/(np.linalg.norm(p0-p1) * np.linalg.norm(p3-p0)))
|
||
|
if angle_p0 < 0.5 * np.pi:
|
||
|
if np.linalg.norm(p0 - p1) > np.linalg.norm(p0-p3):
|
||
|
# p0 and p2
|
||
|
## p0
|
||
|
p2p3 = fit_line([p2[0], p3[0]], [p2[1], p3[1]])
|
||
|
p2p3_verticle = line_verticle(p2p3, p0)
|
||
|
|
||
|
new_p3 = line_cross_point(p2p3, p2p3_verticle)
|
||
|
## p2
|
||
|
p0p1 = fit_line([p0[0], p1[0]], [p0[1], p1[1]])
|
||
|
p0p1_verticle = line_verticle(p0p1, p2)
|
||
|
|
||
|
new_p1 = line_cross_point(p0p1, p0p1_verticle)
|
||
|
return np.array([p0, new_p1, p2, new_p3], dtype=np.float32)
|
||
|
else:
|
||
|
p1p2 = fit_line([p1[0], p2[0]], [p1[1], p2[1]])
|
||
|
p1p2_verticle = line_verticle(p1p2, p0)
|
||
|
|
||
|
new_p1 = line_cross_point(p1p2, p1p2_verticle)
|
||
|
p0p3 = fit_line([p0[0], p3[0]], [p0[1], p3[1]])
|
||
|
p0p3_verticle = line_verticle(p0p3, p2)
|
||
|
|
||
|
new_p3 = line_cross_point(p0p3, p0p3_verticle)
|
||
|
return np.array([p0, new_p1, p2, new_p3], dtype=np.float32)
|
||
|
else:
|
||
|
if np.linalg.norm(p0-p1) > np.linalg.norm(p0-p3):
|
||
|
# p1 and p3
|
||
|
## p1
|
||
|
p2p3 = fit_line([p2[0], p3[0]], [p2[1], p3[1]])
|
||
|
p2p3_verticle = line_verticle(p2p3, p1)
|
||
|
|
||
|
new_p2 = line_cross_point(p2p3, p2p3_verticle)
|
||
|
## p3
|
||
|
p0p1 = fit_line([p0[0], p1[0]], [p0[1], p1[1]])
|
||
|
p0p1_verticle = line_verticle(p0p1, p3)
|
||
|
|
||
|
new_p0 = line_cross_point(p0p1, p0p1_verticle)
|
||
|
return np.array([new_p0, p1, new_p2, p3], dtype=np.float32)
|
||
|
else:
|
||
|
p0p3 = fit_line([p0[0], p3[0]], [p0[1], p3[1]])
|
||
|
p0p3_verticle = line_verticle(p0p3, p1)
|
||
|
|
||
|
new_p0 = line_cross_point(p0p3, p0p3_verticle)
|
||
|
p1p2 = fit_line([p1[0], p2[0]], [p1[1], p2[1]])
|
||
|
p1p2_verticle = line_verticle(p1p2, p3)
|
||
|
|
||
|
new_p2 = line_cross_point(p1p2, p1p2_verticle)
|
||
|
return np.array([new_p0, p1, new_p2, p3], dtype=np.float32)
|
||
|
|
||
|
|
||
|
def sort_rectangle(poly):
|
||
|
# sort the four coordinates of the polygon, points in poly should be sorted clockwise
|
||
|
# First find the lowest point
|
||
|
p_lowest = np.argmax(poly[:, 1])
|
||
|
if np.count_nonzero(poly[:, 1] == poly[p_lowest, 1]) == 2:
|
||
|
# 底边平行于X轴, 那么p0为左上角 - if the bottom line is parallel to x-axis, then p0 must be the upper-left corner
|
||
|
p0_index = np.argmin(np.sum(poly, axis=1))
|
||
|
p1_index = (p0_index + 1) % 4
|
||
|
p2_index = (p0_index + 2) % 4
|
||
|
p3_index = (p0_index + 3) % 4
|
||
|
return poly[[p0_index, p1_index, p2_index, p3_index]], 0.
|
||
|
else:
|
||
|
# 找到最低点右边的点 - find the point that sits right to the lowest point
|
||
|
p_lowest_right = (p_lowest - 1) % 4
|
||
|
p_lowest_left = (p_lowest + 1) % 4
|
||
|
angle = np.arctan(-(poly[p_lowest][1] - poly[p_lowest_right][1])/(poly[p_lowest][0] - poly[p_lowest_right][0]))
|
||
|
# assert angle > 0
|
||
|
# if angle <= 0:
|
||
|
# print(angle, poly[p_lowest], poly[p_lowest_right])
|
||
|
if angle/np.pi * 180 > 45:
|
||
|
# 这个点为p2 - this point is p2
|
||
|
p2_index = p_lowest
|
||
|
p1_index = (p2_index - 1) % 4
|
||
|
p0_index = (p2_index - 2) % 4
|
||
|
p3_index = (p2_index + 1) % 4
|
||
|
return poly[[p0_index, p1_index, p2_index, p3_index]], -(np.pi/2 - angle)
|
||
|
else:
|
||
|
# 这个点为p3 - this point is p3
|
||
|
p3_index = p_lowest
|
||
|
p0_index = (p3_index + 1) % 4
|
||
|
p1_index = (p3_index + 2) % 4
|
||
|
p2_index = (p3_index + 3) % 4
|
||
|
return poly[[p0_index, p1_index, p2_index, p3_index]], angle
|