I've attempted to implement a Sobel Edge detector, like so:
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')
The outputs I'm getting are very noisy. For example:
This is happening because I'm computing the L2 Magnitude of the gradients in x and y directions. However, when I switch the strategy to use L1 norms (i.e, using `S_x * 0.5 + S_y * 0.5), I get a much less noisier output:
Why is this happening? According to various sources, both of these combinations are used, but I want to understand why the L2 variant is so noisy, and how I can avoid it.
Thank you!
cv2.filter2D
produces an output of the same type as the input. If the input is uint8, then the Sobel filter will overflow and underflow (negative values will show up as large positive values).
Convert the input image to a float type before filtering.