|
|
|
@ -5,24 +5,24 @@ Goals |
|
|
|
|
----- |
|
|
|
|
|
|
|
|
|
Learn to: |
|
|
|
|
- Blur the images with various low pass filters |
|
|
|
|
- Blur images with various low pass filters |
|
|
|
|
- Apply custom-made filters to images (2D convolution) |
|
|
|
|
|
|
|
|
|
2D Convolution ( Image Filtering ) |
|
|
|
|
---------------------------------- |
|
|
|
|
|
|
|
|
|
As in one-dimensional signals, images also can be filtered with various low-pass filters(LPF), |
|
|
|
|
high-pass filters(HPF) etc. LPF helps in removing noises, blurring the images etc. HPF filters helps |
|
|
|
|
in finding edges in the images. |
|
|
|
|
As in one-dimensional signals, images also can be filtered with various low-pass filters (LPF), |
|
|
|
|
high-pass filters (HPF), etc. LPF helps in removing noise, blurring images, etc. HPF filters help |
|
|
|
|
in finding edges in images. |
|
|
|
|
|
|
|
|
|
OpenCV provides a function **cv.filter2D()** to convolve a kernel with an image. As an example, we |
|
|
|
|
will try an averaging filter on an image. A 5x5 averaging filter kernel will look like below: |
|
|
|
|
will try an averaging filter on an image. A 5x5 averaging filter kernel will look like the below: |
|
|
|
|
|
|
|
|
|
\f[K = \frac{1}{25} \begin{bmatrix} 1 & 1 & 1 & 1 & 1 \\ 1 & 1 & 1 & 1 & 1 \\ 1 & 1 & 1 & 1 & 1 \\ 1 & 1 & 1 & 1 & 1 \\ 1 & 1 & 1 & 1 & 1 \end{bmatrix}\f] |
|
|
|
|
|
|
|
|
|
Operation is like this: keep this kernel above a pixel, add all the 25 pixels below this kernel, |
|
|
|
|
take its average and replace the central pixel with the new average value. It continues this |
|
|
|
|
operation for all the pixels in the image. Try this code and check the result: |
|
|
|
|
The operation works like this: keep this kernel above a pixel, add all the 25 pixels below this kernel, |
|
|
|
|
take the average, and replace the central pixel with the new average value. This operation is continued |
|
|
|
|
for all the pixels in the image. Try this code and check the result: |
|
|
|
|
@code{.py} |
|
|
|
|
import numpy as np |
|
|
|
|
import cv2 as cv |
|
|
|
@ -47,20 +47,20 @@ Image Blurring (Image Smoothing) |
|
|
|
|
-------------------------------- |
|
|
|
|
|
|
|
|
|
Image blurring is achieved by convolving the image with a low-pass filter kernel. It is useful for |
|
|
|
|
removing noises. It actually removes high frequency content (eg: noise, edges) from the image. So |
|
|
|
|
edges are blurred a little bit in this operation. (Well, there are blurring techniques which doesn't |
|
|
|
|
blur the edges too). OpenCV provides mainly four types of blurring techniques. |
|
|
|
|
removing noise. It actually removes high frequency content (eg: noise, edges) from the image. So |
|
|
|
|
edges are blurred a little bit in this operation (there are also blurring techniques which don't |
|
|
|
|
blur the edges). OpenCV provides four main types of blurring techniques. |
|
|
|
|
|
|
|
|
|
### 1. Averaging |
|
|
|
|
|
|
|
|
|
This is done by convolving image with a normalized box filter. It simply takes the average of all |
|
|
|
|
the pixels under kernel area and replace the central element. This is done by the function |
|
|
|
|
This is done by convolving an image with a normalized box filter. It simply takes the average of all |
|
|
|
|
the pixels under the kernel area and replaces the central element. This is done by the function |
|
|
|
|
**cv.blur()** or **cv.boxFilter()**. Check the docs for more details about the kernel. We should |
|
|
|
|
specify the width and height of kernel. A 3x3 normalized box filter would look like below: |
|
|
|
|
specify the width and height of the kernel. A 3x3 normalized box filter would look like the below: |
|
|
|
|
|
|
|
|
|
\f[K = \frac{1}{9} \begin{bmatrix} 1 & 1 & 1 \\ 1 & 1 & 1 \\ 1 & 1 & 1 \end{bmatrix}\f] |
|
|
|
|
|
|
|
|
|
@note If you don't want to use normalized box filter, use **cv.boxFilter()**. Pass an argument |
|
|
|
|
@note If you don't want to use a normalized box filter, use **cv.boxFilter()**. Pass an argument |
|
|
|
|
normalize=False to the function. |
|
|
|
|
|
|
|
|
|
Check a sample demo below with a kernel of 5x5 size: |
|
|
|
@ -85,12 +85,12 @@ Result: |
|
|
|
|
|
|
|
|
|
### 2. Gaussian Blurring |
|
|
|
|
|
|
|
|
|
In this, instead of box filter, gaussian kernel is used. It is done with the function, |
|
|
|
|
**cv.GaussianBlur()**. We should specify the width and height of kernel which should be positive |
|
|
|
|
and odd. We also should specify the standard deviation in X and Y direction, sigmaX and sigmaY |
|
|
|
|
respectively. If only sigmaX is specified, sigmaY is taken as same as sigmaX. If both are given as |
|
|
|
|
zeros, they are calculated from kernel size. Gaussian blurring is highly effective in removing |
|
|
|
|
gaussian noise from the image. |
|
|
|
|
In this method, instead of a box filter, a Gaussian kernel is used. It is done with the function, |
|
|
|
|
**cv.GaussianBlur()**. We should specify the width and height of the kernel which should be positive |
|
|
|
|
and odd. We also should specify the standard deviation in the X and Y directions, sigmaX and sigmaY |
|
|
|
|
respectively. If only sigmaX is specified, sigmaY is taken as the same as sigmaX. If both are given as |
|
|
|
|
zeros, they are calculated from the kernel size. Gaussian blurring is highly effective in removing |
|
|
|
|
Gaussian noise from an image. |
|
|
|
|
|
|
|
|
|
If you want, you can create a Gaussian kernel with the function, **cv.getGaussianKernel()**. |
|
|
|
|
|
|
|
|
@ -104,14 +104,14 @@ Result: |
|
|
|
|
|
|
|
|
|
### 3. Median Blurring |
|
|
|
|
|
|
|
|
|
Here, the function **cv.medianBlur()** takes median of all the pixels under kernel area and central |
|
|
|
|
Here, the function **cv.medianBlur()** takes the median of all the pixels under the kernel area and the central |
|
|
|
|
element is replaced with this median value. This is highly effective against salt-and-pepper noise |
|
|
|
|
in the images. Interesting thing is that, in the above filters, central element is a newly |
|
|
|
|
in an image. Interestingly, in the above filters, the central element is a newly |
|
|
|
|
calculated value which may be a pixel value in the image or a new value. But in median blurring, |
|
|
|
|
central element is always replaced by some pixel value in the image. It reduces the noise |
|
|
|
|
the central element is always replaced by some pixel value in the image. It reduces the noise |
|
|
|
|
effectively. Its kernel size should be a positive odd integer. |
|
|
|
|
|
|
|
|
|
In this demo, I added a 50% noise to our original image and applied median blur. Check the result: |
|
|
|
|
In this demo, I added a 50% noise to our original image and applied median blurring. Check the result: |
|
|
|
|
@code{.py} |
|
|
|
|
median = cv.medianBlur(img,5) |
|
|
|
|
@endcode |
|
|
|
@ -122,19 +122,19 @@ Result: |
|
|
|
|
### 4. Bilateral Filtering |
|
|
|
|
|
|
|
|
|
**cv.bilateralFilter()** is highly effective in noise removal while keeping edges sharp. But the |
|
|
|
|
operation is slower compared to other filters. We already saw that gaussian filter takes the a |
|
|
|
|
neighbourhood around the pixel and find its gaussian weighted average. This gaussian filter is a |
|
|
|
|
operation is slower compared to other filters. We already saw that a Gaussian filter takes the |
|
|
|
|
neighbourhood around the pixel and finds its Gaussian weighted average. This Gaussian filter is a |
|
|
|
|
function of space alone, that is, nearby pixels are considered while filtering. It doesn't consider |
|
|
|
|
whether pixels have almost same intensity. It doesn't consider whether pixel is an edge pixel or |
|
|
|
|
whether pixels have almost the same intensity. It doesn't consider whether a pixel is an edge pixel or |
|
|
|
|
not. So it blurs the edges also, which we don't want to do. |
|
|
|
|
|
|
|
|
|
Bilateral filter also takes a gaussian filter in space, but one more gaussian filter which is a |
|
|
|
|
function of pixel difference. Gaussian function of space make sure only nearby pixels are considered |
|
|
|
|
for blurring while gaussian function of intensity difference make sure only those pixels with |
|
|
|
|
similar intensity to central pixel is considered for blurring. So it preserves the edges since |
|
|
|
|
Bilateral filtering also takes a Gaussian filter in space, but one more Gaussian filter which is a |
|
|
|
|
function of pixel difference. The Gaussian function of space makes sure that only nearby pixels are considered |
|
|
|
|
for blurring, while the Gaussian function of intensity difference makes sure that only those pixels with |
|
|
|
|
similar intensities to the central pixel are considered for blurring. So it preserves the edges since |
|
|
|
|
pixels at edges will have large intensity variation. |
|
|
|
|
|
|
|
|
|
Below samples shows use bilateral filter (For details on arguments, visit docs). |
|
|
|
|
The below sample shows use of a bilateral filter (For details on arguments, visit docs). |
|
|
|
|
@code{.py} |
|
|
|
|
blur = cv.bilateralFilter(img,9,75,75) |
|
|
|
|
@endcode |
|
|
|
@ -142,7 +142,7 @@ Result: |
|
|
|
|
|
|
|
|
|
![image](images/bilateral.jpg) |
|
|
|
|
|
|
|
|
|
See, the texture on the surface is gone, but edges are still preserved. |
|
|
|
|
See, the texture on the surface is gone, but the edges are still preserved. |
|
|
|
|
|
|
|
|
|
Additional Resources |
|
|
|
|
-------------------- |
|
|
|
|