使用 Python OpenCV 创建图像到卡通转换器

https://pyseek.com/2022/07/image-to-cartoon-converter-in-python/

一、说明

你有没有试过把自己的照片转换成卡通画?顺便说一句,这不是开玩笑。很多人喜欢把他们的照片变成卡通画并在社交媒体上分享。就连我自己也多次尝试过这种技术。有很多在线工具可以完成这项任务。但是如果我们自己制作一个图像到卡通画的转换器呢?听起来很棒吧?

在本教程中,我们将在OpenCV 和 Tkinter 库的帮助下,使用 Python 语言创建这样一个图像到卡通转换器。但是,在进入主要项目讨论之前,我们必须了解卡通化过程背后的核心逻辑以及如何通过 Python 编程实现它。

因此,我将整个主题分为两部分。在第一部分中,您将学习如何通过 Python 程序逐步为图像添加卡通效果。在第二部分中,我们将应用相同的逻辑来创建一个 Python 应用程序,只需单击几下即可实现卡通化效果。任何人都可以轻松使用该应用程序。

那么,让我们继续我们的精彩讨论。

二、算法和思路

2.1 使用

首先,我们需要安装 OpenCV 库(文档)。要获取它,请使用以下命令:

pip install opencv-python 

不用担心 Tkinter 库(文档)。大多数 Python 安装都已预装它。如果您没有它,可以使用以下命令安装它:

pip install tk 

2.2 导入模块

我建议您为该项目创建一个名为“ Cartoon-Maker ”的单独文件夹,并在其中声明一个 Python 文件“ cartoon_maker.py ”。

现在,让我们开始导入cv2模块。

import cv2 

2.3 打开图像

让我们打开您的图库并挑选一张您自己的高质量照片。现在将其保存在项目文件夹中。

在名为“ img_path ”的变量中提及图像的名称,并使用函数加载图像cv2.imread

img_path =“woman.jpg”
img = cv2.imread(img_path) 

2.4 调整图像大小并显示

并非所有计算机或笔记本电脑用户的屏幕尺寸都相同,这意味着显示的图像可能不会对每个人都完美显示。

为了确保统一性并避免任何不一致,调整图像大小非常重要,以便所有用户都能看到相同的图像。您可以使用此cv2.imread功能来实现这一点。

img = cv2.resize(img, (820,540))

在我们进入编辑阶段之前,让我们使用该cv2.imshow函数显示原始图像。

cv2.imshow("Result Image", img)
cv2.waitKey()
cv2.destroyAllWindows()

输出

2.5 转换为灰度

我们首先将图像转换为灰度以创建卡通效果。为此,我们将使用函数cv2.cvtColor。在此函数中,我们需要将初始加载的图像指定为初始参数,然后指定代码值,该代码值需要一个整数输入。

gray_img = cv2.cvtColor(src=img, code=cv2.COLOR_BGR2GRAY)

代码选项有很多,每个选项都与一个不同的整数相关联。记住这些数值可能很困难,这就是为什么我们选择使用更容易记住的代码名称(如cv2.COLOR_BGR2GRAY本例所示)而不是处理数字表示。

这是颜色空间转换的文档:  OpenCV 文档

现在,为了显示转换后的灰度图像,我们将使用上一节中用于显示的相同代码块。唯一需要调整的是更新函数中的第二个参数cv2.imshow,将其指定为“ gray_img ”。

cv2.imshow("Result Image", gray_img)
cv2.waitKey()
cv2.destroyAllWindows()

输出

2.6 平滑图像

平滑图像是图像到卡通转换过程中的关键步骤。

平滑处理是模糊图像同时保留其基本特征的技术。它有助于简化图像的细节、减少噪音并为卡通化过程做好准备。

在此步骤中,我们将对灰度图像应用中值模糊以实现我们现在的目标。

smooth_image = cv2.medianBlur(src=gray_img, ksize=5)

在上面的代码中,

  • src '代表我们之前转换为灰度图像的图像(“gray_img”)。
  • “ ksize ”表示用于模糊的内核的大小。在我们的例子中,我们取值为“5”。请注意,它只接受奇数整数值。您可以调整此值来控制平滑级别,请记住,值越高,平滑效果越好。

再次,我们将使用与上一节相同的技术显示平滑后的图像。

cv2.imshow("Result Image", smooth_img)
cv2.waitKey()
cv2.destroyAllWindows()

输出

2.7 应用边缘检测

现在我们将边缘检测技术应用于之前过滤的图像。

边缘检测是一种基本过程,可以增强图像中物体的轮廓,使其具有独特的卡通外观。在这里,我们将使用自适应阈值技术来实现这一点。为此,我们将cv2.adaptiveThreshold在代码中使用该函数。

edges = cv2.adaptiveThreshold(src=smooth_image, maxValue=255, adaptiveMethod=cv2.ADAPTIVE_THRESH_MEAN_C, thresholdType=cv2.THRESH_BINARY, blockSize=7, C=6)

