Applying Filters on Images using OpenCV

Shenin Francies
5 min readJan 30, 2023

--

This tutorial aims to provide the users with the necessary tools to apply filters on images. In particular, we explore four filters — pencil sketch, warm effect, cool effect and finally, cartooning effect. In the next article, we deploy these filters on Streamlit, which is an App Framework to deploy Data Science projects. If you wish to try the Streamlit deployment on your own, you can reference the author’s repository.

Before we move any further, I would like to acknowledge Aditi Rastogi for her work on Cartooning an Image. You can read her article here:

The source code for the other filters is influenced by the book OpenCV: Computer Vision Projects with Python.

TL;DR: you can find the Code and the application in my GitHub Repo:

And here is the application itself:

With that out of the way, we can dive into the project at hand.

Filters For Images

Pencil Sketch

First off, we define the function for the Pencil Sketch:

def PencilSketch(image):

# Convert the image to Grayscale
gray_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# Remove Noise using Gaussian Blur
blurred_image = cv2.GaussianBlur(gray_image, (21, 21), 0, 0)
# Divide the image
final_image = cv2.divide(gray_image, blurred_image, scale=256)
# Thresholding
ret, mask = cv2.threshold(final_image, 70, 255, cv2.THRESH_BINARY)
# Bitwise operation
sketched_image = cv2.bitwise_and(mask, final_image)
return sketched_image

We can now simply call the function and pass the image into it, and display the output sketch using cv2.imshow():

path = '../Images and Videos/Image01 - Kids.jpg'
image = cv2.imread(path)
cv2.imshow('Original Image', cv2.imread(path))
cv2.imshow('Pencil Sketch', PencilSketch(image))
cv2.waitKey()
cv2.destroyAllWindows()

This yield the following Output:

Original Image
Pencil Sketch

In a similar Fashion, we define the functions for the remaining three filters.

Warming and Cooling Effect

Generally, in order to generate warm colors, we increase the red shade in the image, decrease the intensity of blue and make the colors appear vivid by increasing the color saturation. This gives the viewers an impression that the picture was taken on a hot, sunny day. Contrarily, to implement a cooling effect, we ought to increase the pixel values in the blue channel, decrease the pixel values in the red channel and also decrease the color saturation. The cooling effect gives an impression of the picture taken on a cold, dark or snowy day. When we say color saturation, we mean to take advantage of the HSV color space. Thus, there is also a conversion from RGB to HSV involved.

Now let’s get started. We first have to define a Look-up Table for increasing the pixel intensities and thus creating two generic curve filters. You can read the mathematics behind the curve filters in the aforementioned book.

from scipy.interpolate import UnivariateSpline
def LUT_8UC1(x, y):
spl = UnivariateSpline(x, y)
return spl(range(256))

increase_pixel = LUT_8UC1([0, 64, 128, 192, 256], [0, 70, 140, 210, 256])
decrease_pixel = LUT_8UC1([0, 64, 128, 192, 256], [0, 30, 80, 120, 192])

You can play around with the values — these values are taken from the example provided in the book.

Next, we define the warming and cooling effects:

import numpy as np
import cv2

def warming_effect(image):
# Split into RGB
red, green, blue = cv2.split(image)
# Increase the pixels' intensity in Red channel
red = cv2.LUT(red, increase_pixel).astype(np.uint8)
# Decrease the pixels' intensity in Blue channel
blue = cv2.LUT(blue, decrease_pixel).astype(np.uint8)
# Combine the RGB to yield the changes
rgb_image = cv2.merge((red, green, blue))
# Convert from RGB to HSV Color space for Saturation and split into HSV
hue, saturation, value = cv2.split(cv2.cvtColor(rgb_image, cv2.COLOR_RGB2HSV))
# Increase values of Saturation
saturation = cv2.LUT(saturation, increase_pixel).astype(np.uint8)
# Warming Effect on Image
final_image = cv2.cvtColor(cv2.merge((hue, saturation, value)), cv2.COLOR_HSV2RGB)
return final_image

# No comments - Infer from the Code!
def cooling_effect(image):
red, green, blue = cv2.split(image)
red = cv2.LUT(red, decrease_pixel).astype(np.uint8)
blue = cv2.LUT(blue, increase_pixel).astype(np.uint8)
rgb_image = cv2.merge((red, green, blue))
hue, saturation, value = cv2.split(cv2.cvtColor(rgb_image, cv2.COLOR_RGB2HSV))
saturation = cv2.LUT(saturation, decrease_pixel).astype(np.uint8)
final_image = cv2.cvtColor(cv2.merge((hue, saturation, value)), cv2.COLOR_HSV2RGB)
return final_image

For the same Image as before, here are the warming and cooling effects:

Warming Effect
Cooling Effect

It is important to note that the Warming/Cooling Effect may not correspond logically to how you may think, due to the way it is defined in the respective functions. That is, an image that has high pixel values in Blue Channel will have a higher Blue Channel in the cooling effect (subject to scrutiny).

Cartooning Effect

I will not go into the details of the code used for the Color Quantization, but you can get an insight into this method from Aditi Rastogi’s article here:

def color_quantization(image, k):
data = np.float32(image).reshape((-1, 3))
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 20, 1.0)
success, label, center = cv2.kmeans(data, k, None, criteria, 10, cv2.KMEANS_RANDOM_CENTERS)
center = np.uint8(center)
result = center[label.flatten()]
result = result.reshape(image.shape)
return result

Now we implement the cartooning effect:

def cartoon_effect(image):
# Color Quantization with 7 clusters
quantized_image = color_quantization(image, 7)
# Bilateral Filtering to remove noise
bilateral_image = cv2.bilateralFilter(quantized_image, 8, 150, 150)
# Grayscale Image Conversion
gray_image = cv2.cvtColor(bilateral_image, cv2.COLOR_BGR2GRAY)
# Preserve Edges - Can also use cv2.ADAPTIVE_THRESH_GAUSSIAN_C
edge_image = cv2.adaptiveThreshold(gray_image, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 9,9)
# Integrate the filtered image with its edges
cartoon_image = cv2.bitwise_and(bilateral_image, bilateral_image, mask=edge_image)
return cartoon_image

For the same image that we have been using so far, here is the “cartoonized” effect:

Cartooning Effect

Conclusion

Filters can be implemented seamlessly onto Images, thanks to OpenCV. Moreover, image manipulations are made simple with NumPy and SciPy. In this article, we have seen how we can implement various filters.

--

--

Shenin Francies
Shenin Francies

Written by Shenin Francies

Medical Engineer | Data Scientist | Computer Vision Enthusiast

No responses yet