I'm trying to apply the Sobel operator to a simple binary image, but the resulting gradient is flipped (when comparing to the output of scipy's signal.convolve2d
function.
from scipy import signal
import numpy as np
import matplotlib.pyplot as plt
def sobelx_homemade(arr, kx):
offset = 1
sx = np.zeros(arr.shape)
for y in range(offset, arr.shape[0] - offset):
for x in range(offset, arr.shape[1] - offset):
rstart, rend = y-offset, y+offset+1
cstart, cend = x-offset, x+offset+1
w = arr[rstart:rend, cstart:cend]
Ix = kx * w
sx[y, x] = Ix.sum()
return sx
A = np.array([[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0],
[0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0],
[0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0],
[0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0],
[0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0],
[0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]])
kx = np.array([
[-1, 0, 1],
[-2, 0, 2],
[-1, 0, 1]
], dtype=np.float)
ky = np.array([
[1, 2, 1],
[0, 0, 0],
[-1, -2, -1]
], dtype = np.float)
Gx = signal.convolve2d(A, kx, boundary='symm', mode='same')
Gy = signal.convolve2d(A, ky, boundary='symm', mode='same')
# calculate homemade sobel x gradient
myGx = sobelx_homemade(A, kx)
plt.subplot(131)
plt.title("Original")
plt.imshow(A, cmap="gray")
plt.subplot(132)
plt.title("Gx")
plt.imshow(Gx, cmap="gray")
plt.subplot(133)
plt.title("My Gx")
plt.imshow(myGx, cmap="gray")
I expect the images labeled "Gx" and "My Gx" to be identical.
So, it turns out that a true convolution flips the kernel/filter matrix, which explains the flipped result.
This video from Andrew Ng, explains the differences between textbook convolution and cross-correlation commonly used in machine learning style image processing: https://youtu.be/tQYZaDn_kSg?t=308