最小外接多边形

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

  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)

结果展示

原图:
在这里插入图片描述
mask:
在这里插入图片描述
结果:
在这里插入图片描述
最后,代码图片txt在我的百度云盘,有用的话希望读者点个赞收藏一下哦:
链接: https://pan.baidu.com/s/1cfffEwZCOy8uTZ5wMAiwsA 提取码: cwqp

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
下面是一个基于 Graham 扫描算法的寻找点云最小外接多边形的 C 程序: ```c #include <stdio.h> #include <stdlib.h> #include <math.h> typedef struct { double x, y; } Point; typedef struct { Point p; double angle; } PolarPoint; // 计算两个点之间的距离 double distance(Point p1, Point p2) { double dx = p1.x - p2.x; double dy = p1.y - p2.y; return sqrt(dx*dx + dy*dy); } // 计算极角 double angle(Point p1, Point p2) { double dx = p2.x - p1.x; double dy = p2.y - p1.y; return atan2(dy, dx); } // 比较两个极角大小 int compareAngles(const void* a, const void* b) { const PolarPoint *p1 = a, *p2 = b; if (p1->angle < p2->angle) return -1; if (p1->angle > p2->angle) return 1; return 0; } // 计算点集的凸包 void convexHull(Point* points, int n, Point** hull, int* hullSize) { // 找到最左边的点 int leftmost = 0; for (int i = 1; i < n; ++i) { if (points[i].x < points[leftmost].x) { leftmost = i; } } // 构造极角排序后的点集 PolarPoint* polarPoints = malloc(n * sizeof(PolarPoint)); for (int i = 0; i < n; ++i) { polarPoints[i].p = points[i]; polarPoints[i].angle = angle(points[leftmost], points[i]); } qsort(polarPoints, n, sizeof(PolarPoint), compareAngles); // 构造凸包 Point* stack = malloc(n * sizeof(Point)); int stackSize = 0; for (int i = 0; i < n; ++i) { while (stackSize >= 2 && angle(stack[stackSize-2], stack[stackSize-1]) > angle(stack[stackSize-2], polarPoints[i].p)) { --stackSize; } stack[stackSize++] = polarPoints[i].p; } *hull = realloc(stack, stackSize * sizeof(Point)); *hullSize = stackSize; free(polarPoints); } int main() { Point points[] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}, {0.5, 0.5}}; int n = sizeof(points) / sizeof(points[0]); Point* hull; int hullSize; convexHull(points, n, &hull, &hullSize); printf("Convex Hull:\n"); for (int i = 0; i < hullSize; ++i) { printf("(%g, %g)\n", hull[i].x, hull[i].y); } free(hull); return 0; } ``` 这个程序中,`convexHull` 函数实现了寻找凸包的算法,它首先找到最左边的点作为极角排序的基准点,然后按照极角排序所有点,再依次加入到凸包中。在加入一个新点之前,需要判断是否需要弹出之前已经加入的点,以保证凸包的性质。最后得到的凸包就是点云的最小外接多边形
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值