尝试减少一下代码冗余,好像没减多少
class QuadrilateralVertexSort(object):
'''
输入: 任意顺序的四边形四顶点坐标 list [[x1,y1],[x2,y2],[x3,y3],[x4,y4]]
输出: 四边形的 [[左上x,左上y], [右上x,右上y], [右下x,右下y], [左下x,左下y]]
左优先,上其次
'''
def __init__(self, points):
self.points = points
self.res = None
self.left_index = [0]
self.top_index = [0]
self.right_index = [0]
self.bot_index = [0]
self.获上下左右第一的点()
# print("获取第一的 左上右下", self.left_index, self.top_index, self.right_index, self.bot_index)
self.获上下左右第二的点()
# print("获取第二的 左上右下", self.left_index, self.top_index, self.right_index, self.bot_index)
if self.res is None:
self.十字分割()
print("十字分割后", self.left_top_points, self.right_top_points, '\n ', self.left_bot_points,
self.right_bot_points)
if self.res is None:
self.十字格分析()
print("十字格分析后")
if self.res is None:
self.十字格分析2()
print("十字格分析2后")
if self.res is not None:
print("请通过属性 res 获取结果", self.res)
else:
print("宝宝不知道怎么处理了,您还是想其他办法吧")
def 获上下左右第一的点(self):
# 获取最 上下左右的点
for i in range(1, 4):
# 最左
if self.points[i][0] < self.points[self.left_index[0]][0]:
self.left_index[0] = i
# 最右
if self.points[i][0] > self.points[self.right_index[0]][0]:
self.right_index[0] = i
# 最上
if self.points[i][1] < self.points[self.top_index[0]][1]:
self.top_index[0] = i
# 最下
if self.points[i][1] > self.points[self.bot_index[0]][1]:
self.bot_index[0] = i
def 获上下左右第二的点(self):
surplus_lr = []
surplus_tb = []
# 拿到剩余的
for i in range(4):
if i not in self.left_index and i not in self.right_index:
surplus_lr.append(i)
if i not in self.top_index and i not in self.bot_index:
surplus_tb.append(i)
# 对比区分 次最左最右
if self.points[surplus_lr[0]][0] > self.points[surplus_lr[1]][0]:
self.left_index.append(surplus_lr[1])
self.right_index.append(surplus_lr[0])
elif self.points[surplus_lr[0]][0] < self.points[surplus_lr[1]][0]:
self.left_index.append(surplus_lr[0])
self.right_index.append(surplus_lr[1])
# 对比区分 次最上最下
if self.points[surplus_tb[0]][1] > self.points[surplus_tb[1]][1]:
self.top_index.append(surplus_tb[1])
self.bot_index.append(surplus_tb[0])
elif self.points[surplus_tb[0]][1] < self.points[surplus_tb[1]][1]:
self.top_index.append(surplus_tb[0])
self.bot_index.append(surplus_tb[1])
# 如果当前结果满足,赋值最终值
if 1 == max(len(self.left_index), len(self.top_index), len(self.right_index), len(self.bot_index)):
self.res = [
self.points[self.left_index[0]], self.points[self.top_index[0]], self.points[self.right_index[0]],
self.points[self.bot_index[0]]
]
def 十字分割(self):
left_top_points = []
right_top_points = []
left_bot_points = []
right_bot_points = []
# 十字线分割,拿到四个区域的点
for i in range(4):
if i in self.left_index and i in self.top_index:
left_top_points.append(i)
if i in self.right_index and i in self.top_index:
right_top_points.append(i)
if i in self.left_index and i in self.bot_index:
left_bot_points.append(i)
if i in self.right_index and i in self.bot_index:
right_bot_points.append(i)
# 如果当前结果满足,赋值最终值
if 1 == min(len(left_top_points), len(right_top_points), len(right_bot_points), len(left_bot_points)):
x1, y1 = self.points[left_top_points[0]]
x2, y2 = self.points[right_top_points[0]]
x4, y4 = self.points[left_bot_points[0]]
if x4 < x1 and y2 > y1:
self.res = [
self.points[left_bot_points[0]], self.points[left_top_points[0]], self.points[right_top_points[0]],
self.points[right_bot_points[0]]
]
else:
self.res = [
self.points[left_top_points[0]], self.points[right_top_points[0]], self.points[right_bot_points[0]],
self.points[left_bot_points[0]]
]
self.left_top_points = left_top_points
self.right_top_points = right_top_points
self.right_bot_points = right_bot_points
self.left_bot_points = left_bot_points
def 十字格分析(self):
# 处理有点落在十字线上,导致有的区域没有点
def test(left_points, right_points, d2: bool = True):
idx1 = left_points[0]
idx2 = right_points[0]
if 2 == len(self.top_index):
if d2:
# [左上, 上, 右下, 下]
res_index = [
idx1, self.top_index[self.top_index.index(idx1) - 1], idx2,
self.bot_index[self.bot_index.index(idx2) - 1]
]
else:
# [左下, 上, 右上, 下]
res_index = [
idx1, self.top_index[self.top_index.index(idx2) - 1], idx2,
self.bot_index[self.bot_index.index(idx1) - 1]
]
elif 2 == len(self.left_index):
# 次左点存在,说明竖线上没点,上个版本这里有遗漏
x1, y1 = self.points[idx1]
x2, y2 = self.points[self.left_index[self.left_index.index(idx1) - 1]]
if x1 < x2:
if d2:
# [左上, 右, 右下, 左]
res_index = [
idx1, self.right_index[self.right_index.index(idx2) - 1], idx2,
self.left_index[self.left_index.index(idx1) - 1]
]
else:
# 如果左下比左更靠左, [左下, 左, 右上, 右]
res_index = [
idx1, self.left_index[self.left_index.index(idx1) - 1], idx2,
self.right_index[self.right_index.index(idx2) - 1]
]
else:
if d2:
# [左, 左上, 右, 右下]
res_index = [
self.left_index[self.left_index.index(idx1) - 1], idx1,
self.right_index[self.right_index.index(idx2) - 1], idx2
]
else:
# [左, 右上, 右, 左下]
res_index = [
self.left_index[self.left_index.index(idx1) - 1], idx2,
self.right_index[self.right_index.index(idx2) - 1], idx1
]
else:
raise Exception("超出预想1")
return res_index
if 1 == len(self.left_top_points):
# 如果左上区有点,右下区应该一定有点
res_index = test(self.left_top_points, self.right_bot_points, d2=True)
elif 1 == len(self.left_bot_points):
# 如果左下区有点,右上区应该一定有点
res_index = test(self.left_bot_points, self.right_top_points, d2=False)
else:
return
# 赋值最终值
self.res = [
self.points[res_index[0]], self.points[res_index[1]], self.points[res_index[2]], self.points[res_index[3]]
]
def 十字格分析2(self):
# 四个点落在了两个区
res_index = [None, None, None, None]
def test(left_points, right_points, d2=1):
if d2 not in (1, -1):
return
# 起点
if self.points[left_points[0]][1] == self.points[left_points[1]][1]:
res_index[0], res_index[d2] = self.left_index[0], self.left_index[1]
elif self.points[left_points[0]][0] == self.points[left_points[1]][0]:
if 1 == d2:
res_index[0], res_index[d2] = self.top_index[1], self.top_index[0]
else:
res_index[0], res_index[d2] = self.bot_index[1], self.bot_index[0]
else:
if 1 == d2:
ltb_idx1 = self.top_index[0]
ltb_idx2 = self.top_index[1]
else:
ltb_idx1 = self.bot_index[1]
ltb_idx2 = self.bot_index[0]
ltbx, ltby = self.points[ltb_idx1]
ltbx0, ltby0 = self.points[ltb_idx2]
k1 = (ltby - self.points[right_points[0]][1]) / (ltbx - self.points[right_points[0]][0])
b1 = ltby - k1 * ltbx
k2 = (ltby - self.points[right_points[1]][1]) / (ltbx - self.points[right_points[1]][0])
b2 = ltby - k2 * ltbx
# print(ltbx0, (ltby0 - b1)/k1, (ltby0 - b2)/k2)
if ltbx0 > max((ltby0 - b1) / k1, (ltby0 - b2) / k2):
res_index[0], res_index[d2] = ltb_idx1, ltb_idx2
elif ltbx0 < min((ltby0 - b1) / k1, (ltby0 - b2) / k2):
res_index[0], res_index[d2] = ltb_idx2, ltb_idx1
else:
raise Exception("凹四边形?")
# 其它点
if self.points[right_points[0]][1] == self.points[right_points[1]][1]:
if 1 == d2:
res_index[res_index.index(None)] = self.right_index[0]
res_index[res_index.index(None)] = self.right_index[1]
else:
res_index[res_index.index(None)] = self.right_index[1]
res_index[res_index.index(None)] = self.right_index[0]
elif self.points[right_points[0]][0] == self.points[right_points[1]][0]:
if 1 == d2:
res_index[res_index.index(None)] = self.bot_index[1]
res_index[res_index.index(None)] = self.bot_index[0]
else:
res_index[res_index.index(None)] = self.top_index[0]
res_index[res_index.index(None)] = self.top_index[1]
else:
if 1 == d2:
rtb_idx1 = self.bot_index[0]
rtb_idx2 = self.bot_index[1]
else:
rtb_idx1 = self.top_index[1]
rtb_idx2 = self.top_index[0]
rtbx, rtby = self.points[rtb_idx1]
rtbx0, rtby0 = self.points[rtb_idx2]
k1 = (rtby - self.points[left_points[0]][1]) / (rtbx - self.points[left_points[0]][0])
b1 = rtby - k1 * rtbx
k2 = (rtby - self.points[left_points[1]][1]) / (rtbx - self.points[left_points[1]][0])
b2 = rtby - k2 * rtbx
# print(rtbx0, (rtby0 - b1)/k1, (rtby0 - b2)/k2)
if rtbx0 > max((rtby0 - b1) / k1, (rtby0 - b2) / k2):
if 1 == d2:
res_index[res_index.index(None)] = rtb_idx2
res_index[res_index.index(None)] = rtb_idx1
else:
res_index[res_index.index(None)] = rtb_idx1
res_index[res_index.index(None)] = rtb_idx2
elif rtbx0 < min((rtby0 - b1) / k1, (rtby0 - b2) / k2):
if 1 == d2:
res_index[res_index.index(None)] = rtb_idx1
res_index[res_index.index(None)] = rtb_idx2
else:
res_index[res_index.index(None)] = rtb_idx2
res_index[res_index.index(None)] = rtb_idx1
else:
raise Exception("凹四边形?")
if 2 == len(self.left_top_points):
test(self.left_top_points,
self.right_bot_points,
self.left_index,
self.top_index,
self.right_index,
self.bot_index,
d2=1)
elif 2 == len(self.left_bot_points):
test(self.left_bot_points,
self.right_top_points,
self.left_index,
self.top_index,
self.right_index,
self.bot_index,
d2=-1)
else:
return
if None not in res_index:
self.res = [
self.points[res_index[0]], self.points[res_index[1]], self.points[res_index[2]],
self.points[res_index[3]]
]
if __name__ == '__main__':
src_data = src_data = [[600, 100], [100, 300], [200, 600], [500, 300]]
datas = [[src_data[0], src_data[1], src_data[2], src_data[3]], [src_data[1], src_data[2], src_data[3], src_data[0]],
[src_data[1], src_data[2], src_data[0], src_data[3]], [src_data[2], src_data[0], src_data[1], src_data[3]],
[src_data[2], src_data[3], src_data[0], src_data[1]], [src_data[3], src_data[2], src_data[1], src_data[0]]]
import cv2
import numpy as np
def showImg(title, img, max_H=800, max_W=800):
img = np.array(img, dtype=np.uint8) # .astype(np.uint8)
IMAGE_H, IMAGE_W = img.shape[:2]
if IMAGE_H > max_H or IMAGE_W > max_W:
ratio = min(max_W / IMAGE_W, max_H / IMAGE_H)
IMAGE_H = int(IMAGE_H * ratio)
IMAGE_W = int(IMAGE_W * ratio)
cv2.namedWindow(title, 0)
cv2.resizeWindow(title, IMAGE_W, IMAGE_H)
cv2.imshow(title, img)
cv2.waitKey(0)
cv2.destroyAllWindows()
pts = np.array(src_data, dtype=np.int32)
W, H = pts.max(axis=0)
base_img = np.zeros((int(H * 1.1), int(W * 1.1)), dtype=np.uint8)
img = base_img.copy()
cv2.polylines(img, np.array([src_data], dtype=np.int32), True, 255, 1)
showImg("aaa", img)
for data in datas:
img = base_img.copy()
pts = QuadrilateralVertexSort(data).res
cv2.polylines(img, np.array([pts], dtype=np.int32), True, 255, 1)
for i, p in enumerate(pts):
cv2.putText(img, f"{i}", (int(p[0]), int(p[1])), cv2.FONT_HERSHEY_COMPLEX_SMALL, 2, 255, 1)
showImg("aaa", img)
输出结果使用时可二次排序,比如根据边长
points = QuadrilateralVertexSort(points).res
x1, y1 = points[0]
x2, y2 = points[1]
x3, y3 = points[2]
x4, y4 = points[3]
length_12 = (x2 - x1)**2 + (y2 - y1)**2
length_41 = (x1 - x4)**2 + (y1 - y4)**2
length_23 = (x2 - x3)**2 + (y2 - y3)**2
length_34 = (x4 - x3)**2 + (y4 - y3)**2
if length_12 + length_34 < length_23 + length_41:
points = [points[1], points[2], points[3], points[0]]
强制左上优先起始点?
x1, y1 = points[0]
x2, y2 = points[1]
if abs(y1-y2) > abs(x1-x2):
points = [points[1], points[2], points[3], points[0]]