Custom Image Filters Using 2D Convolution in OpenCV with Python

πŸ’‘ Problem Formulation: When working with image processing, a common task is to apply custom filters to enhance or extract features from images. Convolution is a mathematical operation used to apply these filters. Suppose we have an image and we want to highlight edges, blur, sharpen, or detect specific patterns using a custom designed filter. This article explains how to apply such custom 2D convolution filters using OpenCV in Python, transforming an input image into a filtered output image.

Method 1: Basic Edge Detection Filter

Edge detection is fundamental in image processing. Using a simple 2D convolution with a kernel that highlights edges, we can achieve this with OpenCV. The function cv2.filter2D() is utilized to apply a custom kernel to an image, with arguments specifying the depth of the output image.

Here’s an example:

import cv2
import numpy as np

# Read the image
image = cv2.imread('example.jpg', 0)
# Define the Edge Detection Kernel
kernel = np.array([[-1, -1, -1],
                   [-1,  8, -1],
                   [-1, -1, -1]])
# Apply the kernel to the image
edge_image = cv2.filter2D(image, -1, kernel)

cv2.imshow('Edge Detection', edge_image)
cv2.waitKey(0)
cv2.destroyAllWindows()

The output would be an image with its edges highlighted.

This code reads an image in grayscale, creates an edge detection kernel, and then applies it to the image. The filter emphasizes the edges by increasing the contrast between edge pixels and their surroundings.

Method 2: Custom Blur Filter

Blurring is commonly used to reduce image noise or decrease detail. The cv2.filter2D() function applies a custom kernel that averages surrounding pixels, producing a blur effect.

Here’s an example:

import cv2
import numpy as np

# Read the image
image = cv2.imread('example.jpg', 0)
# Define the Blur Kernel
kernel = np.ones((5, 5), np.float32) / 25
# Apply the kernel to the image
blur_image = cv2.filter2D(image, -1, kernel)

cv2.imshow('Blurred Image', blur_image)
cv2.waitKey(0)
cv2.destroyAllWindows()

The output image appears smoother and less sharp than the original.

The code snippet applies a 5×5 blur kernel to the image. The kernel is created by dividing a matrix of ones by the total number of elements in the kernel (25 in this case), ensuring that the output pixel value is the average of the input pixel’s neighborhood.

Method 3: Sharpening Filter

Sharpening emphasizes the differences in adjacent pixel values, making an image look clearer. This method uses the cv2.filter2D() function with a kernel that enhances the contrast around edges.

Here’s an example:

import cv2
import numpy as np

# Read the image
image = cv2.imread('example.jpg', 0)
# Define the Sharpening Kernel
kernel = np.array([[ 0, -1,  0],
                   [-1,  5, -1],
                   [ 0, -1,  0]])
# Apply the kernel to the image
sharpened_image = cv2.filter2D(image, -1, kernel)

cv2.imshow('Sharpened Image', sharpened_image)
cv2.waitKey(0)
cv2.destroyAllWindows()

The output is a sharper version of the input image with more defined edges and textures.

The code increases edge contrast to sharpen the image. The kernel has a strong positive value at the center and negative values around it, increasing the center pixel’s impact relative to its neighbors.

Method 4: Custom Pattern Detection

Applying a filter to detect specific patterns or textures in an image is more advanced. You can design a convolution kernel to highlight features that match a particular shape or orientation.

Here’s an example:

import cv2
import numpy as np

# Read the image
image = cv2.imread('example.jpg', 0)
# Define a Vertical Line Detection Kernel
kernel = np.array([[-1, 2, -1],
                   [-1, 2, -1],
                   [-1, 2, -1]])
# Apply the kernel to the image
line_image = cv2.filter2D(image, -1, kernel)

cv2.imshow('Vertical Line Detection', line_image)
cv2.waitKey(0)
cv2.destroyAllWindows()

The output highlights vertical lines found in the original image.

This code identifies vertical lines in the image. The convolution kernel applies more weight to pixels in a vertical line, amplifying vertical features and suppressing others.

Bonus One-Liner Method 5: Quick Emboss Filter

The emboss filter gives an image a 3D effect by simulating shadows on edges. A simple one-liner achieves this with a predefined kernel.

Here’s an example:

cv2.imshow('Embossed Image', cv2.filter2D(cv2.imread('example.jpg', 0), -1, np.array([[ -2, -1, 0], [-1, 1, 1], [0, 1, 2]])))

The output simulates an embossed artwork from the input image.

This concise snippet reads an image, applies an embossing kernel, and then displays the result. The kernel has a gradient of weights that create the illusion of depth by differing pixel intensities.

Summary/Discussion

  • Method 1: Edge Detection. Simple and effective for highlighting edges. May not work well on noisy images.
  • Method 2: Blur Filter. Excellent for noise reduction. Can oversmooth detail if the kernel is too large.
  • Method 3: Sharpening Filter. Can enhance detail. Might amplify noise in the image.
  • Method 4: Pattern Detection. Useful for feature extraction. Requires specific kernel design for different patterns.
  • Method 5: Emboss Filter. Provides a quick 3D effect. Not adjustable, and the result can sometimes be too subtle or pronounced, depending on the image.