首页 > 编程语言 >Python 实现任意多边形的最大内切圆算法_任意多边形最大内切圆算法

Python 实现任意多边形的最大内切圆算法_任意多边形最大内切圆算法

时间:2024-05-19 12:57:40浏览次数:25  
标签:多边形 point cv2 pixel 算法 radius id circle 内切圆

CSDN搬家失败,手动导出markdown后再导入博客园

参考 Matlab 计算轮廓内切圆

初衷是为了求裂缝的最大宽度

![[output/attachments/5ecf17abcb54aaa4fb35b00c3f243f32_MD5.png]]

直接上代码

import random
 
import cv2
import math
import numpy as np
from numpy.ma import cos, sin
import matplotlib.pyplot as plt
 
 
def max_circle(f):
    img = cv2.imread(f, cv2.IMREAD_COLOR)
    img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    # _, img_gray = cv2.threshold(img_gray, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
    contous, hierarchy = cv2.findContours(img_gray, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    """
    第二个参数表示轮廓的检索模式,有四种(本文介绍的都是新的cv2接口):
    cv2.RETR_EXTERNAL表示只检测外轮廓
    cv2.RETR_LIST检测的轮廓不建立等级关系
    cv2.RETR_CCOMP建立两个等级的轮廓,上面的一层为外边界,里面的一层为内孔的边界信息。如果内孔内还有一个连通物体,这个物体的边界也在顶层。
    cv2.RETR_TREE建立一个等级树结构的轮廓。

    第三个参数method为轮廓的近似办法
    cv2.CHAIN_APPROX_NONE存储所有的轮廓点,相邻的两个点的像素位置差不超过1,即max(abs(x1-x2),abs(y2-y1))==1
    cv2.CHAIN_APPROX_SIMPLE压缩水平方向,垂直方向,对角线方向的元素,只保留该方向的终点坐标,例如一个矩形轮廓只需4个点来保存轮廓信息
    cv2.CHAIN_APPROX_TC89_L1,CV_CHAIN_APPROX_TC89_KCOS使用teh-Chinl chain 近似算法
    """
    for c in contous:
        left_x = min(c[:, 0, 0])
        right_x = max(c[:, 0, 0])
        down_y = max(c[:, 0, 1])
        up_y = min(c[:, 0, 1])
        upper_r = min(right_x - left_x, down_y - up_y) / 2
        # 定义相切二分精度
        precision = math.sqrt((right_x - left_x) ** 2 + (down_y - up_y) ** 2) / (2 ** 13)
        # 构造包含轮廓的矩形的所有像素点
        Nx = 2 ** 8
        Ny = 2 ** 8
        pixel_X = np.linspace(left_x, right_x, Nx)
        pixel_Y = np.linspace(up_y, down_y, Ny)
 
        # [pixel_X, pixel_Y] = ndgrid(pixel_X, pixel_Y);
        # pixel_X = reshape(pixel_X, numel(pixel_X), 1);
        # pixel_Y = reshape(pixel_Y, numel(pixel_Y), 1);
        xx, yy = np.meshgrid(pixel_X, pixel_Y)
        # % 筛选出轮廓内所有像素点
        in_list = []
        for c in contous:
            for i in range(pixel_X.shape[0]):
                for j in range(pixel_X.shape[0]):
                    if cv2.pointPolygonTest(c, (xx[i][j], yy[i][j]), False) > 0:
                        in_list.append((xx[i][j], yy[i][j]))
        in_point = np.array(in_list)
        pixel_X = in_point[:, 0]
        pixel_Y = in_point[:, 1]
        # 随机搜索百分之一像素提高内切圆半径下限
        N = len(in_point)
        rand_index = random.sample(range(N), N // 100)
        rand_index.sort()
        radius = 0
        big_r = upper_r
        center = None
        for id in rand_index:
            tr = iterated_optimal_incircle_radius_get(c, in_point[id][0], in_point[id][1], radius, big_r, precision)
            if tr > radius:
                radius = tr
                center = (in_point[id][0], in_point[id][1]) # 只有半径变大才允许位置变更,否则保持之前位置不变
        # 循环搜索剩余像素对应内切圆半径
        loops_index = [i for i in range(N) if i not in rand_index]
        for id in loops_index:
            tr = iterated_optimal_incircle_radius_get(c, in_point[id][0], in_point[id][1], radius, big_r, precision)
            if tr > radius:
                radius = tr
                center = (in_point[id][0], in_point[id][1])    # 只有半径变大才允许位置变更,否则保持之前位置不变
        # 效果测试
        plot_x = np.linspace(0, 2 * math.pi, 100)
        circle_X = center[0] + radius * cos(plot_x)
        circle_Y = center[1] + radius * sin(plot_x)
        print(radius * 2)
        plt.figure()
        plt.imshow(img_gray)
        plt.plot(circle_X, circle_Y)
        plt.show()
 
 
def iterated_optimal_incircle_radius_get(contous, pixelx, pixely, small_r, big_r, precision):
    radius = small_r
    L = np.linspace(0, 2 * math.pi, 360)  # 确定圆散点剖分数360, 720
    circle_X = pixelx + radius * cos(L)
    circle_Y = pixely + radius * sin(L)
    for i in range(len(circle_Y)):
        if cv2.pointPolygonTest(contous, (circle_X[i], circle_Y[i]), False) < 0:    # 如果圆散集有在轮廓之外的点
            return 0
    while big_r - small_r >= precision:   # 二分法寻找最大半径
        half_r = (small_r + big_r) / 2
        circle_X = pixelx + half_r * cos(L)
        circle_Y = pixely + half_r * sin(L)
        if_out = False
        for i in range(len(circle_Y)):
            if cv2.pointPolygonTest(contous, (circle_X[i], circle_Y[i]), False) < 0:  # 如果圆散集有在轮廓之外的点
                big_r = half_r
                if_out = True
        if not if_out:
            small_r = half_r
    radius = small_r
    return radius
 
 
if __name__ == '__main__':
    max_circle('thresh_crack.png')

标签:多边形,point,cv2,pixel,算法,radius,id,circle,内切圆
From: https://www.cnblogs.com/algorithmSpace/p/18200234

相关文章

  • 手写Word2vec算法实现
    1.语料下载:https://dumps.wikimedia.org/zhwiki/latest/zhwiki-latest-pages-articles.xml.bz2【中文维基百科语料】2.语料处理(1)提取数据集的文本下载的数据集无法直接使用,需要提取出文本信息。安装python库:pipinstallnumpypipinstallscipypipinstallgensimp......
  • 二分图的最大匹配(匈牙利算法)代码
    二分图的最大匹配代码#include<bits/stdc++.h>usingnamespacestd;constintN=505,M=100005;inth[N],e[M],ne[M],idx;intmatch[N];boolst[N];intn1,n2,m;voidadd(inta,intb){e[idx]=b;//e[idx]存放的是第idx条边的终点ne[idx]=h......
  • m基于BP译码算法的LDPC编译码matlab误码率仿真,对比不同的码长
    1.算法仿真效果matlab2022a仿真结果如下:   2.算法涉及理论知识概要       低密度奇偶校验码(Low-DensityParity-Check,LDPC)是一种高效的前向纠错码,因其优越的纠错性能和近似香农限的接近程度而广泛应用于现代通信系统中。LDPC码的编译码算法众多,其中BeliefProp......
  • 代码随想录算法训练营第十一天 | 20.有效的括号 1047.删除字符串中的所有相邻 重复项
    20.有效的括号题目链接文章讲解视频讲解思路:遍历字符串,如果栈不为空,则进行匹配   如果匹配则出栈,否则入栈   如果栈为空,直接入栈   遍历结束后栈为空则说明全部匹配,否则没有全部匹配classSolution{public:boolisValid(strings){stack<cha......
  • 寻路算法 Pathfinding
    目录我该使用哪种算法?BreadthFirstSearch(BFS)Dijkstra’sAlgorithmGreedyBestFirstSearchA*Algorithm学UGUI的一般使用方法,然后在画grid,除了画热力图之外,还开始了解用于处理寻路的算法A*寻路算法是图搜索算法,所以我打算不用Unity自带的寻路组件,自己简单的实现一......
  • 代码随想录算法训练营第第11天 | 20. 有效的括号 、1047. 删除字符串中的所有相邻重
    今天的题主要是关于栈的,比较简单,一次性过20.有效的括号讲完了栈实现队列,队列实现栈,接下来就是栈的经典应用了。大家先自己思考一下有哪些不匹配的场景,在看视频我讲的都有哪些场景,落实到代码其实就容易很多了。题目链接/文章讲解/视频讲解:https://programmercarl.com/0020.......
  • 北航研究生算法期末复习整理
    课程名称:算法设计与分析参考往年题来源:TheBloodthirster/BUAA_Course_Sharing数据结构二叉树线索二叉树(ThreadedBinaryTree)利用二叉链表中空的指针域指出结点在某种遍历序列中的直接前驱或直接后继指向前驱和后继的指针称为线索实现不用栈的树深度优先遍历算法二叉查......
  • dijkstra迪杰斯特拉算法(邻接表法)
    ​算法简易过程:迪杰斯特拉算法(朴素)O(n^2)G={V,E}V:点集合E:边集合初始化时令S={某源点ear},T=V-S={其余顶点},T中顶点对应的距离(ear,Vi)值若存在,d(ear,Vi)为弧上的权值,dist【i】若不存在,d(ear,Vi)为无穷大,dist【i】循环n-1次(n个点):1、从T中选......
  • python 对于实现rsa加密算法
    importbase64importrsaclassGenerateKey(object):d="ascii"defgenerate_keys(self,bits=1024):(pubkey,privkey)=rsa.newkeys(bits)pem_pubkey=rsa.PublicKey.save_pkcs1(pubkey).decode(self.d)b64_pubkey......
  • hashMap寻址算法
    hashMap寻址算法计算对象的hashCode()。再进行调用hash()方法进行二次哈希,hashcode值右移16位再异或运算,让哈希分布更为均匀。最后(capacity-1)&hash得到索引。为何HashMap的数组长度一定是2的次幂计算索引时效率更高:如果是2的n次幂可以使用位与运算代替取模。扩容时......