提示:内容整理自:/gzr/ImageProcessing100Wen
CV小白从0开始学数字图像处理
43 Canny 边缘检测:第三步——滞后阈值
在这里进行 Canny 边缘检测的最后一步。
在这里我们将通过设置高阈值和低阈值来将梯度幅值二值化。
如果梯度幅值edge(x,y)大于高阈值的话,令edge(x,y)=255;如果梯度幅值edge(x,y)小于低阈值的话,令edge(x,y)=0;如果梯度幅值edge(x,y)介于高阈值和低阈值之间并且周围8邻域内有比高阈值高的像素点存在,令edge(x,y)=255;
在这里,我们使高阈值为100,低阈值为30。顺便说一句,我们只需要在查看结果时判断阈值。
上面的算法就是 Canny 边缘检测算法了。
代码如下:
1.引入库
CV2计算机视觉库
import cv2import numpy as npimport matplotlib.pyplot as plt
2.读入数据
img = cv2.imread("imori.jpg").astype(np.float32)H, W, C = img.shape
3.灰度化
gray = 0.2126 * img[..., 2] + 0.7152 * img[..., 1] + 0.0722 * img[..., 0]
4.Gaussian Filter
K_size = 5sigma = 1.4
5.补0
pad = K_size // 2gau = np.zeros((H + pad*2, W + pad*2), dtype=np.float32)#gau[pad:pad+H, pad:pad+W] = gray.copy().astype(np.float32)gau = np.pad(gray, (pad, pad), 'edge')tmp = gau.copy()
6.Kernel
K = np.zeros((K_size, K_size), dtype=np.float32)for x in range(-pad, -pad+K_size):for y in range(-pad, -pad+K_size):K[y+pad, x+pad] = np.exp( -(x**2 + y**2) / (2* (sigma**2)))K /= (sigma * np.sqrt(2 * np.pi))K /= K.sum()for y in range(H):for x in range(W):gau[pad+y, pad+x] = np.sum(K * tmp[y:y+K_size, x:x+K_size])## Sobel verticalKSV = np.array(((-1., -2., -1.), (0., 0., 0.), (1., 2., 1.)), dtype=np.float32)## Sobel horizontalKSH = np.array(((-1., 0., 1.), (-2., 0., 2.), (-1., 0., 1.)), dtype=np.float32)gau = gau[pad-1:H+pad+1, pad-1:W+pad+1]fy = np.zeros_like(gau, dtype=np.float32)fx = np.zeros_like(gau, dtype=np.float32)K_size = 3pad = K_size // 2for y in range(H):for x in range(W):fy[pad+y, pad+x] = np.sum(KSV * gau[y:y+K_size, x:x+K_size])fx[pad+y, pad+x] = np.sum(KSH * gau[y:y+K_size, x:x+K_size])fx = fx[pad:pad+H, pad:pad+W]fy = fy[pad:pad+H, pad:pad+W]# Non-maximum suppressionedge = np.sqrt(np.power(fx, 2) + np.power(fy, 2))fx[fx == 0] = 1e-5tan = np.arctan(fy / fx)## Angle quantizationangle = np.zeros_like(tan, dtype=np.uint8)angle[np.where((tan > -0.4142) & (tan <= 0.4142))] = 0angle[np.where((tan > 0.4142) & (tan < 2.4142))] = 45angle[np.where((tan >= 2.4142) | (tan <= -2.4142))] = 95angle[np.where((tan > -2.4142) & (tan <= -0.4142))] = 135for y in range(H):for x in range(W):if angle[y, x] == 0:dx1, dy1, dx2, dy2 = -1, 0, 1, 0elif angle[y, x] == 45:dx1, dy1, dx2, dy2 = -1, 1, 1, -1elif angle[y, x] == 90:dx1, dy1, dx2, dy2 = 0, -1, 0, 1elif angle[y, x] == 135:dx1, dy1, dx2, dy2 = -1, -1, 1, 1if x == 0:dx1 = max(dx1, 0)dx2 = max(dx2, 0)if x == W-1:dx1 = min(dx1, 0)dx2 = min(dx2, 0)if y == 0:dy1 = max(dy1, 0)dy2 = max(dy2, 0)if y == H-1:dy1 = min(dy1, 0)dy2 = min(dy2, 0)if max(max(edge[y, x], edge[y+dy1, x+dx1]), edge[y+dy2, x+dx2]) != edge[y, x]:edge[y, x] = 0# Histeresis thresholdHT = 100LT = 30edge[edge >= HT] = 255edge[edge <= LT] = 0_edge = np.zeros((H+2, W+2), dtype=np.float32)_edge[1:H+1, 1:W+1] = edge## 8 - Nearest neighbornn = np.array(((1., 1., 1.), (1., 0., 1.), (1., 1., 1.)), dtype=np.float32)for y in range(1, H+2):for x in range(1, W+2):if _edge[y, x] < LT or _edge[y, x] > HT:continueif np.max(_edge[y-1:y+2, x-1:x+2] * nn) >= HT:_edge[y, x] = 255else:_edge[y, x] = 0edge = _edge[1:H+1, 1:W+1]out = edge.astype(np.uint8)
7.保存结果
cv2.imwrite("out.jpg", out)cv2.imshow("result", out)cv2.waitKey(0)cv2.destroyAllWindows()