A mini project with OpenCV in Python -Cartoonify an Image
By: Adeleke Dare
Tags: Programming, Image Processing, Opencv, Python, Machine Learning

This article is to teach about building an app that will give our photo a cartoonic impact using python and OpenCV. ‘Let get our fingers dirty!!!’

OpenCV, What heck are you?

OpenCV- Open Computer Vision — I am a library of programming functions mainly aimed at real-time computer vision, written in C/C++, released in June 2000, and a cross-platform library. There are bindings in Python, Java, Javascript, and MATLAB/OCTAVE. I am majorly used in image transformation, object detection, face recognition, and many other stunning applications. I am extensively being used in Machine Learning, Artificial Intelligence, Internet of Thing, etcetera. Good!

The app will output an instance seeing below :

The final output

Original Image:

Amazingly, we will be using a photo from this person does not exist website. It is a website powered by AI using GAN (Generative Adversarial Network) one of the machine learning algorithms.

Process of converting an image to a cartoon

To convert an image to a cartoon, multiple transformations are done.

Convert the image to a Grayscale image. Yes, similar to the old day’s pictures.!

The Grayscale image is smoothened

Extract the edges in the image

Form a colour image and mask it with edges.

This creates a beautiful cartoon image with edges and lightened colour of the original image.

Steps to create the Cartoonifier app

Step 1: Importing the required modules

# CODE: import tkinter as tk # graphical user interface toolkit

from tkinter import *

import easygui # to open the filebox

import cv2 # for image processing

import matplotlib.pyplot as plt import os # to read and save path

import sys

From the above, we imported the following;

tkinter: It is a Python binding to the Tk GUI toolkit

cv2: This is a module from the OpenCV library, it will be used for the image processing.

easygui: EasyGUI is a module for very simple, very easy GUI programming in python. Function fileopenbox returns the name of a file.

Matplotlib: This library is used for visualization and plotting. Thus, it is imported to form the plot of images.

OS: For OS interaction. Here, to read the path and save images to that path.

SYS: This module provides access to some variables used or maintained by the interpreter and to functions that interact strongly with the interpreter. e.g exit().

Step 2: Making the GUI main window

# CODE: top = tk.Tk()

top.geometry(‘400x400’)

top.title(‘Cartoonify Your Image !’)

top.configure(background=’blue’)

