Smoothing Images

In this tutorial you will learn how to apply diverse linear filters to smooth images using OpenCV functions such as:

Sources:

Contents

Theory

Note: The explanation below belongs to the book Computer Vision: Algorithms and Applications by Richard Szeliski and Learning OpenCV.

Smoothing, also called blurring, is a simple and frequently used image processing operation.

There are many reasons for smoothing. In this tutorial we will focus on smoothing in order to reduce noise (other uses will be seen in the following tutorials).

To perform a smoothing operation we will apply a filter to our image. The most common type of filters are linear, in which an output pixel's value (i.e. $g(i,j)$) is determined as a weighted sum of input pixel values (i.e. $f(i+k,j+l)$):

$$ g(i,j) = \sum_{k,l} f(i+k, j+l) h(k,l) $$

$h(k,l)$ is called the kernel, which is nothing more than the coefficients of the filter.

It helps to visualize a filter as a window of coefficients sliding across the image.

There are many kind of filters, here we will mention the most used.

1. Normalized Box Filter

$$ K = \frac{1}{K_{width} \cdot K_{height}}
    \left[ {\matrix{
      1 & 1 & 1 & ... & 1 \cr
      1 & 1 & 1 & ... & 1 \cr
      . & . & . & ... & 1 \cr
      . & . & . & ... & 1 \cr
      1 & 1 & 1 & ... & 1
    } } \right] $$

2. Gaussian Filter

pos = get(0, 'DefaultFigurePosition');
set(gcf, 'Position',pos.*[1 1 0.5 0.5])

x = linspace(-4,4,100);
plot(x, normpdf(x,0,1))
xlabel('x'), ylabel('G(x)'), grid on

Assuming that an image is 1D, you can notice that the pixel located in the middle would have the biggest weight. The weight of its neighbors decreases as the spatial distance between them and the center pixel increases.

Note: Remember that a 2D Gaussian can be represented as:

$$ G_{0}(x, y) = A e^{ \frac{ -(x - \mu_{x})^{2} }{ 2\sigma^{2}_{x} } +
                       \frac{ -(y - \mu_{y})^{2} }{ 2\sigma^{2}_{y} } } $$

where $\mu$ is the mean (the peak) and $\sigma$ represents the variance (per each of the variables $x$ and $y$).

3. Median Filter

The median filter run through each element of the signal (in this case the image) and replace each pixel with the median of its neighboring pixels (located in a square neighborhood around the evaluated pixel).

4. Bilateral Filter

Code

https://github.com/opencv/opencv/blob/3.1.0/samples/cpp/tutorial_code/ImgProc/Smoothing.cpp

This program:

%% Smoothing Demo
% Sample code for simple filters
%
% Sources:
%
% * <https://github.com/opencv/opencv/blob/3.1.0/samples/cpp/tutorial_code/ImgProc/Smoothing.cpp>
%

%%
% Global Variables
DELAY_CAPTION = 0.1;
DELAY_BLUR = 0.01;
MAX_KERNEL_LENGTH = 31;

%% Source Image
% Load the source image
src = imread(fullfile(mexopencv.root(),'test','lena.jpg'));
src = cv.resize(src, 2/3, 2/3);
imshow(src), title('Original Image')
pause(DELAY_CAPTION)

%dst = cv.putText(src, 'Original Image', [size(src,2) size(src,1)]./4, ...
%    'FontFace','HersheyComplex', 'FontScale',1, 'Color',[255 255 255]);

%% Homogeneous blur
for i=1:2:MAX_KERNEL_LENGTH
    dst = cv.blur(src, 'KSize',[i i], 'Anchor',[-1,-1]);
    imshow(dst), title(sprintf('Homogeneous Blur %d',i))
    pause(DELAY_BLUR)
end

%% Gaussian blur
for i=1:2:MAX_KERNEL_LENGTH
    dst = cv.GaussianBlur(src, 'KSize',[i i]);
    imshow(dst), title(sprintf('Gaussian Blur %d',i))
    pause(DELAY_BLUR)
end

%% Median blur
for i=1:2:MAX_KERNEL_LENGTH
    dst = cv.medianBlur(src, 'KSize',i);
    imshow(dst), title(sprintf('Median Blur %d',i))
    pause(DELAY_BLUR)
end

%% Bilateral Filter
for i=1:2:MAX_KERNEL_LENGTH
    dst = cv.bilateralFilter(src, 'Diameter',i, ...
        'SigmaColor',i*2, 'SigmaSpace',fix(i/2));
    imshow(dst), title(sprintf('Bilateral Blur %d',i))
    pause(DELAY_BLUR)
end

Explanation

Let's check the OpenCV functions that involve only the smoothing procedute, since the rest is already known by now.

1. Normalized Block Filter:

OpenCV offers the function cv.blur() to perform smoothing with this filter.

dbtype smoothing_demo 26:30
26    for i=1:2:MAX_KERNEL_LENGTH
27        dst = cv.blur(src, 'KSize',[i i], 'Anchor',[-1,-1]);
28        imshow(dst), title(sprintf('Homogeneous Blur %d',i))
29        pause(DELAY_BLUR)
30    end

We specify the following arguments (for more details, check the function reference):

2. Gaussian Filter:

It is performed by the function cv.GaussianBlur():

dbtype smoothing_demo 33:37
33    for i=1:2:MAX_KERNEL_LENGTH
34        dst = cv.GaussianBlur(src, 'KSize',[i i]);
35        imshow(dst), title(sprintf('Gaussian Blur %d',i))
36        pause(DELAY_BLUR)
37    end

Here we use the following arguments:

3. Median Filter:

This filter is provided by the cv.medianBlur() function:

dbtype smoothing_demo 40:44
40    for i=1:2:MAX_KERNEL_LENGTH
41        dst = cv.medianBlur(src, 'KSize',i);
42        imshow(dst), title(sprintf('Median Blur %d',i))
43        pause(DELAY_BLUR)
44    end

We use these arguments:

4. Bilateral Filter:

Provided by OpenCV function cv.bilateralFilter().

dbtype smoothing_demo 47:52
47    for i=1:2:MAX_KERNEL_LENGTH
48        dst = cv.bilateralFilter(src, 'Diameter',i, ...
49            'SigmaColor',i*2, 'SigmaSpace',fix(i/2));
50        imshow(dst), title(sprintf('Bilateral Blur %d',i))
51        pause(DELAY_BLUR)
52    end

We use the following arguments:

Results