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


    前言

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

    1. 准备工作

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

    • OpenCV (cv2)
    • NumPy

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

    pip install opencv-python numpy
    
    • 1

    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()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    在这个步骤中,我们定义了一个名为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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    在这个步骤中,我们定义了一个名为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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    在这个步骤中,我们定义了一个名为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))
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47

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

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

    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)
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123

    总结

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

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

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

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

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

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

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

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

  • 相关阅读:
    BR 备份与恢复场景示例
    停车场系统、智慧城市停车、智慧社区、物业管理、新能源充电、人脸门禁 uniapp 系统源码
    【基于Springboot、Mybatis后端框架开发——招生管理网站(系统)】附源码
    【PyGIS】ERA5降雨蒸散发数据预处理
    Seldom3.0: 支持App测试
    NLP第四范式:Prompt概述【Pre-train,Prompt(提示),Predict】【刘鹏飞】
    手机USB共享网络是个啥
    Linux——页面置换算法(OPT、FIFO、LRU的实现与比较)
    第314场周赛
    Leetcode.198 打家劫舍
  • 原文地址:https://blog.csdn.net/qq_42531954/article/details/133185322