Search code examples
pythonmatplotlibscikit-image

Linear FIlter in Python not working as expected


I'm trying to implement a linear filter that makes the difference between the mean of the 3 pixels above the current pixel. What am I doing wrong?

import numpy as np
from skimage import io,color
import matplotlib.pyplot as plt

# Image loading
img = io.imread('lena_256.jpg')
img = color.rgb2gray(img)*255
plt.figure(),plt.imshow(img,cmap='gray')

img_f1 = img.copy()
size = img.shape


 kernel = np.vstack((np.ones(3),np.zeros(3),-np.ones(3)))
 kernel/=3
for i in range(size[0]-2):
    for j in range(size[1]-2):
        # define the neighborhood - the current pixel will be at line=i+1 and column=j+1
        V = img[i:i+3, j:j+3]
        # multiply each pixel in the neighborhood with the weight in the kernel
        V = V * kernel
        # make the sum of the results and put it in the current pixel
        img_f1[i+1,j+1] = np.sum(V)

# Visualize the result
plt.figure(),plt.imshow(img_f1,cmap='gray', vmin = 0, vmax = 255 )

Solution

  • I think you just have a problem on the definition of your kernel. With the current kernel definition you are just replacing a pixel by the average intensity value in a 3x3 window centered on the pixel. I believe this is the kernel you want:

    kernel = np.vstack((np.ones(3),np.zeros(3),-np.ones(3)))
    kernel/=3
    print(kernel)
    
    [[ 0.33333333  0.33333333  0.33333333]
     [ 0.          0.          0.        ]
     [-0.33333333 -0.33333333 -0.33333333]]
    

    Be aware though that this kernel will always make the subtraction of the mean above to the mean below, which could result in negative pixel intensities. So when you plot your image, setting vmin = 0 will make the pixels with negative intensity to appear black. At this point it depends on what you want exactly, you can compare this resulting three plots to decide:

    # crop negative img intensities to 0
    plt.imshow(img_f1, cmap='gray', vmin = 0, vmax = 255) 
    
    # absolute value of image intensities
    plt.imshow(abs(img_f1), cmap='gray', vmin = 0, vmax = 255) 
    
    # let imshow normalize the data on its own
    plt.imshow(img_f1, cmap='gray')
    
    # set minimum and maximum intensity values to the extreme values that could be
    # generated by the filtering operation
    plt.imshow(img_f1, cmap='gray', vmin = -255, vmax = 255)