Basics of Kernels and Convolutions with OpenCV | by Thiago Carvalho | Towards Data Science

I’ve been trying to learn computer vision with Python and OpenCV, and I always stumble upon the terms kernel and convolution.
At first, I tried to rely on those gifs and some brief explanations, but I often get confused with their use, so I decided to get a better look at it.
In this article, I’ll share some of what I learned about kernels and convolutions while exploring some of its primary applications, such as blurring, sharpening, distilling and eroding.
Like me, you may think this has something to do with corn, but it doesn’t.
Kernels in computer vision are matrices, used to perform some kind of convolution in our data. Let’s try to break this down.
Convolutions are mathematical operations between two functions that create a third function. In image processing, it happens by going through each pixel to perform a calculation with the pixel and its neighbours.
The kernels will define the size of the convolution, the weights applied to it, and an anchor point usually positioned at the center.
So in a 3x3 matrix, each pixel is affected only by the pixels around it, wherein a 7x7 farther pixels would change it.
Alright, so to apply it to an image, we would: Position it over a given pixel using its anchor point, perform some operation between the values in the kernels and the values of the pixels, define a new value for that pixel, and move to the next.
Summarizing:
We can filter and modify images by interacting with their pixels;
That interaction may occur with convolutions;
Those convolutions use kernels to describe how the pixels will be affected;
Kernels represent the area for each operation, the values/weights, and the anchor point;
Enough talk, let’s see how we can put those kernels to use.We’ll use OpenCV, Numpy, and Matplotlib.
import cv2import numpy as npimport matplotlib.pyplot as plt
After importing the libraries, we can plot the original image, so we know what’s changing.
image = cv2.imread('Images/6.jpg')image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)fig, ax = plt.subplots(1, figsize=(12,8))plt.imshow(image)
Cool, now let’s make a kernel for blurring the image. We’ll use Numpy to build a 3x3 matrix of ones, and divide it by 9.
>>> kernel = np.ones((3, 3), np.float32) / 9>>> kernel...array([[0.11111111, 0.11111111, 0.11111111],       [0.11111111, 0.11111111, 0.11111111],       [0.11111111, 0.11111111, 0.11111111]], dtype=float32)
We can apply it to the image with .filter2D.
img = cv2.filter2D(image, -1, kernel)fig, ax = plt.subplots(1, figsize=(12,8))plt.imshow(img)
Let’s try this with a Sharpen kernel.
kernel = np.array([[0, -1, 0],                   [-1, 5, -1],                   [0, -1, 0]])
By using .filter2D, we can apply linear filters with any kernel we want. But there are also more comfortable ways of achieving those results.
OpenCV has some handy functions to filter images, and many times you won’t even have to define the kernel.
We can use .blur to apply a box blur, and we just need to pass the image and the size of the kernel.
image = cv2.imread('Images/6.jpg')image = cv2.blur(img, (5,5))image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)fig, ax = plt.subplots(1, figsize=(12,8))plt.imshow(image)
Gaussian and Median blur:
image = cv2.imread('Images/6.jpg')image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)fig, ax = plt.subplots(1, figsize=(12,16))ax = plt.subplot(211)g = cv2.GaussianBlur(image, (3,3), 0)plt.imshow(g)ax = plt.subplot(212)m = cv2.medianBlur(image, 3)plt.imshow(m)
Kernels can also help dilate and erode images — That seems to be useful when working pictures with text.
image = cv2.imread('Images/9.png')# convert to black and whiteimage = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) r ,image = cv2.threshold(image, 150, 255, cv2.THRESH_BINARY)# create kernelkernel = np.ones((5,5), np.uint8)fig, ax = plt.subplots(1, figsize=(16,12))# originalax = plt.subplot(232)plt.imshow(image, cmap='Greys')plt.title('original')# erosione = cv2.erode(image, kernel)ax = plt.subplot(234)plt.imshow(e, cmap='Greys')plt.title('erosion')# dilationd = cv2.dilate(image, kernel)ax = plt.subplot(235)plt.imshow(d, cmap='Greys')plt.title('dilation')# morphological gradient (dilation - erosion)m = cv2.morphologyEx(image, cv2.MORPH_GRADIENT, kernel)ax = plt.subplot(236)plt.imshow(m, cmap='Greys')plt.title('dilation - erosion')
In that application, the kernels are a structuring element that defines the shape and extension of the applied effect. Even though you do have to create a matrix, OpenCV has some functions to facilitate this process.
Kernels and convolutions are way more straightforward than I expected, and it’s easier to understand why they’re so widely used in image processing and how they can increase in complexity to support tasks such as image classification, object detection, and much more.
Thanks for reading my article. I hope you could get a clearer understanding of how convolutions use kernels to perform operations.
Resources:OpenCV 2D filter;OpenCV Smoothing;OpenCV filtering;OpenCV Morphological Transformations;
Going Further:OpenCV denoising;OpenCV Edge Detection;