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

news2024/12/23 9:23:14

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1923703.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

vue实现a-model弹窗拖拽移动

通过自定义拖拽指令实现 实现效果 拖动顶部,可对整个弹窗实施拖拽(如果需要拖动底部、中间内容实现拖拽,把下面的ant-modal-header对应改掉就行) 代码实现 编写自定义指令 新建一个ts / js文件,用ts举例 import V…

《财经日报》︱揭秘随身WiFi市场乱象与格行的破局之路 格行如何树立行业清流新标杆? 随身WiFi真的靠谱吗?

在移动互联网高速发展的今天,随身WiFi以其便捷性和高性价比迅速成为市场宠儿。然而,随着行业的迅速扩张,一系列乱象与套路也逐渐浮出水面:从虚假宣传到限速虚量,随身WiFi行业中的种种套路让消费者防不胜防。商家利用信…

Redis 的强大之处:为何它成为开发者的首选?

Redis 的强大之处:为何它成为开发者的首选? 1. 速度极快2. 数据类型多样3. 事务支持4. 特性丰富5、总结 💖The Begin💖点点关注,收藏不迷路💖 Redis,作为开源的内存数据结构存储系统&#xff0c…

AI办公自动化:相似照片批量智能删除

电脑中有大量手机照片,要批量删除其中相似度高的,首先得有一个分析照片相似度的算法和模型。CLIP(Contrastive Language-Image Pre-Training)模型是由OpenAI在2021年发布的一种多模态预训练神经网络,旨在通过对比学习方…

揭秘!MySQL索引背后的秘密武器:B+树为何力压跳表,独领风骚?

引出 想象一下,你正在一家巨大的图书馆工作,这里藏书百万册,读者络绎不绝,每个人都想尽快找到他们想要的书籍。图书馆的布局有两种设计方案摆在你面前: 方案A:使用传统的目录卡片系统,就像老式…

循环结构(一)——for语句【互三互三】

文章目录 🍁 引言 🍁 一、语句格式 🍁 二、语句执行过程 🍁 三、语句格式举例 🍁四、例题 👉【例1】 🚀示例代码: 👉【例2】 【方法1】 🚀示例代码: 【方法2】…

无人机运营合格证及无人机服务资质认证详解

一、运营合格证 无人机运营合格证是无人机运营单位或个人在特定区域内从事无人机运营活动的法定凭证。该证书由相关部门根据无人机运营单位的资质、技术能力和管理水平等综合因素进行审批和颁发。获得运营合格证的单位或个人需严格遵守国家相关法规和规定,确保无人…

3-2 多层感知机的从零开始实现

import torch from torch import nn from d2l import torch as d2lbatch_size 256 # 批量大小为256 train_iter, test_iter d2l.load_data_fashion_mnist(batch_size) # load进来训练集和测试集初始化模型参数 回想一下,Fashion-MNIST中的每个图像由 28 28 784…

【考研408操作系统】最容易理解的知识体系-文件管理-面向计算机管理

苏泽 “弃工从研”的路上很孤独,于是我记下了些许笔记相伴,希望能够帮助到大家 本篇内容续写上一篇的【考研408&操作系统】最容易理解的知识体系-文件管理-面向人类管理 这一篇将站在计算机如何管理好文件的角度去梳理这一章节的知识点 目录 本…

.欧拉函数.

先介绍欧拉函数: 贴一张 证明: 这里利用容斥原理来进行证明:若要求1~N当中与N互质的个数,则应在1~N当中去除N的质因数的倍数,因为既然是因数,那么一定不与N互质,既然是N的因数,那么…

初识Laravel(Laravel的项目搭建)

初识Laravel(Laravel的项目搭建) 一、项目简单搭建(laravel)1.首先我们确保使用国内的 Composer 加速镜像([加速原理](https://learnku.com/php/wikis/30594)):2.新建一个名为 Laravel 的项目&a…

gfast前端UI:基于Vue3与vue-next-admin适配手机、平板、pc 的后台开源模板

摘要 随着现代软件开发的高效化需求,一个能够快速适应不同设备、简化开发过程的前端模板变得至关重要。gfast前端UI,基于Vue3.x和vue-next-admin,致力于提供这样一个解决方案。本文将深入探讨gfast前端UI的技术栈、设计原则以及它如何适配手机…

(补充):java各种进制、原码、反码、补码和文本、图像、音频在计算机中的存储方式

文章目录 前言一、进制1 逢几进一2 常见进制在java中的表示3 进制中的转换(1)任意进制转十进制(2)十进制转其他进制二、计算机中的存储1 计算机的存储规则(文本数据)(1)ASCII码表(2)编码规则的发展演化2 计算机的存储规则(图片数据)(1)分辨率、像素(2)黑白图与灰度…

Linux 复现Docker NAT网络

Linux 复现Docker NAT网络 docker 网络的构成分为宿主机docker0网桥和为容器创建的veth 对构成。这个默认网络命名空间就是我们登陆后日常使用的命名空间 使用ifconfig命令查看到的就是默认网络命名空间,docker0就是网桥,容器会把docker0当成路由&…

linux nethogs网络监控程序(端口监控、流量监控、上传流量、下载流量、进程监控进程网络)

文章目录 Nethogs 网络监控程序详解1. 引言2. Nethogs 的安装与运行2.1 安装 Nethogs- **Debian/Ubuntu**- **Fedora**- **Arch Linux** 2.2 运行 Nethogs 3. Nethogs 的使用详解3.1 基本界面- **PID**:进程的 ID。- **用户**:运行该进程的用户。- **程序…

【Linux网络】数据链路层【上】{初识数据链路层/以太网/路由表/MAC地址表/ARP表/NAT表}

文章目录 1.初识数据链路层2.认识以太网2.0前导知识以太网帧和MAC帧CMSA/CD以太网的最小帧长限制是64字节IP层和MAC层 2.1以太网帧格式 3.预备知识计算机网络通信以太网和wifi路由表/MAC地址表/ARP表/NAT表/ACL表 用于同一种数据链路节点的两个设备之间进行信息传递。 1.初识数…

美团一面,你碰到过CPU 100%的情况吗?你是怎么处理的?

本文主要分为三部分 分析一下CPU 100%的常见原因 CPU 100%如何排查 回答这个问题的一个参考答案 CPU被打满的常见原因 1. 死循环 在实际工作中,可能每个开发都写过死循环的代码。 死循环有两种: 在 while、for、forEach 循环中的死循环。 无限递…

期末成绩单怎么单独发给家长,这个小工具超简单!

随着期末考试的落幕,老师们再次迎来了成绩处理的高峰期。传统的成绩单分发方式不仅耗时,还容易出错。但如今,有了易查分小程序,这一过程变得简便而高效。 易查分小程序,一个专为教师和家长设计的便捷工具,让…

[ruby on rails]部署时候产生ActiveRecord::PreparedStatementCacheExpired错误的原因及解决方法

一、问题: 有时在 Postgres 上部署 Rails 应用程序时,可能会看到 ActiveRecord::PreparedStatementCacheExpired 错误。仅当在部署中运行迁移时才会发生这种情况。发生这种情况是因为 Rails 利用 Postgres 的缓存准备语句(PreparedStatementCache)功能来…

【Apache Doris】周FAQ集锦:第 10 期

【Apache Doris】周FAQ集锦:第 10 期 SQL问题数据操作问题运维常见问题其它问题关于社区 欢迎查阅本周的 Apache Doris 社区 FAQ 栏目! 在这个栏目中,每周将筛选社区反馈的热门问题和话题,重点回答并进行深入探讨。旨在为广大用户…