Jim421616
Jim421616

Reputation: 1536

Applying even-sized median filter in Python

My assignment is to apply a median filter of size 50x50 pixels to an image. I know how to apply the filter, but how can I specify the size of the filter when it is even? My code so far is below.

import matplotlib.pyplot as plt
from astropy.io import fits
import scipy.signal as sg

#   Open data files
hdulist = fits.open('xbulge-w1.fits')
w1data = hdulist[0].data

hdulist2 = fits.open('xbulge-w2.fits')
w2data = hdulist2[0].data

#   Apply median filter to each image
w1_med = sg.medfilt(w1data)
w2_med = sg.medfilt(w2data)

#   Set maximum sampled galactic lat (b) and long (l)
l_max = 15
b_max = 15

#   Plot median filtered images, rescaled to galactic coordinates
plt.subplot2grid((2,1), (0,0))
plt.imshow(w1_med, origin='lower',
           extent=[l_max, -l_max, -b_max, b_max],
           cmap = 'gray')
plt.title('W1 median filter')

plt.subplot2grid((2, 1), (1,0))
plt.imshow(w2_med, origin='lower',
           extent=[l_max, -l_max, -b_max, b_max],
           cmap = 'gray')
plt.title('W2 median filter')

plt.tight_layout()
plt.show()

Upvotes: 0

Views: 5732

Answers (3)

aless80
aless80

Reputation: 3332

[EDIT] Sorry for the misunderstanding in my previous answer. Median filtering is a noise suppression technique. The result depends on the kernel dimension, which is typically a "small" odd number e.g. 3,5,7. The kernel size will give the dimension on which median gets applied. For example, with a square kernel of size 3, the algorithm carries out the operation depicted in the figure below.

enter image description here

So I would suggest to just try a few different kernels (e.g. 3, 5) independently on your figure size (well, almost). Then pick the one that yields the best result. This will depend on your figures.

sg.medfilt(w1data,kernel_size=5)

In addition I see this definition for medfilt:

Signature: sg.medfilt(volume, kernel_size=None)
Docstring:
Perform a median filter on an N-dimensional array.

Apply a median filter to the input array using a local window-size given by kernel_size. The array will automatically be zero-padded.

Parameters
----------
volume : array_like
    An N-dimensional input array.
kernel_size : array_like, optional
    A scalar or an N-length list giving the size of the median filter
    window in each dimension.  Elements of `kernel_size` should be odd.
    If `kernel_size` is a scalar, then this scalar is used as the size in
    each dimension. Default size is 3 for each dimension.
    ....

Notice the "The array will automatically be zero-padded". This is needed to fix your even sized images

Upvotes: 1

AGN Gazer
AGN Gazer

Reputation: 8378

The key in your question is the even-sizedness of the kernel. scipy.signal.medfilt constrains you to use odd-sized kernels. Do a search on the Web and you will find plenty of information as to why kernels are usually odd-sized. The main reason, I believe, is centering.

For example, if you convolve an image containing a Gaussian with an even-sized Gaussian kernel - you will end-up with an image with a Gaussian with a shifted (by 1/2 pixels) center compared to the original, not convolved, image.

With regard to the median filter specifically, there is an additional reason why one may consider odd-sized kernels: having an odd number of pixels produces a unique median while having an even number of pixels would require deciding, e.g., on which pixel to use as the result: pixel[int(size/2)], pixel[int(size/2)+1], or the average of the two.

You cannot use scipy.signal.medfilt for even-sezed kernels. However, you can always write a loop to go through all pixels of the input image and extract an even-sized window "around" each pixel, and then compute the median of the pixels in that window. I quote "around" because it is not clear (=unique) how to center that window on a pixel: it will be up to you to make a decision.

Upvotes: 0

Max Power
Max Power

Reputation: 8954

Based on the docs I think all you need to change is

#   Apply median filter to each image
w1_med = sg.medfilt(w1data)
w2_med = sg.medfilt(w2data)

to

#   Apply median filter to each image
w1_med = sg.medfilt(w1data, kernel_size=50)
w2_med = sg.medfilt(w2data, kernel_size=50)

...does that work for you?

Upvotes: 0

Related Questions