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

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

最大内切圆算法详解

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

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

在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张图片

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

算法对比

并且从时间角度来看:

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

从计算的直径上来看:

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

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

你可能感兴趣的:(二维检测,算法,opencv)