深入了解Python和OpenCV:图像的卡通风格化

前言

当今数字时代,图像处理和美化已经变得非常普遍。从社交媒体到个人博客,人们都渴望分享独特且引人注目的图片。本文将介绍如何使用Python编程语言和OpenCV库创建令人印象深刻的卡通风格图像。卡通风格的图像具有艺术性和创意,它们可以用于图像编辑、创意表达以及增加娱乐价值。

1. 准备工作

在开始之前,您需要安装以下必要的库:

  • OpenCV (cv2)
  • NumPy

如果您还没有安装这些库,可以使用pip进行安装。

pip install opencv-python numpy

2. 读取和显示图像

首先,我们将介绍如何使用OpenCV读取图像文件并在窗口中显示它们。这是我们处理图像的第一步。

# 读取文件
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()

在这个步骤中,我们定义了一个名为read_file的函数,它接受一个文件名作为参数,并返回一个NumPy数组表示的图像。如果文件路径无效或图像格式不受支持,函数将引发异常。
我们定义了一个名为display_image的函数,它接受两个参数:要显示的图像和窗口的名称。函数将图像显示在指定的窗口中,并等待用户按下任意键后关闭窗口。这个简单的步骤允许我们在进行后续处理之前,查看原始照片的外观。

3. 创建边缘掩膜

接下来,我们将图像转化为卡通风格的第一步是创建边缘掩膜。我们将使用边缘检测技术来实现这一目标。

# 边缘掩膜
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

在这个步骤中,我们定义了一个名为edge_mask的函数,它接受三个参数:图像、线条大小(控制边缘粗细)和模糊程度。函数将图像转换为灰度图,然后应用中值模糊和自适应阈值处理,以创建边缘掩膜。

4. 颜色量化

卡通风格的图像通常具有较少的颜色。我们将使用K-Means聚类算法来减少图像中的颜色数量。

# 颜色量化
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

在这个步骤中,我们定义了一个名为color_quantization的函数,它接受两个参数:图像和要使用的颜色数量。函数首先将图像转换为数据矩阵,然后使用K-Means聚类算法将图像颜色量化为指定数量的颜色。最后,我们增强了图像的饱和度,以使颜色更加生动。

5. 图像处理和效果增强

在这一步骤中,我们将应用一些图像处理技术,如双边滤波,以增强最终的卡通效果图像。

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))

在这个步骤中,我们首先调整图像的大小和裁剪,以确保它符合处理的要求。然后,我们依次应用边缘掩膜、颜色量化、双边滤波和最后的掩膜应用,将图像转换成卡通画风。

这是整个卡通化过程的关键部分,通过这些步骤,您可以将任何普通照片转换成具有卡通风格的艺术品。在接下来的文章中,我们将展示如何使用这些代码来卡通化您自己的照片。

6. 完整代码

# -*- 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)

总结

在本文中,我们探讨了如何使用Python和OpenCV库创建卡通风格的图像。通过一系列图像处理步骤,我们将普通照片转化为有趣和具有创意的卡通风格图像。这个过程涵盖了图像读取、边缘检测、颜色量化、图像处理和效果增强等关键步骤。

卡通风格图像的制作涉及多个步骤,但通过掌握这些技巧,您可以自由发挥创造力,为照片增添新的趣味性。以下是本文中使用的一些关键技术的简要回顾:

  • 图像读取和显示: 我们使用OpenCV库来读取图像文件并在窗口中显示它们。这是开始图像处理的第一步。

  • 边缘掩膜: 为了创建卡通风格,我们使用了边缘检测技术,将图像中的边缘突出显示。

  • 颜色量化: 卡通图像通常包含较少的颜色。我们使用K-Means聚类来减少图像中的颜色数量,从而实现卡通风格的色彩。

  • 图像处理和效果增强: 我们应用了一些图像处理技术,例如双边滤波,以增强最终的卡通效果图像。

在完成所有处理步骤后,我们得到了有趣和独特的卡通风格图像。这个过程可以批量处理图像,使您能够轻松创建多个卡通化的照片。

希望本文对您有所帮助,能够启发您探索更多有趣的图像处理项目。 创造自己独特的卡通风格图像,让您的照片在社交媒体和网络上脱颖而出。

猜你喜欢

转载自blog.csdn.net/qq_42531954/article/details/133185322