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) 来增强程序。它创建了一个用于将图像转换为卡通的应用程序。