在上面的代码中,

  • src ' 是我们在流程早期准备的平滑图像(“smooth_image”)。
  • maxValue '代表可能的最高像素值,在我们的上下文中,它设置为'255',并分配给满足阈值条件的像素。
  • adaptiveMethod '(cv2.ADAPTIVE_THRESH_MEAN_C)指定自适应阈值方法,该方法将每个邻域的阈值计算为邻域面积的平均值。
  • 'thresholdType ' ( cv2.THRESH_BINARY) 表示超过阈值的像素值将被设置为最大值 ( 255 ),而低于阈值的像素值将被设置为零。

现在,让我们展示一下最近添加的过滤图像。

cv2.imshow("Result Image", edges)
cv2.waitKey()
cv2.destroyAllWindows()

输出

2.8 应用卡通效果

在本节中,我们将使用双边滤波为图像提供卡通效果。它是图像处理中的关键工具,因为它可以同时平滑图像并保留边缘等重要细节。

我们来做一下代码:

color_img = cv2.bilateralFilter(src=img, d=9, sigmaColor=300, sigmaSpace=300)

在上面的代码中,

  • 'img ' 是您的图像的原始版本。
  • 参数“ d ”代表过滤过程中考虑的每个像素邻域的直径。
  • sigmaColor ' 根据颜色控制滤镜的影响。要获得卡通效果,您需要为其选择> 150 的值。
  • “ sigmaSpace ”根据空间距离或坐标控制滤镜的影响。要获得微调艺术效果,请为最后两个参数选择较高的值。

它会是什么样子?让我们再次显示它。

cv2.imshow("Result Image", color_img)
cv2.waitKey()
cv2.destroyAllWindows()

输出

2.9 应用风格化

我们正处于卡通化过程的最后一步。在本节中,我们将使用按位 AND函数将风格化应用于卡通化图像。

此功能使我们能够将卡通图像边缘检测图像相结合,突出图像的轮廓和特征,就像手绘插图一样。

以下是在 Python 中应用按位 AND 函数的方法:

cartoon_img = cv2.bitwise_and(src1=color_img, src2=color_img, mask=edges)

在上面的代码中:

  • color_image`是我们使用以前的技术卡通化的图像。
  • edges`是我们之前使用自适应阈值准备的边缘检测图像。

我们的卡通形象现在已经准备好了。让我们显示它。

cv2.imshow("Result Image", cartoon_img)
cv2.waitKey()
cv2.destroyAllWindows()

输出

2.10 保存图像

我们已经将原始图像转换为卡通图像,但要在其他地方使用它,我们必须保存它。在程序末尾添加此代码片段,以将卡通化图像保存在当前工作目录中。

cv2.imwrite("result.jpg", cartoon_img)

三、将程序变成应用程序

现在是时候通过使用 Tkinter 库提供图形界面来改善程序的用户体验了。我们将创建一个使用 Python 将图像转换为卡通的应用程序。

程序的核心逻辑是一样的。在本例中,我们将创建一个 GUI 窗口和一些小部件来选择、显示、卡通化和保存图像。

因此,在复制整个代码之前,请在“Cartoon-Maker”文件夹中创建一个名为“ app.py ”的 Python 文件。

import cv2
import pathlib
import pyautogui
from tkinter import *
from PIL import ImageTk, Image
from tkinter import filedialog


