基于OpenCV的图像卡通化

重磅干货,第一时间送达

本期将创建一个类似于Adobe Lightroom的Web应用程序,使用OpenCV和Streamlit实现图像的卡通化

作为一个狂热的街头摄影爱好者,几乎每个周末都要在城市中拍摄一些照片,因此Adobe Lightroom始终是我们的首选软件,通过它可以编辑原始照片以使其更具“ Instagram风格”。

我们想能否创建一个自己的图像编辑软件?

开源计算机视觉库(如OpenCV)和开源应用程序框架(如Streamlit)的出现使这一想法得以实现。使用不到100行代码,我们就可以构建一个简单的图像卡通化Web应用程序,模仿Adobe Lightroom的功能。

在本文中,我们将展示如何使用OpenCV和Streamlit,根据滤波器,构建一个简单的Web应用程序,以将图像转换为卡通图像。
如何使图像成为卡通图?

我们通常需要执行两个主要步骤将图像转换为卡通图像:边缘检测和区域平滑。

边缘检测的主要目的显然是为了强调图像的边缘,因为卡通图像通常具有良好的边缘。同时,区域平滑的主要目的是消除颜色边界并减少图像的噪点,使图像像素化程度降低。

根据不同滤波器,我们可以获得不同的图像卡通化结果。在本文中,将有四个不同的过滤器:

1. 铅笔素描
2. 细节增强
3. 双边过滤器
4. 铅笔边缘

接下来,我们将展示如何应用每个过滤器,以及从每个过滤器中获得什么样的结果。

铅笔素描滤波器

使用“铅笔素描”滤波器,您的图像将被转换为素描,就像使用铅笔绘制图像一样。下面是使用OpenCV将图像转换为铅笔素描的完整代码。

# Convert the image into grayscale imagegray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# Blur the image using Gaussian Blur gray_blur = cv2.GaussianBlur(gray, (25, 25), 0)
# Convert the image into pencil sketchcartoon = cv2.divide(gray, gray_blur, scale=250.0)

令人惊讶的是,使用OpenCV,我们只需三行代码就可以将图像转换成铅笔素描状的图片。现在让我逐行解释一下该图像发生了哪些变化。

在第一行中,我们使用OpenCV的cvtColor()功能将图像从彩色通道转换为灰度通道。这很简单,处理的结果是我们将图像变成了灰度图。

接下来,我们使用高斯模糊对图像进行模糊处理。模糊灰度图像,实际上是在平滑图像,减少图像的噪点。另外,模糊也是我们检测图像边缘的必要步骤。

模糊图像,可以使用OpenCV中的GaussianBlur()功能。我在GaussianBlur()函数中输入的(25,25)是内核的大小。

由于我们使用高斯模糊,因此内核中像素值的分布遵循正态分布。核数越大,标准偏差将越大,因此模糊效果越强。下面是内核大小不同时的模糊结果示例。

基于不同内核大小的模糊效果

最后一步是将原始灰度图像除以模糊后的灰度图像。这样可以得出两个图像中每个像素之间的变化率。模糊效果越强,每个像素的值相对于其原点的变化就越大,因此,它使我们的铅笔素描更加清晰。

以下是使用铅笔素描过滤器的结果。

铅笔素描过滤器实现示例
细节增强滤波器

简而言之,“细节增强”滤镜通过锐化图像,平滑颜色以及增强边缘效果为我们提供了卡通效果。以下是使用此滤镜将您的图像转换成卡通的完整代码。

#convert the image into grayscale imagegray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
#Blur the grayscale image with median blurgray_blur = cv2.medianBlur(gray, 3)
#Apply adaptive thresholding to detect edgesedges = cv2.adaptiveThreshold(gray_blur, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 9, 9)
#Sharpen the imagecolor = cv2.detailEnhance(img, sigma_s=5, sigma_r=0.5)
#Merge the colors of same images using "edges" as a maskcartoon = cv2.bitwise_and(color, color, mask=edges)

第一步与之前相同,我们需要将图像转换为灰度图像。

