Python image processing [13] using PIL to perform image noise reduction

0. Preface

In this section we describe some spatial filters and how to Pillowimplement 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 maxand minfilters. 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=mml=mmw k lfi+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=w1,1fi1,j1+w1,0fi1,j+w1,1fi1,j+1+w0,1fi,j1+w0,0fi,j+w0,1fi,j+1+w1,1fi+1,j1+w1,0fi+1,j+w1,1fi+1,j+1

In this section, we will use the function PILof filter()to apply a square blur filter to an input RGBimage 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.pyplotof 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_noiseparameter is used to define the noise ratio of the input pixel, and the parameter saltand pepperis 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()

mean filter
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 filterthe 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 1Dproduct 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 3x3and 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 RGBcolor 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 PILin image.filter(), use to ImageFilter.GaussianBlurinstantiate a Gaussian filter with different radius parameter values ​​(from 1to 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()

Gaussian blur

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 Pythonlibraries, read the input color image, and add random impulse noise RGBto 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 PILof image.filter()to specify parameters ImageFilter.MedianFilterto 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()

median filter
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

Guess you like

Origin blog.csdn.net/qq_30167691/article/details/128450352