A Deep Dive into Python and OpenCV: Cartoon Stylization of Images

Preface

In today's digital age, image manipulation and beautification have become very common. From social media to personal blogs, people are eager to share unique and eye-catching images. This article will show you how to create impressive cartoon-style images using the Python programming language and the OpenCV library. Cartoon-style images are artistic and creative, and they can be used for image editing, creative expression, and to add entertainment value.

1. Preparation

Before starting, you need to install the following necessary libraries:

  • OpenCV (cv2)
  • NumPy

If you haven't installed these libraries yet, you can install them using pip.

pip install opencv-python numpy

2. Reading and displaying images

First, we'll cover how to use OpenCV to read image files and display them in a window. This is our first step in processing images.

# 读取文件
def read_file(filename: str) -> np.ndarray:
    try:
        img = cv2.imread(filename)
        if img is None:
            raise ValueError("Invalid file path or file format.")
        return img
    except:
        raise ValueError("Invalid file path or file format.")

# 显示图片
def display_image(img: np.ndarray, window_name: str) -> None:
    cv2.imshow(window_name, img)
    cv2.waitKey()

In this step, we define a function called read_file that accepts a filename as an argument and returns a NumPy array representation of the image. If the file path is invalid or the image format is not supported, the function throws an exception.
We define a function called display_image that accepts two parameters: the image to display and the name of the window. The function displays the image in the specified window and waits for the user to press any key before closing the window. This simple step allows us to see how the original photo will look before further processing.

3. Create an edge mask

Next, our first step in transforming the image into a cartoon style is to create an edge mask. We will use edge detection technology to achieve this.

# 边缘掩膜
def edge_mask(image: np.ndarray, line_size: int, blur_value: int) -> np.ndarray:
    if not isinstance(line_size, int) or not isinstance(blur_value, int) or line_size < 1 or blur_value < 1:
        raise ValueError("Invalid value for 'line_size' or 'blur_value' parameter. Must be a positive integer.")
    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    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

In this step, we define a function called edge_mask, which accepts three parameters: image, line size (to control edge thickness), and blur level. The function converts the image to grayscale and then applies median blur and adaptive thresholding to create an edge mask.

4. Color quantification

Cartoon style images usually have less color. We will use K-Means clustering algorithm to reduce the number of colors in the image.

# 颜色量化
def color_quantization(image: np.ndarray, num_colors: int) -> np.ndarray:
    if not isinstance(num_colors, int) or num_colors < 1:
        raise ValueError("Invalid value for 'num_colors' parameter. Must be a positive integer.")

    # 转换图片
    data = np.float32(image).reshape((-1, 3))

    # 设置KMeans聚类参数
    kmeans_criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 20, 0.001)
    flags = cv2.KMEANS_RANDOM_CENTERS

    # 执行KMeans聚类
    _, labels, centers = cv2.kmeans(data, num_colors, None, kmeans_criteria, 10, flags)
    centers = np.uint8(centers)
    processed_image = centers[labels.flatten()]
    processed_image = processed_image.reshape(image.shape)

    # 应用颜色增强
    hsv_image = cv2.cvtColor(processed_image, cv2.COLOR_BGR2HSV)
    hsv_image[:, :, 1] = hsv_image[:, :, 1] * 1.5  # 增强饱和度
    enhanced_image = cv2.cvtColor(hsv_image, cv2.COLOR_HSV2BGR)

    return enhanced_image

In this step, we define a function called color_quantization, which accepts two parameters: the image and the number of colors to use. The function first converts the image into a data matrix and then uses the K-Means clustering algorithm to quantize the image colors into a specified number of colors. Finally, we enhanced the saturation of the image to make the colors more vivid.

5. Image processing and effect enhancement

In this step, we will apply some image processing techniques such as bilateral filtering to enhance the final cartoon effect image.

