156. 边缘连接局部处理的简化算法

9. 阈值处理与边缘检测索引

一、 局部处理连接边缘

  • 在实际应用中,由于噪声、光照等原因引起的边缘断裂,使边缘检测的结果并不是完全的、完整的边缘,通常要通过边缘连接算法,将边缘像素组合为有意义的边缘或区域边界。

  • 边缘连接方可以分为局部处理方法和全局处理方法。边缘连接的局部处理方法,是分析每个边缘像素点的邻域,根据预定义的准则将所有相似的点连接起来,形成同类像素的边缘。

  • 在局部分析中,主要基于梯度向量的幅值和方向进行边缘像素的相似性判断。如果检测所有像素点的邻域,计算量很大。

二、一种简化的边缘连接局部处理方法

(1)计算输入图像 f(x,y) 的梯度向量的幅值M(x,y) 和方向 α(x,y);

(2)二值化处理:


式中 T_M 是阈值,A 是规定的角度方向,\pm T_A定义方向的角度范围。

(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
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容