前段时间我将网上最大内切圆算法进行了代码的整理,原先博主上传的代码稍微有点乱,可能也是它自己使用,大家可以看这篇整理好的:最大内切圆算法计算裂缝宽度。
一个圆与给定的多边形或曲线的每一条边或曲线都相切的圆。而我们就是需要计算的是给定图像的轮廓的最大内切圆,也就是与轮廓的每一条边都相切的圆中直径最大的圆。这样直径就是我们的轮廓的宽度了。
既然要求轮廓的内接圆,从圆的特点来说,想要唯一的确定一个圆,就是要知道它的圆心和半径。好的,那现在的问题就从求取轮廓的内接圆,巧妙地转变成求取某个点和一个多边形的距离和关系。
在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}
现在我们就能知道两条裂缝对应的最大内切圆直径,即裂缝的宽度。
并且从时间角度来看:
从计算的直径上来看:
这里的实现比较简单,只是嵌套的循环比较多,但能存储每条裂缝对应的宽度。
- # 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)