Using the Image Filters in OpenCV
This tutorial is the 3rd in its series, and assumes that you have already completed the Tutorial 1 and Tutorial 2. OpenCV library have a well defined set of functions for filtering our image. When an image is acquired from a camera it is not proper. The image will be having random variations in the color intensity and contrast. We have to make the image process-able so that we get improved results from the application of various image processing algorithms. This is when the image filtering techniques comes into picture. These basic but slightly complex algorithms are useful in removing all the abnormalities in our input image making it ready for processing. Therefore the image filtering can be thought of as the first step in any image processing code. And That it the reason why this tutorial is classified as a basic beginner level OpenCV tutorial. The image filtering techniques which we are going to deal with in this tutorial are Erode, Dilate,Laplace,Smooth,and Sobel. I will explain each of them at a primary level before going into the implementation.
Kernel
The basic defenition that you need to know inorder to be able to follow this tutorial is about a kernel. A kernel is nothing but a fixed dimensional array of numeric coefficients which is used to manipulate an image in some manner. For example, we can imagine a 2x2 identity matrix being multiplied with an image after slicing the image into a number of matrices. Now if we rejoin the resulting matrices, we will obtain a transformed image. This means that a 2x2 kernel was used to transform the image in some fashion.
If you want to read more : Kernel
If you want to read more : Kernel
Erode
Inorder to understand Eroding properly, consider a kernel of some size which if operated upon another matrix finds the local minima of that matrix. Now consider that the our input image is sliced into matrices of size sufficient so that the kernel can operate upon. If the Kernel is convoluted with such a matrix, it will return the local minima of the matrix. When such a kernel is scanned over the whole image, effectively all the matrices containg a dark element will become dark. So effectively it means that the dark parts of image become significant/brighter. This can be used to fill smalll white noise in a black/dark background.
Dilate
Inorder to understand Dilate properly, consider a kernel of some size which if operated upon another matrix finds the local maxima of that matrix. Now consider that the our input image is sliced into matrices of size sufficient so that the kernel can operate upon. If the Kernel is convoluted with such a matrix, it will return the local maxima of the matrix. When such a kernel is scanned over the whole image, effectively all the matrices containg a lighter element will become lighter. So effectively it means that the lighter parts of image become significant/brighter. This can be used to fill smalll black noise in a white/light background. I deliberately copied and pasted the same paragraph to make you understand that the concept remains the same for both Erode and Dilate.
Smooth
Smoothing is done to remove the noise in an image. This is done by using a kernel which will find the weighted sum of the input matrix. There are different methods for snoothing. The difference in all of these techhniques is the kernel used. It may be a normalised unity matrix, gaussian,etc.
To read more : Smoothing
To read more : Smoothing
Laplace
Laplace basically helps us find the edges in an image. In an image, an edge is characterized by a high intensity variation. Therefore, if we take the first derivative of the same we will find a local maxima at the edge. This is just basic mathematics. Isn't it. Now consider that we take the second derivative of the image. We will get a zero at the edge. This is actually the method used in mathematics to check whether a point is a local maxima or not. So this is what laplace also does. Actually laplacian operator is the sum of the second derivative of the image or matrix or whatever in all the possible dimensions. So in the case of a single channel image, laplacian operator is the sum of second derivative of image in the two dimensions namely x and y.
Sobel
Sobel Operater is a discrete differential operator with gaussian smoothing. This means that it is the first step of laplace. Sobel can be used to find edges in an image. The edged will appear white on a dark background.
Erode,Dilate and Smooth
C implementation#include <cv.h> #include <highgui.h> int main() { //variables required in the program int erodecount = 1, dilatecount = 1; int smoothsize = 1, smoothheight = 1; int maxsmooth = 20, maxerode = 20, maxdilate = 20,max_ss = 10, max_sh = 10; //window names are initialized here const char *eimage = "Eroded Image", *dimage = "Dilated Image", *simage = "Smoothed Image"; //trackbar names are initialized here const char *etrack = "Erode", *dtrack = "Dilate", *sstrack = "Smooth Size", *shtrack = "Smooth Height"; //The images are initialized here. IplImage *im = cvLoadImage("F:\image.jpg"); IplImage *imerode = cvCreateImage(cvGetSize(im), 8,3),*imdilate = cvCreateImage(cvGetSize(im), 8,3); IplImage *imsmooth = cvCreateImage(cvGetSize(im), 8,3); cvNamedWindow(eimage); cvNamedWindow(dimage); cvNamedWindow(simage,3); //The required trackbars are created here. cvCreateTrackbar(etrack, eimage, &erodecount, maxerode, NULL); cvCreateTrackbar(dtrack, dimage, &dilatecount, maxdilate, NULL); cvCreateTrackbar(sstrack, simage, &smoothsize, max_ss, NULL); cvCreateTrackbar(shtrack, simage, &smoothheight, max_sh, NULL); while(cvWaitKey(10) != 27) { //Applying the filters cvErode(im, imerode, 0, erodecount); cvDilate(im, imdilate, 0, dilatecount); cvSmooth(im, imsmooth, CV_GAUSSIAN, 2*smoothsize-1,2*smoothheight-1); //Showing the images cvShowImage(eimage, imerode); cvShowImage(dimage, imdilate); cvShowImage(simage, imsmooth); cvShowImage("Original Image", im); } } |
C++ implementation#include <opencv2\opencv.hpp> using namespace cv; int main() { //variables required in the program int erodecount = 1, dilatecount = 1; int smoothheight = 1, smoothwidth = 1; int maxerode = 20, maxdilate = 20,max_sw = 20, max_sh = 20; //window names are initialized here const char *eimage = "Eroded Image", *dimage = "Dilated Image", *simage = "Smoothed Image"; //trackbar names are initialized here const char *etrack = "Erode", *dtrack = "Dilate", *swtrack = "Smooth Width", *shtrack = "Smooth Height"; //The images are initialized here. Mat im = imread("F:\image.jpg"); Mat imerode, imdilate,imsmooth; //creating a copy of image header only for illustration purpose imerode.create(im.size(),im.type()); namedWindow(eimage); namedWindow(dimage); namedWindow(simage,3); //Creating the trackbars createTrackbar(etrack, eimage, &erodecount, maxerode, NULL); createTrackbar(dtrack, dimage, &dilatecount, maxdilate, NULL); createTrackbar(swtrack, simage, &smoothwidth, max_sw, NULL); createTrackbar(shtrack, simage, &smoothheight, max_sh, NULL); while(waitKey(10) != 27) { //Appplying the image filters erode(im, imerode, Mat(), Point(-1, -1), erodecount); dilate(im, imdilate, Mat(), Point(-1, -1), dilatecount); GaussianBlur(im, imsmooth, Size(2*smoothwidth-1,2*smoothheight-1), 0, 0); //Displaying the images imshow("Original Image", im); imshow(eimage, imerode); imshow(dimage, imdilate); imshow(simage, imsmooth); } } |
Explanation
In the previous tutorials we haven't done any manipulation on the image. But in this tutorial, i have created a dynamic program which can allows the user to adjust the erosion, dilation, smoothness using the track bar feature of OpenCV. So now i will explain the newly introduced functions briefly.
IplImage *imsmooth = cvCreateImage(cvGetSize(im), 8,3); cvCreateImage(CvSize size, int bitDepth, int channels) is used to create and allocate image data. CvSize is an OpenCV structure that stores height and width.
To read more : CvSize Now the second parameter is the depth of image. the value can be 8,16,32. The 3rd paramater is the number of channels in the image. To read more : cvCreateImage cvCreateTrackbar(etrack, eimage, &erodecount, maxerode, NULL); |
imerode.create(im.size(),im.type()); The above line has no effect in the code. But was included so that the reader understands the various usages of Mat member functions.
Mat::create(Size size, int type) is used to create and allocate the space for image data. In this example we are allocating the same size and type of im to the image imerode. The Member functions Mat::size() and Mat::type() has been used to copy the image properties of im to imerode. To read more : Mat::create createTrackbar(etrack, eimage, &erodecount, maxerode, NULL); |
The explanation for both the functions are given together only because there is not much of a difference in the function declaration.
cvCreateTrachBar(const char* trackbarName, const char* windowName, int* value, int count, CvTrackbarCallback onChange)
can be used to create track bars in our OpenCV programs. Now Lets understand what are the parameters:
cvCreateTrachBar(const char* trackbarName, const char* windowName, int* value, int count, CvTrackbarCallback onChange)
can be used to create track bars in our OpenCV programs. Now Lets understand what are the parameters:
- The first parameter is the name of the track bar This will be displayed in the window.
- The second parameter is the name of the window. The window must be created using cvNamedWindow/namedWindow before creating track bar.
- The third parameter is the address of the integer variable. This variable will contain the value that we change using track bar.
- The fourth parameter is the maximum value the former variable can take.
- The fifth parameter is the name of the callback function to be called when the track bar value is changed. If not required give it as NULL.
cvErode(im, imerode, 0, erodecount); cvDilate(im, imdilate, 0, dilatecount);erode, NULL); |
erode(im, imerode, Mat(), Point(-1, -1), erodecount); dilate(im, imdilate, Mat(), Point(-1, -1), dilatecount); |
Even though the C and C++ functions for erode and dilate have a lot of difference, the structure of the function is same when we check cvErode and cvDilate. Therefore, I will be explaining only Erode function as you can easily understand how cvDilate works from the former.
cvErode(const CvArr* src, CvArr* dst, IplConvKernel* element, int iterations) is the function which is used to erode an image. Actually this is pretty easy use this function if you properly knows the function parameters.
cvSmooth(im, imsmooth, CV_GAUSSIAN, 2*smoothsize-1,2*smoothheight-1); cvSmooth(const CvArr* src, CvArr* dst, int smoothtype=CV_GAUSSIAN, int param1=3, int param2=0, double param3=0, double param4=0)
is the function used to smoothen an image.
|
erode(const Mat& src, Mat& dst, const Mat& element, Point anchor=Point(-1, -1), int iterations=1, int borderType=BORDER_CONSTANT, const Scalar& borderValue=morphologyDefaultBorderValue())
is the C++ equivalent of erode function. As we can see from the function declaration, it is highly flexible. It is possible to change the anchor point of kernel using the erode function itself. Now let us understand the function clearly
GaussianBlur(im, imsmooth, Size(2*smoothwidth-1,2*smoothheight-1), 0, 0); GaussianBlur(const Mat& src, Mat& dst, Size ksize, double sigmaX, double sigmaY=0, int borderType=BORDER_DEFAULT)
is the C++ equivalent of cvSmooth with CV_GAUSSIAN kernel.
|
Laplace and Sobel
This section of the tutorial will introduce two more interesting image filtering functions to you namely, Laplace and Sobel. I hope that you have went through the
theory of how the Laplacian and Sobel are taken for an image. You are always welcome to do some extra reading from other websites/textbooks about the operations.
theory of how the Laplacian and Sobel are taken for an image. You are always welcome to do some extra reading from other websites/textbooks about the operations.
#include <opencv2\opencv.hpp> using namespace cv; int main() { int laplacesize = 1,sobel_dx = 1, sobel_dy = 1, sobelsize = 1; int lsizemax = 3, smaxsize = 3, max_dx = 2, max_dy = 2; const char *lapwindow = "Laplace image", *sobelwindow = "Sobel image"; const char *laptrack = "Laplace size" , *sobels = "Sobel Size"; const char *sobeldy = "y order",*sobeldx = "x order"; IplImage *im = cvLoadImage("F:\image.jpg"); IplImage *imlaplace = cvCreateImage(cvGetSize(im),8,3), *imsobel = cvCreateImage(cvGetSize(im),8,3); cvNamedWindow(lapwindow); cvNamedWindow(sobelwindow,3); cvCreateTrackbar(laptrack, lapwindow, &laplacesize, lsizemax, NULL); cvCreateTrackbar(sobels, sobelwindow, &sobelsize, smaxsize, NULL); cvCreateTrackbar(sobeldx, sobelwindow, &sobel_dx, max_dx, NULL); cvCreateTrackbar(sobeldy, sobelwindow, &sobel_dy, max_dy, NULL); while(cvWaitKey(10) != 27) { cvLaplace(im, imlaplace, 2*laplacesize+1); cvSobel(im, imsobel, sobel_dx, sobel_dy, 2*sobelsize+1); cvShowImage("Original Image", im); cvShowImage(lapwindow, imlaplace); cvShowImage(sobelwindow, imsobel); } } |
#include <opencv2\opencv.hpp> using namespace cv; int main() { int laplacesize = 3,sobel_dx = 1, sobel_dy = 1, sobelsize = 3; int lsizemax = 3, smaxsize = 3, max_dx = 2, max_dy = 2; const char *lapwindow = "Laplace image", *sobelwindow = "Sobel image"; const char *laptrack = "Laplace size" , *sobels = "Sobel Size"; const char *sobeldy = "y order",*sobeldx = "x order"; Mat im = imread("F:\image.jpg"), imlaplace, imsobel; namedWindow(lapwindow); namedWindow(sobelwindow); createTrackbar(laptrack, lapwindow, &laplacesize, lsizemax, NULL); createTrackbar(sobels, sobelwindow, &sobelsize, smaxsize, NULL); createTrackbar(sobeldx, sobelwindow, &sobel_dx, max_dx, NULL); createTrackbar(sobeldy, sobelwindow, &sobel_dy, max_dy, NULL); while(waitKey(10) != 27) { Laplacian(im, imlaplace, CV_8U, 2*laplacesize+1); Sobel(im, imsobel, CV_8U, sobel_dx, sobel_dy, 2*sobelsize+1); imshow("Original Image", im); imshow(lapwindow, imlaplace); imshow(sobelwindow, imsobel); } } |
Explanation
cvLaplace(im, imlaplace, 2*laplacesize+1); cvLaplace(const CvArr* src, CvArr* dst, int apertureSize=3) is the fucnction used to find the laplacian of an image.
cvSobel(im, imsobel, sobel_dx, sobel_dy, 2*sobelsize+1); cvSobel(const CvArr* src, CvArr* dst, int xorder, int yorder, int apertureSize=3)
is the function used to apply sobel operation on an image.
|
Laplacian(im, imlaplace, CV_8U, 2*laplacesize+1); Laplacian(const Mat& src, Mat& dst, int ddepth, int ksize=1) is the function in C++ which is used too find the laplacian of an image.
Sobel(im, imsobel, CV_8U, sobel_dx, sobel_dy, 2*sobelsize+1); Sobel(const Mat& src, Mat& dst, int ddepth, int xorder, int yorder, int ksize=3)is the function used to apply sobel operation on an image.
|