接下来,不使用高斯模糊,而是应用中值模糊。为此,我们使用OpenCV中的medianBlur() 函数。中值模糊通过计算与内核重叠的像素值的中值,然后将其中心像素替换为中值。但是,我们可以根据需要先使用高斯模糊。

接下来,我们需要检测图像的边缘。为此,将自适应阈值与OpenCV中的adaptiveThreshold() 函数一起应用。自适应阈值的主要目标是根据内核重叠的像素的平均值,将图像每个区域中的每个像素值转换为黑色或白色。

以下是自适应阈值对模糊图像的影响的可视化结果。

左:自适应阈值之前—右:自适应阈值之后

为了使图像看起来更清晰,我们可以使用OpenCV中的detailEnhance()函数。我们需要指定两个参数:

· sigma_s:控制着邻域的大小,该邻域的大小将被加权以替换图像中的像素值。值越高,邻域越大。这样可以使图像更平滑。

· sigma_r:如果要在平滑图像时保留边缘,这很重要。较小的值只会产生非常相似的颜色进行平均(即平滑),而相差很大的颜色将保持不变。

最后,我们使用自适应阈值的结果作为掩码。然后,根据蒙版的值合并细节增强的结果,以创建具有清晰边缘的清晰效果。

以下是“细节增强”过滤器的示例结果。

细节增强过滤器实现示例

双边过滤器

使用双边滤镜的一大优势是,我们可以在保留边缘的同时使图像和颜色平滑。以下是通过双边过滤将您的图像转换为卡通图像的完整代码。

#convert the image into grayscale imagegray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
#Blur the grayscale image with median blurgray_blur = cv2.medianBlur(gray, 3)
#Apply adaptive thresholding to detect edgesedges = cv2.adaptiveThreshold(gray_blur, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 9, 9)
#Sharpen the imagecolor = cv2.detailEnhance(img, sigma_s=5, sigma_r=0.5)
#Merge the colors of same images using "edges" as a maskcartoon = cv2.bitwise_and(color, color, mask=edges)

如果仔细看,所有步骤都与“细节增强”过滤器中的步骤相似,但是这次不是使用detailEnhance() 函数,而是使用openCV中的bilateralFilter()函数。

调用此函数时需要传递的参数与detailEnhance()相同,只多一个附加参数,即内核大小d。首先,我们指定图像源,然后是d,sigma_s和sigma_r值控制平滑效果,并保持边缘。

以下是使用双边过滤器的结果示例。

双边过滤器实施示例

铅笔边缘滤波器

铅笔边缘滤镜可创建仅包含重要边缘和白色背景的新图像。要应用此滤波器,下面是完整的代码。

#Convert the image into grayscale imagegray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
#Blur the grayscale image using median blurgray = cv2.medianBlur(gray, 25)
#Detect edges with Laplacianedges = cv2.Laplacian(gray, -1, ksize=3)
#Invert the edgesedges_inv = 255-edges
#Create a pencil edge sketchdummy, cartoon = cv2.threshold(edges_inv, 150, 255, cv2.THRESH_BINARY)

前两个步骤与其他过滤器相同。首先,我们将图像转换为灰度图像。接下来,我们使用大小为25的内核对图像进行模糊处理。

接下来,我们应用拉普拉斯滤波器来检测边缘。根据内核的大小,拉普拉斯滤波器中的值可以不同。

Laplacian滤波器的工作是,将通过对象内部的灰度级和图像背景强度来突出对象的边缘。以下是拉普拉斯滤波器应用结果。

左:拉普拉斯滤波器应用之前—右:拉普拉斯滤波器应用之后

接下来,我们将Laplacian滤波器的结果求反。最后,通过应用openCV中的threshold()函数,根据指定的阈值将灰度图像转换为全黑或全白。

以下是“铅笔边缘”过滤器的结果示例。

Pencil Edges滤镜实现示例

使用Streamlit构建图像卡通化Web应用程序

在创建了图像卡通化滤波器的代码之后,现在就可以创建图像卡通化Web应用程序了。

