一、 局部处理连接边缘
在实际应用中,由于噪声、光照等原因引起的边缘断裂,使边缘检测的结果并不是完全的、完整的边缘,通常要通过边缘连接算法,将边缘像素组合为有意义的边缘或区域边界。
边缘连接方可以分为局部处理方法和全局处理方法。边缘连接的局部处理方法,是分析每个边缘像素点的邻域,根据预定义的准则将所有相似的点连接起来,形成同类像素的边缘。
在局部分析中,主要基于梯度向量的幅值和方向进行边缘像素的相似性判断。如果检测所有像素点的邻域,计算量很大。
二、一种简化的边缘连接局部处理方法
(1)计算输入图像 f(x,y) 的梯度向量的幅值M(x,y) 和方向 α(x,y);
(2)二值化处理:

式中
(3)对二值图像 g,逐行扫描并填充水平间隙。
(4)对二值图像 g,逐列扫描并填充垂直间隙。编程时可以将 g 转置后,再做一次逐行扫描水平填充来实现。
在必要时,还可以对二者图像 g 进一步在其它任何方向上扫描并填充间隙。
三、例程
- 11.10:边缘连接的局部处理简化算法
import cv2
import numpy as np
from matplotlib import pyplot as plt
# 11.10 边缘连接的局部处理简化算法
img = cv2.imread(r"E:/OpenCV/building.jpg", 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_的博客:
https://blog.csdn.net/youcans/article/details/124158416