I'm trying to build a Sobel mask on a Gaussian noisy greyscale image using Python but it looks like it's not detecting edges as it should be and I don't understand what I'm doing wrong. This is my code where I've added all the variable declaration:
# Import numpy, skimage and matplotlib
import numpy as np
from skimage import io,color
import matplotlib.pyplot as plt
# Image loading
img = io.imread('lena.png')
plt.figure(),plt.imshow(img),plt.title("Initial image")
# Grayscale conversion
img = color.rgb2gray(img)
# Displaying the grayscale image
# The grayscale image has values between 0 (black) and 1 (white).
plt.figure(),plt.imshow(img,cmap='gray', vmin = 0, vmax = 1),plt.title("Greyscale image")
# convert the image to values between 0 (black) and 255 (white)
img = img*255
# generate the gaussian noise with mean = 0 and a given standard deviation
N = np.random.normal(0,30,img.shape)
# add the noise to the image
img_n = img + N
# Show image with the Gaussian Noise
plt.figure(),plt.imshow(img_n,cmap='gray', vmin = 0, vmax = 255),plt.title("Image with Gaussian Noise")
size = img.shape
# define the 4 masks for the 4 differences between the pixels
mask_x = np.array([[0, 0, 0], [-1, 0, 1], [0, 0, 0] ])
mask_y = np.array([[0, -1, 0], [0, 0, 0], [0, 1, 0] ])
mask_45 = np.array([[-1, 0, 0], [0, 0, 0], [0, 0, 1] ])
mask_135 = np.array([[0, 0, -1], [0, 0, 0], [1, 0, 0] ])
# for each pixel in the image
for i in range(size[0]-2):
for j in range(size[1]-2):
# compute the result of the 4 differences (with the 4 linear filters)
V = img[i:i+3,j:j+3]
Vx = V * mask_x
img_fx[i+1,j+1] = np.sum(Vx)
Vy = V * mask_y
img_fy[i+1,j+1] = np.sum(Vy)
V45 = V * mask_45
img_f45[i+1,j+1] = np.sum(V45)
V135 = V * mask_135
img_f135[i+1,j+1] = np.sum(V135)
# take the one that gives the maximum absolute difference
compass[i+1,j+1] = max([abs(img_fx[i+1,j+1]), abs(img_fy[i+1,j+1]), abs(img_f45[i+1,j+1]), abs(img_f135[i+1,j+1]) ])
# visualize all of them
plt.figure(),plt.imshow(img,cmap='gray')
plt.figure(),plt.imshow(img_fx,cmap='gray', vmin = -255, vmax = 255)
plt.figure(),plt.imshow(img_fy,cmap='gray', vmin = -255, vmax = 255)
plt.figure(),plt.imshow(img_f45,cmap='gray', vmin = -255, vmax = 255)
plt.figure(),plt.imshow(img_f135,cmap='gray', vmin = -255, vmax = 255)
plt.figure(),plt.imshow(compass,cmap='gray', vmin = 0, vmax = 255)
I mean, I don't know exactly where your code is going wrong, and this is not a Sobel filter, but you're making it way more complicated than it needs to be. You should use scipy.ndimage.correlate
:
import numpy as np
from scipy import ndimage as ndi
kernels = [
np.array([[-1, 0, 1]]),
np.array([[-1], [0], [1]]),
np.array([[-1, 0, 0], [0, 0, 0], [0, 0, 1]]),
np.array([[0, 0, -1], [0, 0, 0], [1, 0, 0]]),
]
filtered = [
ndi.correlate(img, kernel)
for kernel in kernels
]
compass = np.max(np.abs(filtered), axis=0)