class Image_Cartoonify:
    def __init__(self, root):
        self.window = root
        self.window.geometry("960x560")
        self.window.title('Cartoonify')
        self.window.resizable(width=False, height=False)

        self.width = 740
        self.height = 480

        self.Image_Path = ''

        # ==============================================
        # ================Menubar Section===============
        # ==============================================
        # Creating Menubar
        self.menubar = Menu(self.window)

        # Adding Edit Menu and its sub menus
        edit = Menu(self.menubar, tearoff=0)
        self.menubar.add_cascade(label='Open', menu=edit)
        edit.add_command(label='Open Image', command=self.open_image)

        # Menu widget to cartoonify the image
        cartoonify = Menu(self.menubar, tearoff=0)
        self.menubar.add_cascade(label='Cartoonify', menu=cartoonify)
        cartoonify.add_command(label='Create Cartoon', command=self.cartoonify)

        # Exit the Application
        exit = Menu(self.menubar, tearoff=0)
        self.menubar.add_cascade(label='Exit', menu=exit)
        exit.add_command(label='Exit', command=self._exit)

        # Configuring the menubar
        self.window.config(menu=self.menubar)
        # ===================End=======================

        # Creating a Frame
        self.frame = Frame(self.window,
                           width=self.width, height=self.height)
        self.frame.pack()
        self.frame.place(anchor='center', relx=0.5, rely=0.5)

    # Open an Image through filedialog
    def open_image(self):
        self.clear_screen()
        self.Image_Path = filedialog.askopenfilename(title="Select an Image",
                                                     filetypes=(("Image files", "*.jpg *.jpeg *.png"),))
        if len(self.Image_Path) != 0:
            self.show_image(self.Image_Path)

    # Display the Image
    def show_image(self, Img):
        # Opening the image
        image = Image.open(Img)
        # resize the image, so that it fits to the screen
        resized_image = image.resize((self.width, self.height))

        # Create an object of tkinter ImageTk
        self.img = ImageTk.PhotoImage(resized_image)

        # A Label Widget for displaying the Image
        label = Label(self.frame, image=self.img)
        label.pack()

    def cartoonify(self):
        # Storing the image path to a variable
        ImgPath = self.Image_Path

        # If any image is not selected
        if len(ImgPath) == 0:
            pass
        else:
            # Get the file name to be saved after cartoonify the image
            filename = pyautogui.prompt("Enter the filename to be saved")
            # Filename with the extension (extension of the original image)
            filename = filename + pathlib.Path(ImgPath).suffix
            # Read the image
            Img = cv2.imread(ImgPath)
            Img = cv2.resize(Img, (740, 480))
            GrayImg = cv2.cvtColor(src=Img, code=cv2.COLOR_BGR2GRAY)
            SmoothImg = cv2.medianBlur(src=GrayImg, ksize=5)

            Edges = cv2.adaptiveThreshold(src=SmoothImg, maxValue=255, adaptiveMethod=cv2.ADAPTIVE_THRESH_MEAN_C,
                                          thresholdType=cv2.THRESH_BINARY, blockSize=9, C=9)

            # Adjust the the values of sigmaColor and sigmaSpace to get a proper cartoon effect
            ColorImg = cv2.bilateralFilter(src=Img, d=9, sigmaColor=300, sigmaSpace=300)

            CartoonImg = cv2.bitwise_and(src1=ColorImg, src2=ColorImg, mask=Edges)

            cv2.imwrite(filename, CartoonImg)

            self.clear_screen()
            self.show_image(filename)

    # Remove all widgets from the frame
    def clear_screen(self):
        for widget in self.frame.winfo_children():
            widget.destroy()

    # It destroys the main GUI window of the
    # application
    def _exit(self):
        self.window.destroy()


if __name__ == "__main__":
    root = Tk()
    # Creating an object of Image_Cartoonify class
    obj = Image_Cartoonify(root)
    root.mainloop()

在上面的程序中,我们创建一个名为的类Image_Cartoonify并声明六个方法。__init__创建一个 GUI 窗口和所有小部件。该open_image方法打开一个 tkinter 对话框来选择图像。

show_image方法在框架上显示所选图像。卡通化方法负责为所选图像赋予卡通效果。clear_screen_exit方法分别用于删除窗口上显示的所有小部件并关闭窗口。

四、总结

在本教程中,我们探索使用 Python 和 OpenCV 库创建图像到卡通转换器。

本教程分为两部分,第一部分重点介绍核心程序,分解每个步骤,从导入 OpenCV 模块到将图像转换为卡通。该过程包括图像加载、调整大小、灰度转换、平滑、边缘检测、应用卡通效果和风格化。

这还不是全部。在第二部分中,我们通过使用 Tkinter 库添加图形用户界面 (GUI) 来增强程序。它创建了一个用于将图像转换为卡通的应用程序。

相关推荐

  1. docker从创建使用

    2024-07-17 09:28:07       32 阅读
  2. Numpy矩阵OpenCV图像转换

    2024-07-17 09:28:07       34 阅读
  3. 爬虫框架Scrapy从创建使用

    2024-07-17 09:28:07       37 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-07-17 09:28:07       67 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-07-17 09:28:07       71 阅读
  3. 在Django里面运行非项目文件

    2024-07-17 09:28:07       58 阅读
  4. Python语言-面向对象

    2024-07-17 09:28:07       69 阅读

热门阅读

  1. Shiro 学习总结

    2024-07-17 09:28:07       23 阅读
  2. 面试题 27. 二叉树的镜像

    2024-07-17 09:28:07       30 阅读
  3. 从三个方向来谈谈开源项目有哪些机遇与挑战

    2024-07-17 09:28:07       24 阅读
  4. 告别自动激活:掌握如何在Conda中禁用Base环境

    2024-07-17 09:28:07       29 阅读
  5. 中国电子学会青少年编程等级考试真题下载

    2024-07-17 09:28:07       24 阅读
  6. Shell

    Shell

    2024-07-17 09:28:07      24 阅读
  7. 01.Verilog基础语法

    2024-07-17 09:28:07       22 阅读
  8. 音视频开发入门教程(1)如何安装FFmpeg?共210节

    2024-07-17 09:28:07       21 阅读
  9. HTTP缓存/强缓存/协商缓存

    2024-07-17 09:28:07       21 阅读
  10. 69、Flink 的 DataStream Connector 之 Kafka 连接器详解

    2024-07-17 09:28:07       20 阅读