提示:内容整理自:https://github.com/gzr2017/ImageProcessing100Wen
CV小白从0开始学数字图像处理
42 Canny 边缘检测:第二步——边缘细化
在这里完成 Canny 边缘检测的第二步。
我们从在第41问中求出的边缘梯度进行非极大值抑制,来对边缘进行细化。
非极大值抑制是对除去非极大值以外的值的操作的总称(这个术语在其它的任务中也经常出现)。
在这里,我们比较我们我们所关注的地方梯度的法线方向邻接的三个像素点的梯度幅值,如果该点的梯度值不比其它两个像素大,那么这个地方的值设置为0。
也就是说,我们在注意梯度幅值edge(x,y)的时候,可以根据下式由梯度方向angle(x,y)来变换edge(x,y):
if angle(x,y) = 0
if edge(x,y), edge(x-1,y), edge(x+1,y)で edge(x,y)が最大じゃない
then edge(x,y) = 0
if angle(x,y) = 45
if edge(x,y), edge(x-1,y+1), edge(x+1,y-1)で edge(x,y)が最大じゃない
then edge(x,y) = 0
if angle(x,y) = 90
if edge(x,y), edge(x,y-1), edge(x,y+1)で edge(x,y)が最大じゃない
then edge(x,y) = 0
if angle(x,y) = 135
if edge(x,y), edge(x-1,y-1), edge(x+1,y+1)で edge(x,y)が最大じゃない
then edge(x,y) = 0
代码如下:
1.引入库
CV2计算机视觉库
import cv2
import numpy as np
import 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 = 5
sigma = 1.4
5.补0
pad = K_size // 2
gau = 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 vertical
KSV = np.array(((-1., -2., -1.), (0., 0., 0.), (1., 2., 1.)), dtype=np.float32)
## Sobel horizontal
KSH = 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 = 3
pad = K_size // 2
for 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 suppression
edge = np.sqrt(np.power(fx, 2) + np.power(fy, 2))
fx[fx == 0] = 1e-5
tan = np.arctan(fy / fx)
## Angle quantization
angle = np.zeros_like(tan, dtype=np.uint8)
angle[np.where((tan > -0.4142) & (tan <= 0.4142))] = 0
angle[np.where((tan > 0.4142) & (tan < 2.4142))] = 45
angle[np.where((tan >= 2.4142) | (tan <= -2.4142))] = 95
angle[np.where((tan > -2.4142) & (tan <= -0.4142))] = 135
for y in range(H):
for x in range(W):
if angle[y, x] == 0:
dx1, dy1, dx2, dy2 = -1, 0, 1, 0
elif angle[y, x] == 45:
dx1, dy1, dx2, dy2 = -1, 1, 1, -1
elif angle[y, x] == 90:
dx1, dy1, dx2, dy2 = 0, -1, 0, 1
elif angle[y, x] == 135:
dx1, dy1, dx2, dy2 = -1, -1, 1, 1
if 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
out = edge.astype(np.uint8)
7.保存结果
cv2.imwrite("out.jpg", out)
cv2.imshow("result", out)
cv2.waitKey(0)
cv2.destroyAllWindows()