从今天开始,我将在本博客分享基于Python的数据科学案例,从基础的第三方库调用到一系列案例,来与大家一同分享Python与数据科学的魅力。今天的第一个案例是基于培养Python语言实现一个图像的手绘效果,是对PIL库和numpy库的一次基本应用。

图像的数组表示

图像的RGB色彩模式

图像一般使用RGB色彩模式,即每个像素点的颜色由红(R)、绿(G)、蓝(B)组成

RGB三个颜色通道的变化和叠加得到各种颜色,其中

• R 红色,取值范围,0‐255

• G 绿色,取值范围,0‐255

• B 蓝色,取值范围,0‐255

RGB形成的颜色包括了人类视力所能感知的所有颜色。

PIL库

PIL, Python Image Library

PIL库是一个具有强大图像处理能力的第三方库

在命令行下的安装方法: pip install pillow

1
from PIL import Image

Image是PIL库中代表一个图像的类(对象)

图像的数组表示

RGB值: (R, G, B)

图像是一个由像素组成的二维矩阵,每个元素是一个RGB值

1
2
3
4
5
from PIL import Image
import numpy as np
im=np.array(Image.open("D:/pycodes/beijing.jpg"))
print(im.shape,im.dtype)
(669,1012,3)uint8

图像是一个三维数组,维度分别是高度、宽度和像素RGB值

图像的变换

读入图像后,获得像素RGB值,修改后保存为新的文件

1565449754800

1
2
3
4
5
6
7
8
from PIL import Image
import numpy as np
a=np.array(Image.open("D:/pycodes/beijing.jpg"))
print(a.shape,a.dtype)
(669,1012,3)uint8
b=[255,255,255]-a
im=Image.fromarray(b.astype('uint8'))
im.save("D:/pycodes/beijing2.jpg")
1
2
3
4
5
6
7
#灰度变换案例,效果如下所示
from PIL import Image
import numpy as np
a=np.array(Image.open("D:/pycodes/beijing.jpg").convert('L'))
b=255-a
im=Image.fromarray(b.astype('uint8'))
im.save("D:/pycodes/beijing3.jpg")

1565449942001

1
2
3
4
5
6
7
#区间变换案例,效果如下所示
from PIL import Image
import numpy as np
a=np.array(Image.open("D:/pycodes/beijing.jpg").convert('L'))
b=(100/255)*a+150
im=Image.fromarray(b.astype('uint8'))
im.save("D:/pycodes/beijing4.jpg")

1565450010267

1
2
3
4
5
6
7
#像素平方变换案例,效果如下所示
from PIL import Image
import numpy as np
a=np.array(Image.open("D:/pycodes/beijing.jpg").convert('L'))
b=255*(a/255)**2
im=Image.fromarray(b.astype('uint8'))
im.save("D:/pycodes/beijing5.jpg")

1565450057566

图像的手绘效果 - 实例分析

1565450106375

为了实现手绘效果变换,我们首先要观察手绘效果图,其特点如下:

• 黑白灰色

• 边界线条较重

• 相同或相近色彩趋于白色

• 略有光源效果

因此我们应该在接下来的变换中实现这样的效果特点。

源代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
from PIL import Image
import numpy as np
a=np.asarray(Image.open('D:/pycodes/beijing.jpg').convert('L')).astype('float')
depth=10. #预设深度值为10,取值范围为0-100
grad=np.gradient(a) #取图像灰度的梯度值
grad_x,grad_y=grad #提取x、y方向的梯度值
grad_x=grad_x*depth/100.
grad_y=grad_y*depth/100. #根据深度调整x和y的梯度值
A=np.sqrt(grad_x**2+grad_y**2+1.) #构造x和y轴梯度的三维归一化三维坐标系
uni_x=grad_x/A
uni_y=grad_y/A
uni_z=1./A
vec_el=np.pi/2.2 #光源俯视角度的弧度值
vec_az=np.pi/4. #光源方位角度的弧度值
dx=np.cos(vec_el)*np.cos(vec_az) #np.cos(vec_el)为单位光线在地平面上投影长度
dy=np.cos(vec_el)*np.sin(vec_az)
dz=np.sin(vec_el) #dx、dy、dz是光源对x、y、z方向的影响程度
b=255*(dx*uni_x+dy*uni_y+dz*uni_z) #光源归一化,梯度与光源相互作用,将梯度转化为灰度
b=b.clip(0,255) #为了避免数据越界,将生成的灰度值裁剪到0-255区间
im=Image.fromarray(b.astype('uint8'))
im.save('./beijingHD.jpg') #生成图像

梯度的重构

利用像素之间的梯度值和虚拟深度值对图像进行重构,根据灰度变化来模拟人类视觉的远近程度

1
2
3
4
5
depth=10.	#预设深度值为10,取值范围为0-100
grad=np.gradient(a)
grad_x,grad_y=grad #提取x、y方向的梯度值
grad_x=grad_x*depth/100.
grad_y=grad_y*depth/100. #根据深度调整x和y的梯度值

光源效果

根据灰度变化来模拟人类视觉的远近程度

1565450474748• 设计一个位于图像斜上方的虚拟光源→光源相对于图像的俯视角为Elevation,方位角为Azimuth→建立光源对个点梯度值的影响函数→运算出各点的新像素值

1
2
3
4
5
vec_el=np.pi/2.2
vec_az=np.pi/4.
dx=np.cos(vec_el)*np.cos(vec_az) #np.cos(vec_el)为单位光线在地平面上投影长度
dy=np.cos(vec_el)*np.sin(vec_az)
dz=np.sin(vec_el) #dx、dy、dz是光源对x、y、z方向的影响程度

梯度归一化

1
2
3
4
5
A=np.sqrt(grad_x**2+grad_y**2+1.)	#构造x和y轴梯度的三维归一化三维坐标系
uni_x=grad_x/A
uni_y=grad_y/A
uni_z=1./A
b=255*(dx*uni_x+dy*uni_y+dz*uni_z) #梯度与光源相互作用,将梯度转化为灰度

图像生成

1
2
3
b=b.clip(0,255)	#为了避免数据越界,将生成的灰度值裁剪到0-255区间
im=Image.fromarray(b.astype('uint8'))
im.save('./beijingHD.jpg') #生成图像

本实例源代码下载

点击此处下载源代码.