In this tutorial you will learn how to:
- Use the OpenCV function :filter2d:`filter2D <>` to create your own linear filters.
Note
The explanation below belongs to the book Learning OpenCV by Bradski and Kaehler.
In a very general sense, convolution is an operation between every part of an image and an operator (kernel).
A kernel is essentially a fixed size array of numerical coefficeints along with an anchor point in that array, which is tipically located at the center.
Assume you want to know the resulting value of a particular location in the image. The value of the convolution is calculated in the following way:
- Place the kernel anchor on top of a determined pixel, with the rest of the kernel overlaying the corresponding local pixels in the image.
- Multiply the kernel coefficients by the corresponding image pixel values and sum the result.
- Place the result to the location of the anchor in the input image.
- Repeat the process for all pixels by scanning the kernel over the entire image.
Expressing the procedure above in the form of an equation we would have:
H(x,y) = \sum_{i=0}^{M_{i} - 1} \sum_{j=0}^{M_{j}-1} I(x+i - a_{i}, y + j - a_{j})K(i,j)
Fortunately, OpenCV provides you with the function :filter2d:`filter2D <>` so you do not have to code all these operations.
What does this program do?
Loads an image
Performs a normalized box filter. For instance, for a kernel of size size = 3, the kernel would be:
K = \dfrac{1}{3 \cdot 3} \begin{bmatrix} 1 & 1 & 1 \\ 1 & 1 & 1 \\ 1 & 1 & 1 \end{bmatrix}
The program will perform the filter operation with kernels of sizes 3, 5, 7, 9 and 11.
The filter output (with each kernel) will be shown during 500 milliseconds
The tutorial code's is shown lines below. You can also download it from here
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include <stdlib.h>
#include <stdio.h>
using namespace cv;
/** @function main */
int main ( int argc, char** argv )
{
/// Declare variables
Mat src, dst;
Mat kernel;
Point anchor;
double delta;
int ddepth;
int kernel_size;
char* window_name = "filter2D Demo";
int c;
/// Load an image
src = imread( argv[1] );
if( !src.data )
{ return -1; }
/// Create window
namedWindow( window_name, CV_WINDOW_AUTOSIZE );
/// Initialize arguments for the filter
anchor = Point( -1, -1 );
delta = 0;
ddepth = -1;
/// Loop - Will filter the image with different kernel sizes each 0.5 seconds
int ind = 0;
while( true )
{
c = waitKey(500);
/// Press 'ESC' to exit the program
if( (char)c == 27 )
{ break; }
/// Update kernel size for a normalized box filter
kernel_size = 3 + 2*( ind%5 );
kernel = Mat::ones( kernel_size, kernel_size, CV_32F )/ (float)(kernel_size*kernel_size);
/// Apply filter
filter2D(src, dst, ddepth , kernel, anchor, delta, BORDER_DEFAULT );
imshow( window_name, dst );
ind++;
}
return 0;
}
Load an image
src = imread( argv[1] ); if( !src.data ) { return -1; }
Create a window to display the result
namedWindow( window_name, CV_WINDOW_AUTOSIZE );
Initialize the arguments for the linear filter
anchor = Point( -1, -1 ); delta = 0; ddepth = -1;
Perform an infinite loop updating the kernel size and applying our linear filter to the input image. Let's analyze that more in detail:
First we define the kernel our filter is going to use. Here it is:
kernel_size = 3 + 2*( ind%5 ); kernel = Mat::ones( kernel_size, kernel_size, CV_32F )/ (float)(kernel_size*kernel_size);
The first line is to update the kernel_size to odd values in the range: [3,11]. The second line actually builds the kernel by setting its value to a matrix filled with 1's and normalizing it by dividing it between the number of elements.
After setting the kernel, we can generate the filter by using the function :filter2d:`filter2D <>`:
filter2D(src, dst, ddepth , kernel, anchor, delta, BORDER_DEFAULT );
The arguments denote:
- src: Source image
- dst: Destination image
- ddepth: The depth of dst. A negative value (such as -1) indicates that the depth is the same as the source.
- kernel: The kernel to be scanned through the image
- anchor: The position of the anchor relative to its kernel. The location Point(-1, -1) indicates the center by default.
- delta: A value to be added to each pixel during the convolution. By default it is 0
- BORDER_DEFAULT: We let this value by default (more details in the following tutorial)
Our program will effectuate a while loop, each 500 ms the kernel size of our filter will be updated in the range indicated.