1. 简介
人们一直以来对于艺术的追求,包括绘画,一直是人类探索的方向之一。而随着技术的发展,现在我们可以通过计算机来实现各种各样的绘画效果,从而满足人们的需求。本文主要介绍如何利用Python实现将普通图片转变为素描和漫画风格的图片。
2. Python绘图库介绍
在这个教程中,我们会使用两个Python绘图库来完成转换工作,它们分别是:
OpenCV:是一款流行的计算机视觉库,提供了各种各样的图像处理函数和模块。
Stylized-Image:是一个基于PyTorch的深度学习库,可以进行图像转换和风格转移。
3. 素描效果
3.1 准备工作
在这个部分,我们将介绍如何使用OpenCV将图片转换为素描效果的图像。
首先,我们先安装必要的库:
!pip install opencv-python-headless
!pip install opencv-contrib-python-headless
然后读入一张图片,代码如下:
import cv2
image = cv2.imread("test.jpg")
这里我们读入的图片是一张风景图片,我们将它转换成灰度图,如下所示:
gray_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
接下来,我们将使用Canny算子进行边缘提取,如下所示:
canny_output = cv2.Canny(gray_image, 100, 200)
然后再使用高斯滤波进行模糊,代码如下:
blurred = cv2.GaussianBlur(canny_output, (11, 11), 0)
最后,我们将边缘图与原图结合起来,得到绘画风格的图片:
edged = cv2.bitwise_or(blurred, canny_output)
result = cv2.bitwise_or(image, edged)
3.2 模块封装
为了方便使用,我们将上面的代码进行封装成模块,供后续使用:
import cv2
class Sketch:
def __init__(self, img_path):
self.image = cv2.imread(img_path)
def sketch(self, ksize=5, sigmaX=0, sigmaY=0):
gray_image = cv2.cvtColor(self.image, cv2.COLOR_BGR2GRAY)
# 边缘提取
canny_output = cv2.Canny(gray_image, 100, 200)
# 高斯滤波
blurred = cv2.GaussianBlur(canny_output, (ksize, ksize), sigmaX, sigmaY)
# 结合图像
edged = cv2.bitwise_or(blurred, canny_output)
result = cv2.bitwise_or(self.image, edged)
return result
这样,我们就可以轻松地使用上面的代码,生成我们的绘画风格图片了:
image_path = "test.jpg"
s = Sketch(image_path)
sketch = s.sketch()
cv2.imwrite("sketch_test.jpg", sketch)
运行上面的代码,我们可以得到以下素描风格的图片:
4. 漫画效果
4.1 准备工作
这里我们将介绍如何使用Stylized-Image模块,将图片转换为漫画效果的图像。漫画风格通常是应用一些特定的图像处理方法,例如:
边缘检测
图像平滑
颜色量化
接下来,我们将一步步地实现这个过程。
首先,我们需要安装必要的库:
!pip install torch torchvision
!pip install stylized-image
然后,我们读入一张图片:
import cv2
import numpy as np
import torch
import torchvision.transforms as transforms
from PIL import Image
from stylized_image.models import TransformerNet
image = cv2.imread("test.jpg")
image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
我们使用了PyTorch提供的transforms类,将图片转换为一个PIL类型的对象。
4.2 边缘检测
接下来,我们将使用Canny算法进行边缘检测:
gray_image = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)
edges = cv2.Canny(gray_image, 100, 200)
这里我们得到的是一个边缘检测的二值图像:
4.3 图像平滑
接下来,我们将对上面得到的二值图像进行平滑处理,使整个图像变得更加自然。
我们使用OpenCV提供的Bilateral Filter算法进行平滑处理。它能够使边缘保留得更好,同时去除噪声。
#Bilateral Filter
color = cv2.bilateralFilter(image, 9, 250, 250)
# 将颜色图像转换为灰度图像
gray = cv2.cvtColor(color, cv2.COLOR_BGR2GRAY)
# 将值域缩小为0到10之间
gray = cv2.convertScaleAbs(gray, alpha=10, beta=0)
# 将灰度图像和边缘图像通过逻辑“与”操作
cartoon = cv2.bitwise_and(gray, gray, mask=edges)
我们可以看到,处理后的图片变得更加平滑和自然:
4.4 颜色量化
最后,我们将对上面得到的图像进行颜色量化。这里我们使用Python中的Pillow模块,将图像的颜色数量限制到10种左右。
# 转换为Pillow图片
cartoon = Image.fromarray(cartoon)
# 定义色板
color_palette = Image.new('P', (1, 1))
color_palette.putpalette(np.array([
0, 0, 0,
63, 31, 31,
94, 47, 47,
127, 63, 63,
159, 79, 79,
191, 95, 95,
223, 111, 111,
255, 127, 127,
223, 159, 159,
255, 223, 223,
]).astype('uint8'))
# 重新调整图片大小
cartoon = cartoon.quantize(colors=10, palette=color_palette)
# 转换为OpenCV格式图片
cartoon = cv2.cvtColor(np.asarray(cartoon), cv2.COLOR_RGB2BGR)
处理后的图片:
4.5 模块封装
为了方便使用,我们将上述代码进行封装成模块:
import cv2
import numpy as np
import torch
import torchvision.transforms as transforms
from PIL import Image
from stylized_image.models import TransformerNet
class Cartoonify:
def __init__(self, img_path):
self.image = cv2.imread(img_path)
self.net = self.load_network('https://www.dropbox.com/s/w463to8he8b3w4g/mosaic.pth?dl=1')
def load_network(self, url):
state_dict = torch.utils.model_zoo.load_url(url)
net = TransformerNet()
net.load_state_dict(state_dict)
return net.eval().cuda()
def cartoonify(self):
# 边缘检测
gray_image = cv2.cvtColor(self.image, cv2.COLOR_BGR2GRAY)
edges = cv2.Canny(gray_image, 100, 200)
# 平滑处理
color = cv2.bilateralFilter(self.image, 9, 250, 250)
gray = cv2.cvtColor(color, cv2.COLOR_BGR2GRAY)
gray = cv2.convertScaleAbs(gray, alpha=10, beta=0)
cartoon = cv2.bitwise_and(gray, gray, mask=edges)
# 颜色量化
cartoon = Image.fromarray(cartoon)
color_palette = Image.new('P', (1, 1))
color_palette.putpalette(np.array([
0, 0, 0,
63, 31, 31,
94, 47, 47,
127, 63, 63,
159, 79, 79,
191, 95, 95,
223, 111, 111,
255, 127, 127,
223, 159, 159,
255, 223, 223,
]).astype('uint8'))
cartoon = cartoon.quantize(colors=10, palette=color_palette)
cartoon = cv2.cvtColor(np.asarray(cartoon), cv2.COLOR_RGB2BGR)
return cartoon
使用上面封装好的模块,我们可以轻松地将我们的图片转换为漫画效果:
image_path = "test.jpg"
c = Cartoonify(image_path)
cartoon = c.cartoonify()
cv2.imwrite("cartoon_test.jpg", cartoon)
运行上面的代码,我们可以得到以下漫画风格的图片:
总结
本文主要介绍如何利用Python实现将普通图片转变为素描和漫画风格的图片。其中,我们使用了OpenCV和Stylized-Image两个Python绘图库,分别实现素描风格和漫画风格转换。同时,我们还封装了两个模块,使得转换过程更加简单和方便。