Many might have heard about openCV, and how you can do various image processing using this library. OpenCV is a huge open source library for computer vision, machine learning and image processing. It is something very interesting and any AI/ML enthusiast should definitely having a look on this library.
Today, We are going to see an interesting usage of OpenCV, on how to make an image cartoonized. You would have seen something like this on snapchat or pix-art where it is trying to cartoonize the image. We will take the same objective and do it using python and OpenCV.
If you do not have OpenCV installed, then first you need to install it for python. Run this command on your terminal or notebook, and install the OpenCV.
pip install opencv-python
Now that we have installed our library. Lets import required packages for this objective.
import cv2 import numpy as np import matplotlib.pyplot as plt from matplotlib.pyplot import figure
Now let’s define a function that will read the image and store it. We can also see the image using this function as well. This read function will help us in future to process the input image.
def read_file(filename): img = cv2.imread(filename) img = cv2.cvtColor(img,cv2.COLOR_BGR2RGB) plt.imshow(img) plt.show() return img
Now lets provide a image path to this function and display the image. We are also going to store a copy of image which will come handfull later to check the differences. Lets do it.
filename = "image_path/image.jpg" img = read_file(filename) org_image=np.copy(img)
Great now we have read the image. Now we will try to create a cartoon of this. For this there is one thing that plays pretty huge role. That is getting the edges.
Creating Edge Mask:
Now are going to try to increase the edges of the image. So we define a function that will give us the edges of the image. It will take three arguments(image, line size, blur value). Lets create it.
def edge_mask(img, line_size, blur_value): gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY) gray_blur = cv2.medianBlur(gray, blur_value) edges = cv2.adaptiveThreshold(gray_blur, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, line_size, blur_value) return edges
Ok, now that we have made this function let’s go ahead and call it.
line_size,blur_value = 9,9 edges = edge_mask(img, line_size, blur_value) plt.imshow(edges, cmap="gray") plt.show()
Here, I have set line size and blur value to 9, but feel free to play around with it and see various outcomes. Lets look at the output.
Reducing Color Palette:
So now that we have got our edges, next thing that we to do is reducing or defining the the number of colors we want to see in our picture. For this we define a function that will transform the image to npfloat32 and reshape it. We will determine a criteria and implement a k-means clustering. Let’s built it.
def color_quantization(img, k): # Transform the image data = np.float32(img).reshape((-1,3)) #Determine Criteria criteria = (cv2.TERM_CRITERIA_EPS+ cv2.TERM_CRITERIA_MAX_ITER, 20, 0.001) ##Implementing K-Means ret, label, center = cv2.kmeans(data, k, None, criteria, 10, cv2.KMEANS_RANDOM_CENTERS) center = np.uint8(center) result=center[label.flatten()] result = result.reshape(img.shape) return result
The term k is the number of colors that we want in our image. For k-means, it is a number of centroids.
Let’s call this function now.
img_quantiz = color_quantization(img, k=4) plt.imshow(img_quantiz) plt.show()
It is not completely necessary to reduce noise, but it is a good practise to keep. So it will basically make a blur image rather than keeping must of edges that we defined. Reason to do so it we don’t want those edges to be showing in out cartoonized image, but one can keep it if wanted. It can be done by just using a bilateral Filter available in OpenCV. Let’s make it.
blurred = cv2.bilateralFilter(img_quantiz, d=4, sigmaColor=200, sigmaSpace=200) plt.imshow(blurred) plt.show()
The output would be something like:
So we have defined everything we need to make a cartoonized image. All that is left is to combine edge mask and color quantise function to one. We can do it by making a separate function for this. I would be like this:
def cartoon(): c = cv2.bitwise_and(blurred, blurred,mask= edges) plt.figure(figsize=(15, 15)) plt.imshow(c) plt.title("Cartoon Image") plt.show() plt.imshow(org_image) plt.title("Original Image") plt.show()
We are also printing both the images at once so you can see the difference. Making the cartoonized output a bit bigger so to see it properly.