我尝试实现一个 Sobel Edge 检测器,如下所示:
def sobel(img):
img = cv2.GaussianBlur(img, (5, 5), 0)
filter_x = np.array([
[-1, 0, 1],
[-2, 0, 2],
[-1, 0, 1]
])
filter_y = np.array([
[-1, -2, -1],
[0, 0, 0],
[1, 2, 1]
])
S_x = cv2.filter2D(img, -1, filter_x)
S_y = cv2.filter2D(img, -1, filter_y)
# S_x = cv2.convertScaleAbs(S_x)
# S_y = cv2.convertScaleAbs(S_y)
# grad = S_x * 0.5 + S_y * 0.5
grad = np.sqrt(S_x ** 2 + S_y ** 2)
grad = np.clip(grad, 0, 255)
return grad.astype(np.uint8)
img_gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
plt.figure(figsize=(10, 10))
edge = sobel(img_gray)
plt.imshow(edge, cmap='gray')
发生这种情况是因为我正在计算 x 和 y 方向上梯度的 L2 幅度。然而,当我将策略切换为使用 L1 规范(即使用 `S_x * 0.5 + S_y * 0.5)时,我得到的输出噪音要小得多:
为什么会发生这种情况?根据各种消息来源,这两种组合都被使用,但我想了解为什么 L2 变体如此嘈杂,以及如何避免它。
谢谢!
你观察到,使用 L2 范数计算梯度幅值时 Sobel 边缘检测结果比使用 L1 范数噪声更大,这是因为这两种范数对异常值的敏感度不同。
L2 范数(或欧几里得范数) 计算平方梯度的平方根:(Gx² + Gy²)^(1/2)。它对大值给予更多权重,这使得它对噪声或图像中存在的急剧变化更加敏感。结果,噪声像素的梯度幅值会更高,导致边缘图中出现更多噪声。
L1 范数(或曼哈顿范数) 计算水平和垂直梯度的绝对值之和:|Gx| + |Gy|。它对异常值不太敏感,因为不涉及平方。因此,与 L2 范数相比,噪声像素对梯度幅值的影响较小,从而产生更平滑、噪声更小的边缘图。
那么,为什么还要使用 L2 范数呢?
尽管 L2 范数对噪声更敏感,但它也能够检测到更微弱的边缘和更高的各向同性。各向同性是指算子对所有方向上的边缘具有同等响应的能力。由于 L2 范数考虑了梯度的幅值和方向,因此它在检测具有不同方向的边缘方面做得更好。
如何减少 L2 范数中的噪声?
-
预先平滑: 正如你所做的那样,在应用 Sobel 算子之前,通过使用高斯模糊或中值滤波等技术对图像进行平滑处理,可以减少噪声。平滑有助于抑制噪声像素,使 Sobel 算子不那么容易受到这些像素的影响。
-
阈值调整: 应用 Sobel 算子后,可以使用阈值来区分边缘像素和非边缘像素。通过调整阈值,你可以控制边缘图的灵敏度和噪声量。较高的阈值将导致检测到的边缘较少,但也减少了噪声。
-
使用不同的梯度组合技术: 除了 L1 和 L2 范数之外,还可以使用其他梯度组合技术,例如 Canny 边缘检测器,它使用滞后阈值和非最大值抑制来生成更清晰、更连续的边缘。
总之,L1 和 L2 范数都有其优缺点。L1 范数对噪声不太敏感,而 L2 范数可以检测到更微弱的边缘并提供更好的各向同性。最佳选择取决于特定的应用和所需的噪声水平与边缘检测灵敏度之间的权衡。
标签:python,numpy,opencv,image-processing From: 78831701