圆环半径计算(canny算法)

本文介绍了在使用Canny算法检测圆环边缘时,如何处理睫毛对结果的影响,通过轮廓提取、边界选择和连通域分析,逐步提高精度,最终实现从内到外找到第二圈圆环的精确边界线计算。

圆环半径计算(canny算法)

前言

使用canny算法,从内到外找到第二个圆环外边缘(红色曲线)。

在这里插入图片描述

一、难点

1.如何去除睫毛的影响
2.精度控制在0.1个像素点

二、算法步骤

1.先使用canny算法检测边界

image_path = os.path.join(input_folder, image_file)
image = cv2.imread(image_path, cv2.IMREAD_COLOR)
# 使用Canny边缘检测
edges = cv2.Canny(cv2.cvtColor(image, cv2.COLOR_BGR2GRAY), lower_threshold, upper_threshold, 3, L2gradient=True)
# edges = canny_edge(crop_center(image),lower_threshold=75, upper_threshold=150)
# 截取中心区域
edges = crop_center(edges)

edges图像如下:
在这里插入图片描述
可以看到由于睫毛的遮挡,canny分割的边界并不准确。为了解决这个问题,首先,我们需要将轮廓线的坐标点都提取出来,以此来选取所需的边界并确定圆环圆心,代码如下:

 # 轮廓提取
 contours, hierarchy = cv2.findContours(edges, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)

 len_min = 200
 min_idx = 0
 for i in range(len(contours)):
     if hierarchy[0][i][3] == -1 or contours[i].shape[0]<50:  # 没有父级轮廓,即低级轮廓
         continue
     if contours[i].shape[0]<len_min:
         len_min = contours[i].shape[0]
         min_idx = i
 x = int((np.min(contours[min_idx][:,0,0]) + np.max(contours[min_idx][:,0,0]))/2)
 y = int((np.min(contours[min_idx][:,0,1]) + np.max(contours[min_idx][:,0,1]))/2)
 cv2.circle(image, (x,y), 1, (0, 0, 255), 2)

这里cv2.findContours(edges, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)中使用cv2.RETR_TREE通过层级关系可以去除外面几条边界,同时通过限制contours的长度去除较短的边界,然后比较contours的长度,找到最内侧的边界线计算圆心。

2.提取出所需的边界线

我们需要提取由内到外的第四条边界线。
代码如下:

rays = create_rays((x,y))
circle_list = []
for i in range(len(rays)):
    sorted_pixels = find_intersection_points(edges,rays[i][0],rays[i][1])
    if len(sorted_pixels) < 4: continue
    circle_list.append(sorted_pixels[3])
connectedList = connectedComponents(edges)
idx,result_lists = find_list_with_most_coordinates(circle_list, connectedList)

其中create_rays根据圆心每隔45度创建一条线段,一共生成八条线段,正常情况大部分线段会与第四条边界线有交点,并且该点排在sorted_pixels 的第四个位置。然后通过connectedComponents连通域分析将所有曲线坐标点都提取出来,接着通过find_list_with_most_coordinates将connectedList 中包含circle_list最多的点提取出来,所得到的
result_lists 即为第四条边界线。结果如下:
在这里插入图片描述
分割的结果仍存在问题,有很大一部分未被睫毛遮挡的部分边界并未提取出来。

3.提取出完整边界线

average_radius, center_point = fit_circle_least_distance(result_lists)
resltlist = calculate_average_distance(connectedList,idx,center_point[0],center_point[1],threshold=5)
result_lists.extend(resltlist)
for i in range(10):
    result_lists,std_distance = fit_circle_with_outliers(result_lists, threshold=2,threshold_std_distance=0.4)
    if std_distance<0.4:
        break
average_radius, center_point = fit_circle_least_distance(result_lists)

首先通过最小二乘法找到上面提取出的曲线的半径和中心点,然后通过计算connectedList中的曲线与result_lists的误差比较小的曲线即为所需要补充的曲线,接着通过fit_circle_with_outliers不断去除离群点直到整体误差小于某个范围,最后结果即为所需的曲线。
在这里插入图片描述

评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值