jupyter-notebookscikit-imagenoisesobel

Implementation of Sobel mask filter failed


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)

Solution

  • 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)