Faisal Qureshi
Professor
Faculty of Science
Ontario Tech University
Oshawa ON Canada
http://vclab.science.ontariotechu.ca
© Faisal Qureshi
This work is licensed under a Creative Commons Attribution-NonCommercial 4.0 International License.
import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt
im = cv.imread('data/bambi.jpg',0).astype(np.uint8)
plt.figure(figsize=(10,10))
plt.imshow(im, cmap='gray');
Lets add some salt and pepper noise
black = 10
white = 250
mask = np.empty(im.shape, np.uint8)
mask = cv.randu(mask, 0, 255)
im[mask < black] = 0
im[mask > white] = 255
plt.figure(figsize=(10,10))
plt.imshow(im, cmap='gray');
The following example supports the assertion that Gaussian smoothing fails to get rid of the salt-and-pepper noise.
half_width = 2
sigma = 1
plt.figure(figsize=(10,10))
plt.imshow(cv.GaussianBlur(im, (2*half_width+1, 2*half_width+1), sigma), cmap='gray');
This is a non-linear filtering technique. (What does that mean?) It is widely used in digital image processing and signal processing to get rid of speckle and salt-and-pepper noise while preserving edges.
From Wikipedia article on median filtering
For small to moderate levels of Gaussian noise, the median filter is demonstrably better than Gaussian blur at removing noise whilst preserving edges for a given, fixed window size. However, its performance is not that much better than Gaussian blur for high levels of noise, whereas, for speckle noise and salt-and-pepper noise (impulsive noise), it is particularly effective. Because of this, median filtering is very widely used in digital image processing.
Aside: Speckle is a granular interference that inherently exists in and degrades the quality of the active radar, synthetic aperture radar (SAR), medical ultrasound and optical coherence tomography images. See here) for more information.
Replace a value at location $i$ with the median of its neighbourhood values.
(Treat neighbourhood in a similar vein as the filter width in the case of linear filtering.)
x = np.random.rand(10)*255
x = x.astype(np.uint8)
print(f'x = {x}')
Picking values around $i$
# %load solutions/median-filtering/solution-01.py
half_width = 2
s = half_width
e = len(x)-half_width
for i in range(s,e):
print(f'center = {i}, values={x[i-half_width:i+half_width+1]}')
Picking median values for $i$ using its neighbourhood
# %load solutions/median-filtering/solution-02.py
result = np.copy(x)
for i in range(s,e):
neighbourhood = x[i-half_width:i+half_width+1]
result[i] = np.median(neighbourhood)
print(f'result = {result}')
half_width = 1
plt.figure(figsize=(20,15))
plt.subplot(121)
plt.title('Gaussian smoothing')
plt.imshow(cv.GaussianBlur(im, (2*half_width+1, 2*half_width+1), sigma), cmap='gray')
plt.subplot(122)
plt.title('Median filtering')
plt.imshow(cv.medianBlur(im, 2*half_width+1), cmap='gray');