【youcans 的 OpenCV 例程200篇】156. 边缘连接局部处理的简化算法
2.8 局部处理连接边缘
在实际应用中,由于噪声、光照等原因引起的边缘断裂,使边缘检测的结果并不是完全的、完整的边缘,通常要通过边缘连接算法,将边缘像素组合为有意义的边缘或区域边界。
边缘连接方可以分为局部处理方法和全局处理方法。边缘连接的局部处理方法,是分析每个边缘像素点的邻域,根据预定义的准则将所有相似的点连接起来,形成同类像素的边缘。
在局部分析中,主要基于梯度向量的幅值和方向进行边缘像素的相似性判断。如果检测所有像素点的邻域,计算量很大。
一种简化的边缘连接局部处理方法是:
(1)计算输入图像 f(x,y) 的梯度向量的幅值 M ( x , y ) M(x,y) M(x,y) 和方向 α ( x , y ) \alpha (x,y) α(x,y);
(2)二值化处理:
g
(
x
,
y
)
=
{
1
,
M
(
x
,
y
)
>
T
M
,
且
α
(
x
,
y
)
=
A
±
T
A
0
,
e
l
s
e
g(x,y) = \begin{cases} 1, \quad M(x,y) > T_M, 且 \alpha(x,y)=A \pm T_A \\ 0, \quad else \end{cases}
g(x,y)={1,M(x,y)>TM,且α(x,y)=A±TA0,else
式中
T
M
T_M
TM 是阈值,A 是规定的角度方向,
±
T
A
\pm T_A
±TA 定义方向的角度范围。
(3)对二值图像 g,逐行扫描并填充水平间隙。
(4)对二值图像 g,逐列扫描并填充垂直间隙。编程时可以将 g 转置后,再做一次逐行扫描水平填充来实现。
在必要时,还可以对二者图像 g 进一步在其它任何方向上扫描并填充间隙。
例程 11.10:边缘连接的局部处理简化算法
# 11.10 边缘连接的局部处理简化算法
img = cv2.imread("../images/Fig1027a.tif", flags=0) # flags=0 读取为灰度图像
hImg, wImg = img.shape
# (1) Sobel 计算梯度
gx = cv2.Sobel(img, cv2.CV_64F, 1, 0, ksize=3) # SobelX 水平梯度
gy = cv2.Sobel(img, cv2.CV_64F, 0, 1, ksize=3) # SobelY 垂直梯度
# magn, angle = cv2.cartToPolar(gx, gy, angleInDegrees=1) # 计算梯度幅值 mag 和角度 angle
magn = np.sqrt(np.power(gx,2) + np.power(gy,2)) # 梯度向量的幅值
gxFlat, gyFlat = gx.flatten(), gy.flatten() # 展平为一维,便于计算角度
angleFlat = np.arctan2(gy, gx) * 180 / np.pi # 梯度向量的角度,将弧度转为角度: (-180, 180)
angle = angleFlat.reshape(hImg, wImg) # youcans@xupt
angle = np.abs(angle) # 角度转为: (0, 180)
# (2) 二值化处理
TM = 0.25 * magn.max() # TM 设为最大梯度的 20%
A, Ta = 90, 30 # A=90 水平扫描, Ta = 30
edgeX = np.zeros((hImg, wImg), np.uint8) # 水平边缘
for h in range(hImg):
for w in range(wImg):
if (magn[h, w] > TM) and (A-Ta < angle[h, w] < A+Ta):
edgeX[h, w] = 255
edgeY = np.zeros((hImg, wImg), np.uint8) # 垂直边缘
for h in range(hImg):
for w in range(wImg):
if (magn[h, w] > TM) and ((angle[h,w]<Ta) | (angle[h,w]>180-Ta)):
edgeY[h, w] = 255
# (3) 水平垂直边缘合成
edgeConnect = cv2.bitwise_or(edgeX, edgeY)
# (4) 边缘细化
edge = edgeConnect.copy()
element = cv2.getStructuringElement(cv2.MORPH_CROSS, (3, 3))
edgeThin = np.zeros(edge.shape, np.uint8) # 创建空骨架图
while True:
imgOpen = cv2.morphologyEx(edge, cv2.MORPH_OPEN, element) # 开运算
subSkel = cv2.subtract(edge, imgOpen) # 获得骨架子集
edgeThin = cv2.bitwise_or(edgeThin, subSkel) # # 将删除的像素添加到骨架图
edge = cv2.erode(edge, element) # 腐蚀,用于下一次迭代
if cv2.countNonZero(edge) == 0:
break
plt.figure(figsize=(12, 7))
plt.subplot(231), plt.title("Origin"), plt.imshow(img, cmap='gray'), plt.axis('off')
plt.subplot(232), plt.title("Magnitude"), plt.imshow(np.uint8(magn), cmap='gray'), plt.axis('off')
plt.subplot(233), plt.title("Edge connect"), plt.imshow(edgeConnect, cmap='gray'), plt.axis('off')
plt.subplot(234), plt.title("Horizontal"), plt.imshow(edgeX, cmap='gray'), plt.axis('off')
plt.subplot(235), plt.title("Vertical"), plt.imshow(edgeY, cmap='gray'), plt.axis('off')
plt.subplot(236), plt.title("Edge youcans"), plt.imshow(edgeThin, cmap='gray'), plt.axis('off')
plt.tight_layout()
plt.show()
(本节完)
版权声明:
youcans@xupt 原创作品,转载必须标注原文链接:(https://blog.csdn.net/youcans/article/details/124158416)
Copyright 2022 youcans, XUPT
Crated:2022-4-10