圆环半径计算(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不断去除离群点直到整体误差小于某个范围,最后结果即为所需的曲线。

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