def resize_crop(image):
    h, w, c = np.shape(image)
    if min(h, w) > 720:
        if h > w:
            h, w = int(720 * h / w), 720
        else:
            h, w = 720, int(720 * w / h)
    image = cv2.resize(image, (w, h), interpolation=cv2.INTER_AREA)
    h, w = (h // 8) * 8, (w // 8) * 8
    image = image[:h, :w, :]
    return image

# 图像处理和效果增强
def cartoonize(load_folder, save_folder):
    name_list = os.listdir(load_folder)
    for name in name_list:
        try:
            load_path = os.path.join(load_folder, name)
            save_path = os.path.join(save_folder, name)
            if not save_path.endswith('.jpg'):
                raise ValueError("Invalid file format. Must be a '.jpg' file.")
            image = cv2.imread(load_path)
            image = resize_crop(image)
            display_image(image, "Image")

            # 设置边缘掩膜参数并应用
            line_size = 7
            blur_value = 7
            edges = edge_mask(image, line_size, blur_value)
            display_image(edges, "Edges")

            # 执行颜色量化
            num_colors = 9
            processed_image = color_quantization(image, num_colors)
            display_image(processed_image, "Processed_image")

            # 应用双边滤波
            blurred = cv2.bilateralFilter(processed_image, d=9, sigmaColor=200, sigmaSpace=200)
            display_image(blurred, "Blurred")

            # 应用掩膜
            cartoonized_image = cv2.bitwise_and(blurred, blurred, mask=edges)
            display_image(cartoonized_image, "Cartoonized Image")

            cv2.imwrite(save_path, cartoonized_image)
        except:
            print('cartoonize {} failed'.format(load_path))

In this step, we first resize and crop the image to ensure it meets the processing requirements. We then apply edge masking, color quantization, bilateral filtering and finally mask application to transform the image into a cartoon style.

This is a crucial part of the entire cartoonization process, and with these steps you can transform any ordinary photo into a cartoon-style piece of art. In the following article, we'll show you how to use these codes to cartoonize your own photos.

6. Complete code

# -*- coding = utf-8 -*-
"""
# @Time : 2023/9/22 20:18
# @Author : FriK_log_ff 374591069
# @File : newmyway.py
# @Software: PyCharm
# @Function: 请输入项目功能
"""
import cv2
import numpy as np
import os


# 读取文件
def read_file(filename: str) -> np.ndarray:
    try:
        img = cv2.imread(filename)
        if img is None:
            raise ValueError("Invalid file path or file format.")
        return img
    except:
        raise ValueError("Invalid file path or file format.")


# 显示图片
def display_image(img: np.ndarray, window_name: str) -> None:
    cv2.imshow(window_name, img)
    cv2.waitKey()


# 边缘掩膜
def edge_mask(image: np.ndarray, line_size: int, blur_value: int) -> np.ndarray:
    if not isinstance(line_size, int) or not isinstance(blur_value, int) or line_size < 1 or blur_value < 1:
        raise ValueError("Invalid value for 'line_size' or 'blur_value' parameter. Must be a positive integer.")
    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    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


# 颜色量化
def color_quantization(image: np.ndarray, num_colors: int) -> np.ndarray:
    if not isinstance(num_colors, int) or num_colors < 1:
        raise ValueError("Invalid value for 'num_colors' parameter. Must be a positive integer.")

    # 转换图片
    data = np.float32(image).reshape((-1, 3))

    # 设置KMeans聚类参数
    kmeans_criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 20, 0.001)
    flags = cv2.KMEANS_RANDOM_CENTERS

    # 执行KMeans聚类
    _, labels, centers = cv2.kmeans(data, num_colors, None, kmeans_criteria, 10, flags)
    centers = np.uint8(centers)
    processed_image = centers[labels.flatten()]
    processed_image = processed_image.reshape(image.shape)

    # 应用颜色增强
    hsv_image = cv2.cvtColor(processed_image, cv2.COLOR_BGR2HSV)
    hsv_image[:, :, 1] = hsv_image[:, :, 1] * 1.5  # 增强饱和度
    enhanced_image = cv2.cvtColor(hsv_image, cv2.COLOR_HSV2BGR)

    return enhanced_image


def resize_crop(image):
    h, w, c = np.shape(image)
    if min(h, w) > 720:
        if h > w:
            h, w = int(720 * h / w), 720
        else:
            h, w = 720, int(720 * w / h)
    image = cv2.resize(image, (w, h), interpolation=cv2.INTER_AREA)
    h, w = (h // 8) * 8, (w // 8) * 8
    image = image[:h, :w, :]
    return image


# 上传文件
def cartoonize(load_folder, save_folder):
    name_list = os.listdir(load_folder)
    for name in name_list:
        try:
            load_path = os.path.join(load_folder, name)
            save_path = os.path.join(save_folder, name)
            if not save_path.endswith('.jpg'):
                raise ValueError("Invalid file format. Must be a '.jpg' file.")
            image = cv2.imread(load_path)
            image = resize_crop(image)
            display_image(image, "Image")

            # 设置边缘掩膜参数并应用
            line_size = 7
            blur_value = 7
            edges = edge_mask(image, line_size, blur_value)
            display_image(edges, "Edges")

            # 执行颜色量化
            num_colors = 9
            processed_image = color_quantization(image, num_colors)
            display_image(processed_image, "Processed_image")

            # 应用双边滤波
            blurred = cv2.bilateralFilter(processed_image, d=9, sigmaColor=200, sigmaSpace=200)
            display_image(blurred, "Blurred")

            # 应用掩膜
            cartoonized_image = cv2.bitwise_and(blurred, blurred, mask=edges)
            display_image(cartoonized_image, "Cartoonized Image")

            cv2.imwrite(save_path, cartoonized_image)
        except:
            print('cartoonize {} failed'.format(load_path))


if __name__ == '__main__':
    load_folder = 'test_images'
    save_folder = 'cartoonized_images'
    if not os.path.exists(save_folder):
        os.mkdir(save_folder)
    cartoonize(load_folder, save_folder)

Summarize

In this article, we explored how to create cartoon-style images using Python and the OpenCV library. Through a series of image processing steps, we transform ordinary photos into fun and creative cartoon-style images. This process covers key steps such as image reading, edge detection, color quantification, image processing and effect enhancement.

There are multiple steps involved in creating cartoon-style images, but by mastering these techniques, you can be free to be creative and add a new level of interest to your photos. Here is a brief review of some of the key technologies used in this article:

  • Image reading and display: We use OpenCV library to read image files and display them in the window. This is the first step to start image processing.

  • Edge Masking: To create a cartoon look, we used edge detection technology to highlight the edges in the image.

  • Color quantization: Cartoon images usually contain fewer colors. We use K-Means clustering to reduce the number of colors in the image to achieve cartoon-style colors.

  • Image processing and effect enhancement: We applied some image processing techniques such as bilateral filtering to enhance the final cartoon effect image.

After completing all processing steps, we get interesting and unique cartoon style images. This process processes images in batches, allowing you to easily create multiple cartoonized photos.

I hope this article was helpful and inspired you to explore more interesting image processing projects. Create your own unique cartoon style images to make your photos stand out on social media and the web.

Guess you like

Origin blog.csdn.net/qq_42531954/article/details/133185322