改进的最大内切圆算法求裂缝轮廓宽度

前段时间我将网上最大内切圆算法进行了代码的整理,原先博主上传的代码稍微有点乱,可能也是它自己使用,大家可以看这篇整理好的:最大内切圆算法计算裂缝宽度

最大内切圆算法详解

一个圆与给定的多边形或曲线的每一条边或曲线都相切的圆。而我们就是需要计算的是给定图像的轮廓的最大内切圆,也就是与轮廓的每一条边都相切的圆中直径最大的圆。这样直径就是我们的轮廓的宽度了。

既然要求轮廓的内接圆,从圆的特点来说,想要唯一的确定一个圆,就是要知道它的圆心和半径。好的,那现在的问题就从求取轮廓的内接圆,巧妙地转变成求取某个点和一个多边形的距离和关系。

在opencv中有一个函数pointPolygonTest就是能够得到某个点和某个多边形之间的关系,例如这个点是在多边形内部、外部、或者是在多边形上,还能得到该点距离多边形的像素距离。那问题其实就很好解决了。我们再使用cv2.minMaxLoc(src)来获得给定的数组中寻找最小值和最大值的位置,它的语法如下

min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(src)

其中,src是输入的数组或图像。函数会返回最小值min_val和最大值max_val,以及它们在数组中的位置最小值的位置min_loc和最大值的位置max_loc。 

讲到这里我想大家也知道怎么求轮廓的宽度了吧,即为:max_loc * 2。

详细代码

import cv2
import string
import numpy as np
import pyzjr as pz

def incircle(img, contours_arr, color=(0, 0, 255)):
    """
    轮廓最大内切圆算法,所有轮廓当中的内切圆
    """
    result = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)
    raw_dist = np.zeros(img.shape, dtype=np.float32)
    letters = list(string.ascii_uppercase)
    label = {}
    for k, contours in enumerate(contours_arr):
        for i in range(img.shape[0]):
            for j in range(img.shape[1]):
                raw_dist[i, j] = cv2.pointPolygonTest(contours, (j, i), True)
        min_val, max_val, _, max_dist_pt = cv2.minMaxLoc(raw_dist)
        label[letters[k]] = max_val * 2
        radius = int(max_val)
        cv2.circle(result, max_dist_pt, radius, color, 1, 1, 0)

    return result, label


if __name__=="__main__":
    path = r"D:\PythonProject\RoadCrack\dimension2_data\num/001.png"
    img = cv2.imread(path)
    gray_img = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
    thresh = pz.BinaryImg(img)
    contours_arr, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)

    result, label = incircle(gray_img, contours_arr)
    print("裂缝宽度:",label)
    cv2.imwrite("result.png",result)

先检测轮廓,你可以使用opencv的findContours。需要确保是ndarray数组的形式。

裂缝宽度: {'A': 5.656854152679443, 'B': 4.4721360206604}

现在我们就能知道两条裂缝对应的最大内切圆直径,即裂缝的宽度。

算法对比

并且从时间角度来看:

  • 原先的最大内切圆算法: 1.79125 sec
  • 改进后的内切圆算法:  1.05487 sec

从计算的直径上来看:

  • 原先的最大内切圆算法:13.81
  • 改进后的内切圆算法:{'A': 14.0}

这里的实现比较简单,只是嵌套的循环比较多,但能存储每条裂缝对应的宽度。


2023/10/22更新
# pip install pyzjr==1.2.5
import cv2
import pyzjr as pz
from pyzjr.augmentation import incircle

if __name__=="__main__":
    path = r"D:\PythonProject\RoadCrack\dimension2_data\num/001.png"
    img = cv2.imread(path)
    gray_img = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
    thresh = pz.BinaryImg(img)
    contours_arr, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)

    result, label = incircle(gray_img, contours_arr)
    print("裂缝宽度:",label)
    cv2.imwrite("result.png",result)
  • 3
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 18
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

夏天是冰红茶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值