最小外接多边形

目的:求得无序点集的最小外接多边形

  1. cv.approxPolyDP该函数输入的点击为有序点集才能得到外接多边形;
  2. 本文得到的mask可作为分割标签。

算法详解

  1. 找到一个边界点:xmax,xmin, ymax,ymin都可以
  2. 找第二个边界点,例如:1步骤中找到ymin后,遍历所有点,寻找到一点,使这点与ymin的线段与水平的夹角最小;
  3. 针对上两个边界点AB,找下一个边界点C 使脚ABC最大,接近180度;可以使用余弦定理
  4. 当找到的边界点为最初的ymin时,结束查找,把以上边界点按次序导出

代码

import math
import cv2
import numpy as np

poly = []
def compute_theta(cor1, cor2, cor3, cor4):
    '''
    cor: [x,y], 计算向量 cor1->cor2和cor3->cor4的夹角
    '''
    
    a1_x = cor2[0] - cor1[0]
    a1_y = cor2[1] - cor1[1] 
    a2_x = cor4[0] - cor3[0]
    a2_y = cor4[1] - cor3[1] 
    c_theta = (a1_x * a2_x + a1_y * a2_y) / (math.sqrt(a1_x * a1_x + a1_y * a1_y) * math.sqrt(a2_x * a2_x + a2_y * a2_y))
    theta = math.acos(c_theta) * 180 / math.pi
    
    return theta

# 返回点集最上面的两个点,作为开始
def get_start_pts(lines):
    
    min_value = 9999
    for pt in lines:
        if pt[1] < min_value:
            min_value = pt[1]
            startp1 = pt
            
    min_value = 9999
    for pt in lines:
        if pt[1] < min_value and pt[1]!=startp1[1]:
            min_value = pt[1]
            startp2 = pt
    poly.append(startp1)
    poly.append(startp2)
    return startp1,startp2  
# 迭代求取角度最大的点
def get_polygon(lines,pt1,pt2):
    if len(poly) > 1 and poly[0][0] == poly[-1][0] and poly[0][1] == poly[-1][1]:
        return
    
    max_theta = 0
    next_pt = []
    for pt in lines:
        if (pt[0] == pt1[0] and pt[1] == pt1[1]) or (pt[0] == pt2[0] and pt[1] == pt2[1]): # 排除送进来的两个点
            continue
        theta = compute_theta(pt2,pt1,pt2,pt)
        if theta > max_theta:
            max_theta = theta
            next_pt = pt
    poly.append(next_pt)
    get_polygon(lines,pt2,next_pt)
    return 

img = cv2.imread('court-detection/input/0000000001.jpg')
mask = np.zeros_like(img)
f = open('court-detection/input/0000000001.txt') # 图片中的直线,起点终点
files = f.read().splitlines()
lines = [] # 无序点集
for i in files:
    x1 = int(i.split(',')[0])
    y1 = int(i.split(',')[1])
    x2 = int(i.split(',')[2])
    y2 = int(i.split(',')[3])
    lines.append([x1,y1])
    lines.append([x2,y2])
    

p1,p2 = get_start_pts(lines)
get_polygon(lines,p1,p2)
cv2.fillConvexPoly(mask, np.array(poly,dtype=np.int32), (1,1,1))
mask = (mask[...,0])[...,None]
cv2.imshow('w',mask*255)
cv2.waitKey(0)
cv2.imshow('w',img*mask)
cv2.waitKey(0)

结果展示

原图:
最小外接多边形_第1张图片
mask:
最小外接多边形_第2张图片
结果:
最小外接多边形_第3张图片
最后,代码图片txt在我的百度云盘,有用的话希望读者点个赞收藏一下哦:
链接: https://pan.baidu.com/s/1cfffEwZCOy8uTZ5wMAiwsA 提取码: cwqp

你可能感兴趣的