第一步,需要将创建图像卡通化滤波器的所有代码放入一个函数中,以便于访问。到目前为止,我们已经对每个参数值进行了硬编码,例如内核的大小等等。

现在,我们可以让用户使用滑块根据自己的喜好指定一个值,而不是对每个参数值进行硬编码。为此,我们可以使用Streamlit中的streamlit.slider()函数。下面是其实现的示例。

gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)scale_val = st.slider('Tune the brightness of your sketch (the higher the value, the brighter your sketch)', 0.0, 300.0, 250.0)kernel = st.slider('Tune the boldness of the edges of your sketch (the higher the value, the bolder the edges)', 1, 99, 25, step=2)gray_blur = cv2.GaussianBlur(gray, (kernel, kernel), 0)cartoon = cv2.divide(gray, gray_blur, scale= scale_val)

使用此滑块,可以创建一个交互式图像卡通化Web应用程序,就像Adobe Lightroom一样。每次调整内核的值和其他参数时,图像卡通化的结果都会实时更改和更新。

我们可以将其应用到streamlit.slider()上,创建的每个图像卡通化滤波器,以替换硬编码的参数值。

接下来,我们需要添加一个小插件,以便用户可以上传自己想要转换为卡通的图像。为此,我们可以使用Streamlit中的streamlit.file_uploader()函数。要添加某些文本到Web应用程序中,我们可以使用Streamlit 中的streamlit.text()或streamlit.write()。

用户上传图像后,现在我们需要显示图像,使用图像卡通化滤波器之一编辑图像,并显示卡通化图像,以便用户知道他们是否要进一步调整滑块。要显示图像,我们可以使用Streamlit中的streamlit.image()函数。

以下是在不到100行代码的情况下如何构建图像卡通化Web应用程序的实现。

import cv2import streamlit as stimport numpy as np from PIL import Image

def cartoonization (img, cartoon):
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
if cartoon == "Pencil Sketch": value = st.sidebar.slider('Tune the brightness of your sketch (the higher the value, the brighter your sketch)', 0.0, 300.0, 250.0) kernel = st.sidebar.slider('Tune the boldness of the edges of your sketch (the higher the value, the bolder the edges)', 1, 99, 25, step=2)

