Cartoonize image using OpenCV in Python

I found a great example code to cartoonize image using OpenCV in Python, let's give it a try!


Reference: Best Ways to Cartoonize an Image Using OpenCV in Python

Modified code in my exercise, pyCartoonize.py.
"""
Cartoonize image using OpenCV in Python

I found a great example code to cartoonize image using OpenCV in Python,
let's give it a try!

reference:
https://blog.finxter.com/5-best-ways-to-cartoonize-an-image-using-opencv-in-python/

In the post, 4 method are listed to Cartoonize an Image Using OpenCV in Python.
Method 1: Bilateral Filtering and Edge Detection.
          Produces a smooth, clean cartoon effect.
          Good for high-resolution images but can be computationally intensive.
Method 2: Color Quantization and Edge Enhancement.
          Delivers a visually distinct cartoon with flat colors and crisp borders.
          Works best with strongly contrasting images.
          The setup is slightly complex due to k-means.
Method 3: Enhancing Edges with a Combination of Filters.
          Provides a high-contrast edge-focused cartoon.
          Suitable for stylized images with strong lines.
          Not ideal for subtle color transitions.
Bonus Method 5: Simplified Cartoon Effect.
          Offers a quick solution with a minimal code footprint.
          Good for rapid prototyping but lacks the finesse of the other methods.

"""
import cv2
import numpy as np
import os
import time

"""
cartoonize part copy from:
https://blog.finxter.com/5-best-ways-to-cartoonize-an-image-using-opencv-in-python/
"""
# Method 1: Applying Bilateral Filtering and Edge Detection
def cartoonize_method1(image_file):
    
    # Read the image
    img = cv2.imread(image_file)

    # Apply bilateral filter
    cartoon_img = cv2.bilateralFilter(img, d=9, sigmaColor=75, sigmaSpace=75)

    # Convert to grayscale and apply median blur
    gray = cv2.cvtColor(cartoon_img, cv2.COLOR_BGR2GRAY)
    blurred = cv2.medianBlur(gray, 7)

    # Detect edges and create a mask
    edges = cv2.adaptiveThreshold(blurred, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, blockSize=9, C=2)
    colored_edges = cv2.bitwise_and(cartoon_img, cartoon_img, mask=edges)
    
    return colored_edges

# Method 2: Color Quantization and Edge Enhancement
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

def cartoonize_method2(image_file):
    # Read the image
    img = cv2.imread(image_file)

    # Color quantization
    quantized_img = color_quantization(img, k=9)

    # Convert to grayscale
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

    # Apply median blur, detect edges
    blurred = cv2.medianBlur(gray, 7)
    edges = cv2.adaptiveThreshold(blurred, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, blockSize=9, C=2)

    # Combine quantized image with edge mask
    cartoon_img = cv2.bitwise_and(quantized_img, quantized_img, mask=edges)
    
    return cartoon_img

# Method 3: Enhancing Edges with a Combination of Filters
def cartoonize_method3(image_file):
    # Read and scale down the image
    img = cv2.imread(image_file)
    img = cv2.pyrDown(cv2.imread(image_file))
    # Convert to grayscale
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    # Apply median blur
    blurred = cv2.medianBlur(gray, 5)
    # Use a Laplacian filter for edge detection
    edges = cv2.Laplacian(blurred, cv2.CV_8U, ksize=5)
    # Invert the color of edges
    inverted_edges = 255-edges 
    # Combine original image with edges
    cartoon_img = cv2.bitwise_or(img, img, mask=inverted_edges)

    return cartoon_img

# Bonus One-Liner Method 5: Simplified Cartoon Effect
def cartoonize_method5(image_file):

    # Reading, smoothing, and edge detection all in one line
    return cv2.bitwise_and(cv2.bilateralFilter(cv2.imread(image_file), d=9, sigmaColor=300, sigmaSpace=300), cv2.bilateralFilter(cv2.imread(image_file), d=9, sigmaColor=300, sigmaSpace=300), mask=cv2.Canny(cv2.imread(image_file), 100, 150))


# Read jpg image from "selected_images" sub-folder
images_folder = "./images_B"
files = os.listdir(images_folder)
jpg_files = [file for file in files if file.endswith('.jpg')]
sorted_jpg_files = sorted(jpg_files)

display_time = 3


while True:
    for filename in sorted_jpg_files:
        img_path = os.path.join(images_folder, filename)
        print(filename)
    
        org_img = cv2.imread(img_path)
        cv2.imshow('org_img', org_img)
    
        cartoonized_image = cartoonize_method1(img_path)
        cv2.imshow('pyCartoonize', cartoonized_image)
    
        end_time = time.time() + display_time
    
        while (time.time() < end_time):
            if cv2.getWindowProperty('pyCartoonize', cv2.WND_PROP_VISIBLE) < 1:
                break
            if cv2.getWindowProperty('org_img', cv2.WND_PROP_VISIBLE) < 1:
                break
            cv2.waitKey(1)
        if cv2.getWindowProperty('pyCartoonize', cv2.WND_PROP_VISIBLE) < 1:
                break
        if cv2.getWindowProperty('org_img', cv2.WND_PROP_VISIBLE) < 1:
                break
    if cv2.getWindowProperty('pyCartoonize', cv2.WND_PROP_VISIBLE) < 1:
        break
    if cv2.getWindowProperty('org_img', cv2.WND_PROP_VISIBLE) < 1:
        break

cv2.destroyAllWindows()


Next:
~ Run on Raspberry Pi, display on 320×480 ST7796 SPI LCD.


Comments