四边形顶点坐标排序十字分割法v2

尝试减少一下代码冗余,好像没减多少

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]]
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值