这里依然是应用在图像分割的场景,在对路面病害中的裂缝进行检测时,通过UNet++图像分割模型我们可以得到裂缝的标注图像,如下图所示。

针对裂缝的图像分割图像,我们仍需进一步的进行图像处理操作,计算裂缝的宽度。这里我采用的是轮廓内切圆算法,通过opencv计算裂缝轮廓中最大内切圆,以此来求得最大的裂缝宽度。代码如下:

import cv2
import math
import random
import numpy as np
from numpy.ma import cos, sin
import matplotlib.pyplot as pltdef max_circle(img_path):'''计算轮廓内切圆算法Args:img_path: 输入图片路径,图片需为二值化图像Returns:'''img = cv2.imread(img_path, cv2.IMREAD_COLOR)# 灰度处理img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)# 图片二值化,缺少这一步也可以,但是图像的二值化可以使图像中数据量大为减少,从而能凸显出目标的轮廓,减小计算量ret, thresh = cv2.threshold(img_gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)# 寻找二值图像的轮廓contous, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)"""第二个参数表示轮廓的检索模式,有四种: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))==1cv2.CHAIN_APPROX_SIMPLE压缩水平方向,垂直方向,对角线方向的元素,只保留该方向的终点坐标,例如一个矩形轮廓只需4个点来保存轮廓信息cv2.CHAIN_APPROX_TC89_L1,CV_CHAIN_APPROX_TC89_KCOS使用teh-Chinl chain 近似算法"""expansion_circle_list = []   # 所有裂缝最大内切圆半径和圆心列表# 可能一张图片中存在多条裂缝,对每一条裂缝进行循环计算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])# 最小矩形中最小的边除2,裂缝内切圆的半径最大不超过此距离upper_r = min(right_x - left_x, down_y - up_y) / 2# 定义相切二分精度precisionprecision = math.sqrt((right_x - left_x) ** 2 + (down_y - up_y) ** 2) / (2 ** 13)# 构造包含轮廓的矩形的所有像素点Nx = 2 ** 8Ny = 2 ** 8pixel_X = np.linspace(left_x, right_x, Nx)pixel_Y = np.linspace(up_y, down_y, Ny)# 从坐标向量中生成网格点坐标矩阵xx, yy = np.meshgrid(pixel_X, pixel_Y)# 筛选出轮廓内所有像素点in_list = []for i in range(pixel_X.shape[0]):for j in range(pixel_X.shape[0]):# cv2.pointPolygonTest可查找图像中的点与轮廓之间的最短距离.当点在轮廓外时返回负值,当点在内部时返回正值,如果点在轮廓上则返回零# 统计裂缝内的所有点的坐标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)# 随机搜索百分之一的像素点提高内切圆半径下限N = len(in_point)rand_index = random.sample(range(N), N // 100)rand_index.sort()radius = 0big_r = upper_r   # 裂缝内切圆的半径最大不超过此距离center = Nonefor 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 = trcenter = (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 = trcenter = (in_point[id][0], in_point[id][1])  # 只有半径变大才允许位置变更,否则保持之前位置不变expansion_circle_list.append([radius, center])   # 保存每条裂缝最大内切圆的半径和圆心# 输出裂缝的最大宽度print('裂缝宽度:', round(radius * 2, 2))print('---------------')expansion_circle_radius_list = [i[0] for i in expansion_circle_list]   # 每条裂缝最大内切圆半径列表max_radius = max(expansion_circle_radius_list)max_center = expansion_circle_list[expansion_circle_radius_list.index(max_radius)][1]print('最大宽度:', round(max_radius * 2, 2))# 绘制轮廓cv2.drawContours(img_original, contous, -1, (0, 0, 255), -1)# 绘制裂缝轮廓最大内切圆for expansion_circle in expansion_circle_list:radius_s = expansion_circle[0]center_s = expansion_circle[1]if radius_s == max_radius:   # 最大内切圆,用蓝色标注cv2.circle(img_original, (int(max_center[0]), int(max_center[1])), int(max_radius), (255, 0, 0), 2)else:   # 其他内切圆,用青色标注cv2.circle(img_original, (int(center_s[0]), int(center_s[1])), int(radius_s), (255, 245, 0), 2)cv2.imshow('Inscribed_circle', img_original)cv2.imwrite('inference/output/Inscribed_circle.png', img_original)cv2.waitKey(0)cv2.destroyAllWindows()# # matplotlib效果测试# plot_x = np.linspace(0, 2 * math.pi, 100)# circle_X = max_center[0] + max_radius * cos(plot_x)# circle_Y = max_center[1] + max_radius * sin(plot_x)# 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):'''计算轮廓内最大内切圆的半径Args:contous: 轮廓像素点array数组pixelx: 圆心x像素坐标pixely: 圆心y像素坐标small_r: 之前所有计算所求得的内切圆的最大半径,作为下次计算时的最小半径输入,只有半径变大时才允许位置变更,否则保持之前位置不变big_r: 圆的半径最大不超过此距离precision: 相切二分精度,采用二分法寻找最大半径Returns: 轮廓内切圆的半径'''radius = small_rL = np.linspace(0, 2 * math.pi, 360)  # 确定圆散点剖分数360, 720circle_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 0while big_r - small_r >= precision:  # 二分法寻找最大半径half_r = (small_r + big_r) / 2circle_X = pixelx + half_r * cos(L)circle_Y = pixely + half_r * sin(L)if_out = Falsefor i in range(len(circle_Y)):if cv2.pointPolygonTest(contous, (circle_X[i], circle_Y[i]), False) < 0:  # 如果圆散集有在轮廓之外的点big_r = half_rif_out = Trueif not if_out:small_r = half_rradius = small_rreturn radiusif __name__ == '__main__':img_original_path = 'inference/images/crack_test1.png'img_gray = 'inference/output/test_crack.png'img_original = cv2.imread('inference/images/crack_test1.png')max_circle(img_gray)