gray_blur = cv2.GaussianBlur(gray, (kernel, kernel), 0)
cartoon = cv2.divide(gray, gray_blur, scale=value)
if cartoon == "Detail Enhancement": smooth = st.sidebar.slider('Tune the smoothness level of the image (the higher the value, the smoother the image)', 3, 99, 5, step=2) kernel = st.sidebar.slider('Tune the sharpness of the image (the lower the value, the sharper it is)', 1, 21, 3, step =2) edge_preserve = st.sidebar.slider('Tune the color averaging effects (low: only similar colors will be smoothed, high: dissimilar color will be smoothed)', 0.0, 1.0, 0.5) gray = cv2.medianBlur(gray, kernel) edges = cv2.adaptiveThreshold(gray, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 9, 9) color = cv2.detailEnhance(img, sigma_s=smooth, sigma_r=edge_preserve) cartoon = cv2.bitwise_and(color, color, mask=edges)
if cartoon == "Pencil Edges": kernel = st.sidebar.slider('Tune the sharpness of the sketch (the lower the value, the sharper it is)', 1, 99, 25, step=2) laplacian_filter = st.sidebar.slider('Tune the edge detection power (the higher the value, the more powerful it is)', 3, 9, 3, step =2) noise_reduction = st.sidebar.slider('Tune the noise effects of your sketch (the higher the value, the noisier it is)', 10, 255, 150) gray = cv2.medianBlur(gray, kernel) edges = cv2.Laplacian(gray, -1, ksize=laplacian_filter)
edges_inv = 255-edges dummy, cartoon = cv2.threshold(edges_inv, noise_reduction, 255, cv2.THRESH_BINARY)
if cartoon == "Bilateral Filter": smooth = st.sidebar.slider('Tune the smoothness level of the image (the higher the value, the smoother the image)', 3, 99, 5, step=2) kernel = st.sidebar.slider('Tune the sharpness of the image (the lower the value, the sharper it is)', 1, 21, 3, step =2) edge_preserve = st.sidebar.slider('Tune the color averaging effects (low: only similar colors will be smoothed, high: dissimilar color will be smoothed)', 1, 100, 50) gray = cv2.medianBlur(gray, kernel) edges = cv2.adaptiveThreshold(gray, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 9, 9) color = cv2.bilateralFilter(img, smooth, edge_preserve, smooth) cartoon = cv2.bitwise_and(color, color, mask=edges)
return cartoon
############################################################################### st.write(""" # Cartoonize Your Image!
""" )
st.write("This is an app to turn your photos into cartoon")
file = st.sidebar.file_uploader("Please upload an image file", type=["jpg", "png"])
if file is None: st.text("You haven't uploaded an image file")else: image = Image.open(file) img = np.array(image) option = st.sidebar.selectbox( 'Which cartoon filters would you like to apply?', ('Pencil Sketch', 'Detail Enhancement', 'Pencil Edges', 'Bilateral Filter')) st.text("Your original image") st.image(image, use_column_width=True) st.text("Your cartoonized image") cartoon = cartoonization(img, option) st.image(cartoon, use_column_width=True)

现在,可以打开提示符,然后转到包含上面代码的Python文件的工作目录。接下来,您需要使用以下命令运行代码。

streamlit run your_app_name.py

最后,您可以在本地计算机上使用图像卡通化Web应用程序!以下是该网络应用程序的示例。

该网络应用程序示例

部署Web应用

本节是可选的,但是如果小伙伴需要部署Web应用程序以便其他人也可以访问您的Web应用程序,则可以使用Heroku部署Web应用程序。

要将Web应用程序部署到Heroku,首先要免费创建一个Heroku帐户,然后下载Heroku CLI。

接下来需要在与Python文件相同的目录中创建四个其他文件,它们是:

· requirements.txt:这是文本文件,用于告诉Heroku构建Web应用程序需要哪些依赖项。因为在我们的web应用程序,我们使用四种不同的库:opencv,numpy,Pillow,和streamlit,那么我们就可以写所有这些库及其版本为requirements.txt的

opencv-python==4.3.0.36streamlit==0.63.0Pillow==7.0.0numpy==1.18.1

· setup.sh:这是用于在Heroku上设置配置的文件。为此setup.sh文件编写以下内容。

mkdir -p ~/.streamlit/ echo "\ [server]\n\ headless = true\n\ port = $PORT\n\ enableCORS = false\n\ \n\ " > ~/.streamlit/config.toml

· Procfile:这是告诉Heroku哪些文件以及应如何执行文件的文件。为Procfile编写以下内容。

web: sh setup.sh && streamlit run cartoon_app.py

· Aptfile:这是Heroku 构建包的文件,以使OpenCV能够在Heroku中运行。为Aptfile编写以下内容。

libsm6 libxrender1 libfontconfig1 libice6

接下来,打开命令提示符,然后转到Python文件和这四个其他文件的工作目录。在其中键入heroku login命令,以便您登录到Heroku帐户。

现在,您可以通过键入来创建新应用heroku create your-app-name。为确保您位于新创建的应用程序内部,请键入以下内容:

heroku git:remote -a your-app-name

接下来,我们需要在新创建的应用程序中添加一个buildpack,以使OpenCV能够在Heroku上运行。要添加必要的buildpack,请在Heroku CLI上键入以下内容。

heroku create --buildpack https://github.com/heroku/heroku-buildpack-apt.git

现在设置好了。接下来,您需要通过打字来初始化一个空的git git init其次是git add .,git commit和git push heroku master命令。

git initgit add .git commit -m "Add your messages"git push heroku master

之后,部署过程就开始了,并且可能需要一些时间来等待此部署过程。最后,Heroku将生成新部署的Web应用程序的URL。

就是这样!现在,我们已经构建了自己的图像卡通化Web应用程序,该应用程序模仿了Adobe Lightroom的功能。

交流群

(0)

相关推荐

  • OpenCV-Python,计算机视觉开发利器

    人工智能,一个已经被谈论了几十年的概念(最早是图灵在1950年提出).如今这几年,相关技术的发展速度是越来越快.高大上如无人驾驶.智能安防.AI辅助诊断,接地气如刷脸支付.内容推荐.自动翻译等,众多领 ...

  • python+opencv图像处理(二)

    python+opencv图像处理(二) ----图像变换 自然界中有很多的颜色,红红的花,绿绿的草,蓝蓝的天,白白的云,多姿多彩的世界,美轮美奂的图像. 通过手机,照相机就可以定格每一个美的瞬间. ...

  • 图像自适应二值化方法---迭代阈值法

    通过迭代方法选择阈值, 计算方法如下: (1)选择灰度图的平均值作为初始阈值T0 ; (2)计算小于等于T0的平均值T1, 和大于T0的平均值T2; (3)新的阈值为T = (T1 + T2)/ 2; ...

  • Python|加权平均法读取灰度化图像介

    问题描述灰度化的原理时假定每个像素点的三通道值相同,并用统一的灰度值待代替.加权平均法读取灰度化图像时,是将三个通道的通道值进行加权,然后用来代替灰度.实际中加权平均法RGB灰度化的公式为: 式中表示 ...

  • 基于Opencv的图像单应性转换实战

    重磅干货,第一时间送达 同形转换 我们所常见的都是以这样的方式来处理图像:检测斑点,分割感兴趣的对象等.我们如何将它们从一种形式转换为另一种形式来处理这些图像呢?通过单应矩阵快速转换图像可以实现这个需 ...

  • 基于OpenCV的图像翻转和镜像

    点击上方"小白学视觉",选择加"星标"或"置顶" 重磅干货,第一时间送达 本期,我们将解释如何在Python中实现图像的镜像或翻转.大家只需 ...

  • 基于OpenCV的图像强度操作

    重磅干货,第一时间送达 01. 什么是图像强度操作 更改任何通道中的像素值 对图像的数学运算 亮度变化 对比度变化 伽玛操纵 直方图均衡 图像预处理中的滤波等增强 使用OpenCV加载图像 impor ...

  • 基于OpenCV的图像融合

    重磅干货,第一时间送达 本期我们将一起学习如何使用OpenCV的进行图像拼接. 01. 目录 python 入门 步骤1 -图像导入 步骤2-调整图像大小 步骤3-融合图像 步骤4-导出结果 02. ...

  • 基于OpenCV的图像阴影去除

    重磅干货,第一时间送达 我们经常需要通过扫描将纸上的全部内容转换为图像.有很多在线工具可以提高图像的亮度,或者消除图像中的阴影.但是我们可以手动删除阴影吗?当然可以,我们只需要将图像加载到相应的代码中 ...

  • 基于OpenCV实战:绘制图像轮廓(附代码)

    重磅干货,第一时间送达 山区和地形图中海拔高的区域划出的线称为地形轮廓,它们提供了地形的高程图.这些线条可以手动绘制,也可以由计算机生成.在本文中,我们将看到如何使用OpenCV在简单图像上绘制轮廓线 ...

  • 大华网络视频监控图像卡顿分析思路和案例总结

    一.理清楚视频卡顿分析思路 1.IPC设备跟电脑直连都卡顿(排除网线和电脑问题)用VLC和WEB,SDK测试DEMO都验证过卡顿.那后续就不用排查其它问题,直接联系研发进行问题处理. 2.直连测试正常 ...

  • 如何使用OpenCV实现图像均衡???

    重磅干货,第一时间送达 我们已经练习了很多图像处理--操作图像(精确地说是图像矩阵).为此,我们探索了图像的均衡方法,以便在一定程度上增强对比度,以使被处理的图像看起来比原始图像更好,这种技术称为直方 ...

  • 基于OpenCV实战:车牌检测

    重磅干货,第一时间送达 拥有思维导图或流程将引导我们朝着探索和寻找实现目标的正确道路的方向发展.如果要给我一张图片,我们如何找到车牌并提取文字? 一般思维步骤: 识别输入数据是图像. 扫描图像以查看由 ...