label = Label(top, background=’#CDCDCD’, font=(‘calibri’, 20, ‘bold’))

The Tk() function was called and assigned to the variable named ‘top’. In this step, we will build the main window of our application. It will contain buttons, labels, and images. .gepmetry(), .title(), .configure, and Label() are methods from Tkinter used in creating the window.

Step 3: Create a File Box to choose a particular file

# CODE: “”” fileopenbox opens the box to choose file

and help us store file path as string””” def upload():

image_path = easygui.fileopenbox()

cartoonify(image_path)

The code will open the pop-up box to choose the file from our device. fileopenbox() is a method from easyGUI module and it returned a string for the path chosen.

Step 4: Making the Cartoonify button in the GUI main window

# CODE: upload = Button(top, text=”Cartoonify an Image”, command=upload, padx=10, pady=5)

upload.configure(background=”#374256", foreground=”wheat”, font=(‘calibri’, 10, ‘bold’))

upload.pack(side=TOP, pady=50)

The above is all about the button creation, calling of step 2 upload function, setting background, font, and other specifications.

Step 5: Making a Save button in the GUI main window

# CODE: savel = Button(top, text=”Save cartoon image”, command=lambda: save(resize_image6, image_path), padx=30, pady=5)

savel.configure(background=’#364156', foreground=’white’, font=(‘calibri’, 10, ‘bold’))

savel.pack(side=TOP, pady=50)

The above code makes a button when the picture is transformed. It gives an alternative to save the cartoonified picture.

Step 6: Main function to build the GUI window

# CODE: top.mainloop()

When the function was called, its output is below:

Step 7: How is an Image stored?

Hope we don’t forget our computer basic knowledge, a computer only understands figure that is binary number 1 and 0. Thus, the below code will covert our imported image into a numpy array.

# CODE: def cartoonify(image_path):

# read image

original_image = cv2.imread(image_path)

original_image = cv2.cvtColor(original_image, cv2.COLOR_BGR2RGB)

print(original_image) # this will be stored in form of number

# to confirm it is image that was chosing

if original_image is None:

print(“Can’t find any image. Choose appropriate file”)

sys.exit() #resize the image after each transformation

resize_image1 = cv2.resize(original_image, (960, 540))

plt.imshow(resize_image1, cmap=’gray’)

In the above code, Imread is a method in cv2 which is used to store images in the form of numbers, it helps us to perform any operations on the image. The image is read as a numpy array, in which cell values depict R, G, and B values of a pixel.

NOTE: We resize the image after each transformation to display all the images on a similar scale at last.

Let Begin the Transformation

Step 8: Image transformation to grayscale

# CODE: # converting an image to grayscale

grayscale_image = cv2.cvtColor(original_image, cv2.COLOR_BGR2GRAY)



resize_image2 = cv2.resize(grayscale_image, (960, 540))

plt.imshow(resize_image2, cmap=”gray”)

cvtColor(image, flag) is a method in cv2 which is used to transform an image into the colour-space mentioned as ‘flag’. Here, our first step is to convert the image into grayscale. Thus, we use the BGR2GRAY flag. This returns the image in grayscale. After each transformation, we resize the resultant image using the resize() method in cv2 and display it using imshow() method. This is done to get more clear insights into every single transformation step.

The above code will generate the following output:

Transformation to Grayscale image

Step 9: Smoothening a grayscale image

# CODE: # applying median blur to smoothen an image

smooth_grayscale_image = cv2.medianBlur(grayscale_image, 5) resize_image3 = cv2.resize(smooth_grayscale_image, (960, 540))

plt.imshow(resize_image3, cmap=’gray’)

The medianBlur() function from cv2 is used in smoothening the grayscale image. The centre pixel is assigned a mean value of all pixels which fall under the kernel, this created a blur effect of the image.

The above code generates the following output:

Step 10a: Extracting the edges in the image (Highlighted Edges)

# CODE: # retrieving the edges for cartoon effect

# by using thresholding technique

get_edge = cv2.adaptiveThreshold(smooth_grayscale_image, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 9, 9) resize_image4 = cv2.resize(get_edge, (960, 540))

plt.imshow(resize_image4, cmap=’gray’)

Cartoon effect has two specialities; Highlighted Edges and Smooth colours. We will work on the first speciality. We try to retrieve the edges and highlight them. This is attained by the adaptive thresholding technique but not ordinary Simple Thresholding. The threshold value is the mean of the neighbourhood pixel values area minus the constant C. C is a constant that is subtracted from the mean or weighted sum of the neighbourhood pixels. Thresh_binary is the type of threshold applied, and the remaining parameters determine the block size.

The above code will generate output like below:

Extracted edges in the image

Step 10b: Cartoon effect specialities:- Smooth colours

# CODE: # applying bilateral filter to remove noise

# and keep edge sharp as required

color_image = cv2.bilateralFilter(original_image, 9, 300, 300) resize_image5 = cv2.resize(color_image, (960, 540))

plt.imshow(resize_image5, cmap=”gray”)

Second speciality ‘Smooth colours’; prepare a lightened colour image that was masked with edges at the end to produce a cartoon image. We use bilateralFilter function from cv2 which removes the noise. It can be taken as smoothening of an image to an extent. The third parameter is the diameter of the pixel neighbourhood, i.e, the number of pixels around a certain pixel which will determine its value. The fourth and Fifth parameter defines signmaColor and sigmaSpace. These parameters are used to give a sigma effect, i.e make an image look vicious and like water paint, removing the roughness in colours. Yes, it’s similar to BEAUTIFY or AI effect in cameras of modern mobile phones.

The above code generates the following output:

Applying smooth colour

Step 11: Giving a Cartoon Effect

# CODE: # masking edged image with our “BEAUTIFY” image

cartoon_image = cv2.bitwise_and(color_image, color_image, mask=get_edge) resize_image6 = cv2.resize(cartoon_image, (960, 540))

plt.imshow(resize_image6, cmap=’gray’)

Next task is to combine the two cartoon effect specialities Highlighted Edges and Smooth colours. This will be done using MASKING. We perform bitwise and on two images to mask them. Remember, images are just numbers? Yes, so that’s how we mask edged image on our “BEAUTIFY” image. This finally CARTOONIFY our image!

The above code will generate output like below:

The cartoon image

Step 12: Plotting all the transitions together

# CODE: # Plotting the whole transition

images = [resize_image1, resize_image2, resize_image3, resize_image4, resize_image5, resize_image6]

fig, axes = plt.subplots(3, 2, figsize=(8, 8), subplot_kw = {‘xticks’: [], ‘yticks’: []}, gridspec_kw=dict(hspace=0.1, wspace=0.1))

for i, ax in enumerate(axes.flat):

ax.imshow(images[i], cmap=’gray’) # save button code

plt.show()

Remember we named each transformation, so, plotting will be easier. Make a list of all the images, the list here is named “images” and contains all the resized images, that is, the name of each transformation. Now, we create axes like subplots in a plot and display one-one images in each block on the axis using imshow() method.

plt.show() plots the whole plot at once after we plot on each subplot.

The above code will generate output like below:

Step 13: Enhancing the save button

# CODE: def save(resize_image6, image_path):

# saving an image using imwrite function

new_name = “cartoonified_Image”

path1 = os.path.dirname(image_path)

extension = os.path.splitext(image_path)[1]

path = os.path.join(path1, new_name + extension)

cv2.imwrite(path, cv2.cvtColor(resize_image6, cv2.COLOR_RGB2BGR))

I = “Image saved by name “ + new_name + “ at “ + path

tk.messagebox.showinfo(title=None, message=I)

Here, the idea is to save the resultant image. For this, we take the old path, and just change the tail (name of the old file) to a new name and store the cartoonified image with a new name in the same folder by appending the new name to the head part of the file. For this, we extract the head part of the file path by os.path.dirname() method. Similarly, os.path.splitext(ImagePath)[1] is used to extract the extension of the file from the path. Here, newName stores “Cartoonified_Image” as the name of a new file. os.path.join(path1, newName + extension) joins the head of path to the newname and extension. This forms the complete path for the new file. imwrite() method of cv2 is used to save the file at the path mentioned. cv2.cvtColor(ReSized6, cv2.COLOR_RGB2BGR) is used to assure that no color get extracted or highlighted while we save our image. Thus, at last, the user is given confirmation that the image is saved with the name and path of the file.

The Final Result:

the final result

The Source Code:

The code source can be found on Github here

Summary

We have successfully developed Image Cartoonifier with OpenCV in Python. This is the magic of OpenCV which let us do wonder and it is just a piece of what openCV can offer.

To Talent and Innovation

References:

Wikipedia

GeeksforGeeks

Stackoverflow

Data-Flair