得到的结果如图所示,上图通过图像标注后存在4条裂缝,通过上述代码分别计算每一条裂缝的最大内切圆,其中,直径最大的内切圆标注为蓝色,其他裂缝的内切圆标注为青色。这里我们求得的最大内切圆直径即裂缝的最大宽度,但此时是像素宽度,若需计算裂缝的实际宽度,需通过距离或参照物换算出1cm对应多少像素,再根据比例关系计算裂缝的实际宽度。

基于opencv的裂缝宽度检测算法(计算轮廓最大内切圆算法)相关推荐

  1. Python基于OpenCV高空抛物检测系统[完整源码&部署教程]

    1.视频演示: [项目分享]Python基于OpenCV高空抛物检测系统[完整源码&部署教程]_哔哩哔哩_bilibili 2.图片演示: 3.算法原理: 参考该博客提出的移动侦测法,即是根据 ...

  2. python运动目标检测与跟踪_基于OpenCV的运动目标检测与跟踪

    尹俊超,刘直芳:基于 OpenCV 的运动目标检测与跟踪 2011, V ol.32, No.8 2817 0 引 言 运动目标检测跟踪技术在航空航天遥感. 生物医学. 工业 自动化生产. 军事公安目 ...

  3. opencv canny源码解析_行人检测 基于 OpenCV 的人体检测

    原文链接 行人检测 基于 OpenCV 的人体检测 - 热分享​hotdog29.com 在 2019年8月1日 上张贴 由 hotdog发表回复 行人检测 基于 OpenCV 的人体检测 我们都知道 ...

  4. pythonopencv检测行人_行人检测 基于 OpenCV 的人体检测

    原文链接行人检测 基于 OpenCV 的人体检测 - 热分享​hotdog29.com 行人检测 基于 OpenCV 的人体检测 我们都知道,无论性别,种族或种族如何,我们的身体都具有相同的基本结构. ...

  5. python行人检测_行人检测 基于 OpenCV 的人体检测

    原文链接行人检测 基于 OpenCV 的人体检测 - 热分享​hotdog29.com 行人检测 基于 OpenCV 的人体检测 我们都知道,无论性别,种族或种族如何,我们的身体都具有相同的基本结构. ...

  6. 基于opencv的人脸检测与识别(python)(1)

    基于opencv的人脸检测与识别(python语言)(1) 人脸检测和识别技术就目前而言,已经相对成熟,各类算法层出不穷,这都归功于各位奋斗在一线的大佬的努力(站在巨人的肩膀上的感觉就是爽).本文是参 ...

  7. 【零基础跑项目】20代码教你基于opencv的人脸检测

    20代码教你基于opencv的人脸检测

  8. 基于OpenCV的火焰检测(二)——RGB颜色判据

    上文跟大家分享了在做火焰检测中常用到的图像预处理方法,从这一篇博文开始,我将向大家介绍如何一步一步地检测出火焰区域.火焰提取要用 到很多判据,今天我要向大家介绍的是最简单的但是很有效的判据--RGB判 ...

  9. 基于opencv实现人脸检测

    基于opencv实现人脸检测 opencv简述 opencv是一个开源的计算机视觉库,它有着C++,Python,Java等接口,支持Windows,Linux,Mac OS,IOS 和 Androi ...

最新文章

  1. 里程碑:DTrace 切换到 GPL 许可证
  2. 奥巴马表示10天内债务谈判出结果 债务违约可能性底
  3. nginx+tomcat+resin+jdk一键自动化安装脚本(4--resin安装脚本)
  4. CentOS7防火墙firewalld和iptable的设置和使用
  5. lt form gt 在html,HTML lt;formgt; 标签的 accept
  6. 小型数据库_如果您从事“小型科学”工作,那么您是否正在利用数据存储库?
  7. Go学习笔记(一)windows下的Go 语言环境安装,并运行第一个Hello World程序
  8. leetcode第一刷_Unique Binary Search Trees
  9. python selenium在编写过程中遇到的问题记录2
  10. 电脑小手图标怎么去除_图文教你去除桌面图标箭头_消除电脑图标小箭头的方法-系统城...
  11. 微软在上海有哪些办公地点?上下班来回三小时?不止闵大荒!
  12. 免费二级域名分发企业备案域名 阿里云备案域名
  13. Intel(R) 6 Series/C200 Series Chipset Family USB Enhanced Host Controller - 1C26出现感叹号,USB无法使用
  14. 修约函数,四舍六进五单双 的修约规则,给有需要的朋友参考
  15. 单线激光雷达为什么这么火?
  16. CRM平台十点功能帮助企业提高销售营销技巧(下)
  17. bzoj2095 [Poi2010]Bridges
  18. Internet Explorer 各版本文件上传和下载限制
  19. Dayjs 时间比较
  20. 精选文章:发明专利/实用新型专利、软著申请的简介、方法、步骤之最强攻略

热门文章

  1. 【Android】Service启动、生命周期
  2. 阿里云林小平:如何实现资源高效运维及成本分析
  3. Elasticsearch之聚合分析
  4. 2016大数据企业排行榜揭示中国数据发展
  5. 鸿蒙有多大几率审核通过,鸿蒙内测申请成功,这个通过几率多大?
  6. 2009年中国信息安全领域八大预测
  7. RabbitMQ-工作模型
  8. 3-论文笔记--《Privacy-preserving and Efficient Aggregation based on Blockchain for Power Grid...》
  9. UOJ超级详细部署文档
  10. C++ 面向对象的日历(万年历)