Perform Image Noise Reduction Using PIL
0. Preface
In this section we describe some spatial filters and how to Pillow
implement them using library functions. We'll cover linear filters such as average ( mean
) and weighted average ( weighted mean
), and later in the study we'll cover nonlinear filters such as max
and min
filters. Each output pixel is a (linear or non-linear) function of the corresponding input pixel's neighbor pixels in the input image by slidingly applying a convolution kernel window over the image.
1. Mean filter
1.1 Principle of mean filter
The moving average or square filter is the simplest of all filters, replacing the pixel center value with the average of the pixel values in a square centered on the pixel. We can define a general linear filter using the following formula, a square filter is a special case of a linear filter:
( 2 m + 1 ) × ( 2 m + 1 ) (2m+1)\times(2m+1) ( 2 m+1)×( 2 m+1 ) Linear filter:
gij = ∑ k = − mm ∑ l = − mmwkl ⋅ fi + k , j + l g_{ij}=\sum ^m _{k=-m} \sum ^m _{l= -m} wkl \cdot f_{i+k,j+l}gij=k=−m∑ml=−m∑mw k l⋅fi+k,j+l
when m = 1 m=1m=When 1 means3 × 3 3\times 33×3 filters, in a square filterwkl = 1 ( 2 m + 1 ) 2 w_{kl}=\frac 1 {(2m+1)^2}wkl=( 2 m + 1 )21。 将下载手机新分,可得:
gij = w − 1 , − 1 fi − 1 , j − 1 + w − 1 , 0 fi − 1 , j + w − 1 , 1 fi − 1 , j + 1 + w 0 , − 1 fi , j − 1 + w 0 , 0 fi , j + w 0 , 1 fi , j + 1 + w 1 , − 1 fi + 1 , j − 1 + w 1 , 0 fi + 1 , j + w 1 , 1 fi + 1 , j + 1 g_{ij}=w_{-1,-1}f_{i-1,j-1}+w_{-1,0}f_{i-1, j}+w_{-1,1}f_{i-1,j+1}+w_{0,-1}f_{i,j-1}+w_{0,0}f_{i,j}+ w_{0,1}f_{i,j+1}+w_{1,-1}f_{i+1,j-1}+w_{1,0}f_{i+1,j}+w_{ 1,1}f_{i+1,j+1}gij=w−1,−1fi−1,j−1+w−1,0fi−1,j+w−1,1fi−1,j+1+w0,−1fi,j−1+w0,0fi,j+w0,1fi,j+1+w1,−1fi+1,j−1+w1,0fi+1,j+w1,1fi+1,j+1
In this section, we will use the function PIL
of filter()
to apply a square blur filter to an input RGB
image with noise and observe the smoothness at different levels of noise.
1.2 Use mean filter to remove salt and pepper noise
(1) First, the code imports the required library:
import numpy as np
import matplotlib.pylab as plt
from PIL import Image, ImageFilter
from copy import deepcopy
(2) Define the function plot_image()
Use the function matlplotlib.pyplot
of the module imshow()
to display the image as follows:
def plot_image(image, title=None, sz=10):
plt.imshow(image)
plt.title(title, size=sz)
plt.axis('off')
(3) Define the function add_noise()
Add salt and pepper (impulse) noise to the image. In addition to the input image, this function can also accept three parameters, where the prop_noise
parameter is used to define the noise ratio of the input pixel, and the parameter salt
and pepper
is used to control whether the image applies salt noise (white pixels) or pepper noise (black pixels), making the function more general , by default, both types of noise pixels are used:
def add_noise(im, prop_noise, salt=True, pepper=True):
im = deepcopy(im)
n = int(im.width * im.height * prop_noise)
x, y = np.random.randint(0, im.width, n), np.random.randint(0, im.height, n)
for (x,y) in zip(x,y):
im.putpixel((x, y), # generate salt-and-pepper noise
((0,0,0) if np.random.rand() < 0.5 else (255,255,255)) if salt and pepper \
else (255,255,255) if salt \
else (0, 0, 0)) # if pepper
return im
(4) Read the input image. For different noise levels/scales, add impulse noise to the input image, then image.filter()
apply a blur filter using the method to smooth the image with noise, plot the output image obtained in each case.
As mentioned before, the blur filter blurs the image by setting each pixel to be the average of the pixels in a square kernel window, thus extending the radius pixels in each direction. Supports arbitrarily sized float type 半径,默认使用
3x3` square blur filters.
orig = Image.open('1.png')
i = 1
plt.figure(figsize=(12,35))
for prop_noise in np.linspace(0.05,0.3,6):
# choose random locations inside image
im = add_noise(orig, prop_noise)
plt.subplot(6,2,i), plot_image(im, 'Original Image with ' + str(int(100*prop_noise)) + '% added noise')
im1 = im.filter(ImageFilter.BLUR)
plt.subplot(6,2,i+1), plot_image(im1, 'Blurred Image')
i += 2
plt.show()
As you can see from the above images, the less the noise scale, the better the noise reduction and smoothing (less blurriness).
2. Gaussian filter
2.1 Principle of Gaussian filter
Although moving average filter
the calculation of the moving average filter ( ) is very convenient and fast, it has the following two disadvantages, which may cause artifacts in the filtered image:
- It is not isotropic (i.e. circularly symmetric), smoother along the diagonal than along the rows and columns
- The changes between the weights are very abrupt, rather than gradually decaying to zero, which can produce discontinuities in the smoothed image
To overcome these disadvantages, it is possible to calculate the mean value that approximates a circular rather than a square neighborhood. To achieve this, we can usually use a Gaussian filter implementation, the Gaussian filter is the only decomposable filter that can be decomposed and expressed as the 1D
product of two Gaussian filters, and is at least approximately circularly symmetric. The weights from the core center to the core edge gradually decay to zero. The following expressions show a Gaussian filter kernel and give two examples of Gaussian kernels, with kernel sizes 3x3
and 5x5
:
Note:
wkl = 1 2 π 2 exp { − ( k 2 + l 2 ) 2 σ 2 } w_{kl}=\frac 1 {2\pi \sigma ^2}exp\{\frac { -(k^2+l^2)} {2\sigma^2}\}wkl=2 p.s _21exp{
2 p2−(k2+l2)}
3 x 3 3 times33×3 Gaussian filter as follows:
1 16 [ 1 2 1 2 4 2 1 2 1 ] \frac 1 {16} \left[ \begin{array}{ccc} 1 & 2 & 1\\ 2 & 4 & 2\\ 1 & 2 & 1\\ \end{array} \right]161
121242121
5 x 5 5\times55×Add 5 digits:
1 256 [ 1 4 6 4 1 4 16 24 16 4 6 24 36 24 6 4 16 24 16 4 1 4 6 4 1 ] \frac 1 {256} \left[ \begin{array}{ ccc} 1 & 4 & 6 & 4 & 1\\ 4 & 16 & 24 & 16 & 4\\ 6 & 24 & 36 & 24 & 6\\ 4 & 16 & 24 & 16 & 4\\ 1 & 4 & 6&4&1\\\end{array}\right]2561
1464141624164624362464162416414641
2.2 Use Gaussian blur filter to remove salt and pepper noise
(1) First read the input RGB
color image, and add a fixed ratio ( 20%
) of impulse noise:
import numpy as np
import matplotlib.pylab as plt
from PIL import Image, ImageFilter
from copy import deepcopy
def plot_image(image, title=None, sz=10):
plt.imshow(image)
plt.title(title, size=sz)
plt.axis('off')
def add_noise(im, prop_noise, salt=True, pepper=True):
im = deepcopy(im)
n = int(im.width * im.height * prop_noise)
x, y = np.random.randint(0, im.width, n), np.random.randint(0, im.height, n)
for (x,y) in zip(x,y):
im.putpixel((x, y), # generate salt-and-pepper noise
((0,0,0) if np.random.rand() < 0.5 else (255,255,255)) if salt and pepper \
else (255,255,255) if salt \
else (0, 0, 0)) # if pepper
return im
im = Image.open('1.png')
im = add_noise(im, prop_noise = 0.2)
(2) Using the method PIL
in image.filter()
, use to ImageFilter.GaussianBlur
instantiate a Gaussian filter with different radius parameter values (from 1
to 3
), and draw the output image:
plt.figure(figsize=(20,15))
i = 1
for radius in np.linspace(1, 3, 12):
im1 = im.filter(ImageFilter.GaussianBlur(radius))
plt.subplot(3,4,i)
plot_image(im1, 'radius = ' + str(round(radius,2)))
i += 1
plt.suptitle('PIL Gaussian Blur with different Radius', size=13)
plt.show()
The figure above shows the execution result of the code. It can be seen that when the Gaussian filter is used to perform denoising tasks, the larger the radius, the smoother the image and more noise can be removed, but at the same time the image will gradually blur and lose details.
3. Median filter
3.1 Principle of Median Filter
Neighborhood averaging can suppress noise from isolated outliers, but a corresponding side effect is that it also blurs more abrupt changes in the image, such as line features, sharp edges, and other image details that correspond to high frequencies. The nonlinear median filter is usually more effective than the linear mean filter in maintaining useful details in the image, and is more suitable for removing salt and pepper noise in the image.
Like the average filter, the median filter considers each pixel in the image in turn and looks at the pixel values in its window neighborhood to determine whether the pixel is representative of the surrounding neighborhood. Instead of simply replacing a pixel with the average of neighboring pixel values, it replaces it with the median of those values. First sort all pixel values in the surrounding neighborhood in numerical order, and then replace the pixel value with the median value of the sorted sequence.
3.2 Use median filter to remove salt and pepper noise
First, import the required Python
libraries, read the input color image, and add random impulse noise RGB
to the input image :1%
import numpy as np
import matplotlib.pylab as plt
from PIL import Image, ImageFilter
from copy import deepcopy
def plot_image(image, title=None, sz=10):
plt.imshow(image)
plt.title(title, size=sz)
plt.axis('off')
def add_noise(im, prop_noise, salt=True, pepper=True):
im = deepcopy(im)
n = int(im.width * im.height * prop_noise)
x, y = np.random.randint(0, im.width, n), np.random.randint(0, im.height, n)
for (x,y) in zip(x,y):
im.putpixel((x, y), # generate salt-and-pepper noise
((0,0,0) if np.random.rand() < 0.5 else (255,255,255)) if salt and pepper \
else (255,255,255) if salt \
else (0, 0, 0)) # if pepper
return im
im = Image.open('1.png')
im = add_noise(im, prop_noise = 0.1)
Use the function PIL
of image.filter()
to specify parameters ImageFilter.MedianFilter
to create multiple median filters with different kernel window sizes, and plot the output images obtained using filters of different sizes.
As mentioned earlier, the median filter selects the median pixel value from a sliding window of a given size:
plt.figure(figsize=(20,10))
plt.subplot(1,4,1)
plot_image(im, 'Input noisy image')
i = 2
for sz in [3,7,11]:
im1 = im.filter(ImageFilter.MedianFilter(size=sz))
plt.subplot(1,4,i), plot_image(im1, 'Output (Filter size=' + str(sz) + ')', 10)
i += 1
plt.tight_layout()
plt.show()
As can be seen from the above output results, the median filter produces less blur compared to the average filter, but for a larger size median filter kernel, it causes more texture loss in the output image.
summary
Noise is an important factor that interferes with the normal analysis and processing of images. There may be various noises in an image in practical applications. The noise may be generated during shooting or during transmission. In this section, we have learned several common linear filters including mean blur and Gaussian blur, as well as nonlinear filter median filter, and used these filters for image noise reduction, thereby improving image quality and facilitating follow-up processing and analysis.
series link
Python image processing [1] Image and video processing basics
Python image processing [2] Exploring Python image processing library
Python image processing [3] Python image processing library application
Python image processing [4] Image linear transformation
Python image processing [5] Image distortion /Unwarp
Python image processing [6] Find duplicate and similar images by hashing
Python image processing [7] Sampling, convolution and discrete Fourier transform
Python image processing [8] Blur images with low-pass filters
Python image processing [9] Python image processing using high-pass filter to perform edge detection
[10] Discrete cosine transform based image compression
Python image processing [11] Deconvolution to perform image deblurring
Python image processing [12] Wavelet transform based image denoising