Introduction
In the previous tutorial we saw how to create our own linear filters by creating the required kernel matrices. In this tutorial we will see three OpenCV functions which create the kernels for some widely used filters like Scharr and Sobel. Instead of typing the numbers by ourselves, we will get them directly. No need to remember the matrices, calculate them or look them up in the Internet. This will simplify our live as developers.
I will start directly with code examples. For more information I will provide links with descriptions of the respective kernel.
Sobel and Scharr kernel matrices
We will start our examples with the Sobel and Scharr kernels. These two filters are popular in the edge detection algorithms. Please, find more information about these filters here. Now, let us see some code
Sobel filter
The following code generates the kernel matrices, which we need to apply the Sobel filter. After we generate the two matrices, we use one OpenCV function to apply them. Here is the code.
// Get filter coefficients for computing spatial image derivative // using Sobel algo void getDerivativeKernelSobel() { // Path to the input image std::string l_pathToInputImage{ "../Resources/loveSymbol.jpg" }; // Create an object to hold the image data of the first image Mat l_image; // Read the image date from a file with no change to color scheme l_image = imread(l_pathToInputImage, IMREAD_UNCHANGED); // Check if we have read the first image data correctly if (!l_image.data) { std::cout << "No image data \n"; return; } // Create the output image matrices Mat l_outputImage{}; // Create the kernel Mat l_xKernel{}; Mat l_yKernel{}; getDerivKernels(l_xKernel, l_yKernel, 0, 1, 7, true); // Apply the filter sepFilter2D(l_image, l_outputImage, -1, l_xKernel, l_yKernel); // Display the input image namedWindow("Input", WINDOW_NORMAL); cv::imshow("Input", l_image); // Display the result image namedWindow("Result", WINDOW_NORMAL); cv::imshow("Result", l_outputImage); }
As usual, we load one image first. In my example I will apply the Sobel filter to one binary image. We can also apply it to grayscale or even colorful one. Then, we create three matrices. First matrix will hold the output image. The two other matrices xKernel and yKernel will hold the row and the column filter coefficients. What we actually are going to do is to generate row and column vectors and we will use the separability property of the filters’ kernels and instead of convolving with the whole matrix, we can convolve with the row then with the column vectors, decreasing the needed computations. Check this for more details.
The OpenCV function
After we have the kernel matrices, it is time to fill them. We do this by calling the getDerivKernels() OpenCV function. This function will return the xKernel vector and the yKernel vector, which we need to convolve with. The first two arguments are the output arrays, where we will hold the results. The third and the fourth arguments show the derivative order in which the convolution will happen. They can take values of 0 or 1. One of them should be 0 and the other one should be 1. This shows the order in which the kernels will be processed. If dx is 0, dy should be 1 and in this case, we will use xKernel first.
The ksize argument sets the aperture size. Use 1, 3, 5 or 7. These are the allowed values. If you use FILTER_SCHARR you will create the Scharr kernel (as we will do in the next example). The normalize argument sets whether to normalize the vectors or no. Try with both normalizing and leaving them as they are. Lastly, we have the ktype argument. I suggest to leave it with the default value.
Once we have created the kernels it is time to use them. There is one OpenCV function which works with separable kernels – sepFilter2D(). It takes the input and the output image matrices as the first arguments. Next, it gets the desired depth. I leave it to -1 in order to use the source image’s depth. The next two arguments are the X and Y kernels. We also have the anchor point, which I leave to the default one (the center point). Last two arguments I also leave by default. These are the delta value, that is added to the result and the border type. Leave them as they are.
The result
We finally display the results. With the binary image it looks like this on my side.

If I process the X kernel first, I get this:

Scharr filter
In the next example I will create the kernels for me to use with the Scharr filter. The code is the same as the Sobel one. Only difference is that I am using FILTER_SCHARR for the aperture size. Here is the code.
// Get filter coefficients for computing spatial image derivative // using Scharr algo void getDerivativeKernelScharr() { // Path to the input image std::string l_pathToInputImage{ "../Resources/loveSymbol.jpg" }; // Create an object to hold the image data of the first image Mat l_image; // Read the image date from a file with no change to color scheme l_image = imread(l_pathToInputImage, IMREAD_UNCHANGED); // Check if we have read the first image data correctly if (!l_image.data) { std::cout << "No image data \n"; return; } // Create the output image matrices Mat l_outputImage{}; // Create the kernel Mat l_xKernel{}; Mat l_yKernel{}; getDerivKernels(l_xKernel, l_yKernel, 0, 1, FILTER_SCHARR, true); // Apply the filter sepFilter2D(l_image, l_outputImage, -1, l_xKernel, l_yKernel); // Display the input image namedWindow("Input", WINDOW_NORMAL); cv::imshow("Input", l_image); // Display the result image namedWindow("Result", WINDOW_NORMAL); cv::imshow("Result", l_outputImage); }
The result with a binary image looks like this. With yKernel processed first:

With the xKernel processed first:

Gabor kernel
We will see now the Gabor filter and its respective kernel. It is used for texture analysis. This filter checks the image in a specific direction. Here and here are more details about it. Let us look at the code now.
// Get Gabor filter coefficients void getGaborKernelMatrix() { // Path to the input image std::string l_pathToInputImage{ "../Resources/hazard.jpg" }; // Create an object to hold the image data of the first image Mat l_image; // Read the image date from a file with no change to color scheme l_image = imread(l_pathToInputImage, IMREAD_UNCHANGED); // Check if we have read the first image data correctly if (!l_image.data) { std::cout << "No image data \n"; return; } // Create the output image matrices Mat l_outputImage{}; // Create the kernel constexpr int c_size = 3; constexpr double c_sigma = 10.0; constexpr double c_theta = 60.0; constexpr double c_lambda = 30.0; constexpr double c_gamma = 0.25; Mat l_kernel = getGaborKernel(Size{ c_size,c_size }, c_sigma, c_theta, c_lambda, c_gamma); // Apply the filter filter2D(l_image, l_outputImage, -1, l_kernel); // Display the input image namedWindow("Input", WINDOW_NORMAL); cv::imshow("Input", l_image); // Display the result image namedWindow("Result", WINDOW_NORMAL); cv::imshow("Result", l_outputImage); }
We start with the usuals – loading an image. Again, I am loading binary image. Then I create one output matrix to hold the result. Next, I am defining the coefficients like sigma and gamma, which we use in the filter’s equation.
In order to get the kernel matrix we call the getGaborKernel() OpenCV function. The first argument is the size of the matrix – both rows and columns. Then we provide the already defined coefficients – sigma, theta, lambda, gamma and psi. From the above links you can find more information about these coefficients. We leave the ktype with its default value.
After we have created the kernel matrix, we call the filter2D() function and process the image with the Gabor filter. In the previous tutorial we already saw how to use this function.
Finally, we display the results. On my side with one binary image the results look like this:

It has detected the areas, where we have a change in the intensity. Or in our case, the areas where we have a change from white to black and vice versa. Check also the result with colorful image below. Of course, you can change the coefficients values and get different results.

Gaussian kernel
Finally, let us see the function, which will create a Gaussian filter kernel. We already saw the Gauss filter in one of our previous tutorials. Now, let us see another way to apply it. Here is the code.
// Get Gaussian filter coefficients void getGaussianKernelMatrix() { // Path to the input image std::string l_pathToInputImage{ "../Resources/stormrider.jpg" }; // Create an object to hold the image data of the first image Mat l_image; // Read the image date from a file with no change to color scheme l_image = imread(l_pathToInputImage, IMREAD_UNCHANGED); // Check if we have read the first image data correctly if (!l_image.data) { std::cout << "No image data \n"; return; } // Create the output image matrices Mat l_outputImage{}; // Create the kernel constexpr int c_size = 7; constexpr double c_sigma = 10.0; Mat l_kernel = getGaussianKernel(c_size, c_sigma); // Apply the filter filter2D(l_image, l_outputImage, -1, l_kernel); // Display the input image namedWindow("Input", WINDOW_NORMAL); cv::imshow("Input", l_image); // Display the result image namedWindow("Result", WINDOW_NORMAL); cv::imshow("Result", l_outputImage); }
We do the usual things first – load an image and create another matrix to hold the result. We define the values, which we will need to pass to the function as arguments. On your side go ahead and play with them so you can get different results.
In order to create the kernel matrix I call the getGaussianKernel() OpenCV function. It requires the size of the matrix and the sigma value as arguments. The third argument ktype I leave with the default value.
Once I am done creating the matrix, I pass it to the already familiar function – filter2D(). Finally, we display the results. On my side it looks like this. You can see how blurred the original image is.

Conclusion
In this tutorial we saw how to generate kernels which we can use to apply some of the most used filters in the computer vision algorithms. Such filters like Sobel and Scharr. We learned the OpenCV functions which we need for this purpose. Now, there will be no need to write the matrices by hand, unless you need some fine-tunning.
The source code for this example is available in GitHub and as an archive attached below.
Next, we will continue with the linear filters and will see the Sobel and Scharr filters.

Passionate developer, loving husband and caring father. As an introvert programming is my life. I work as a senior software engineer in a big international company. My hobbies include playing computer games (mostly World of Warcraft), watching TV series and hiking.