2023年2月

导语

最近在学python数据处理的几个常用库,分别是numpy、matplotlib和pandas。这几个库应该是python数据处理的第三方神器库,学了一招图像手绘风格处理,非常有意思,记录下来。

图像手绘风格

手绘风格示例:
WechatIMG19.jpeg

WechatIMG19HD2.jpeg

第二幅就是有手绘的感觉,当然是基于第一章图片处理得到的。手绘风格可以总结为以下几点:

  • 黑白灰色
  • 边界线条较重
  • 相邻的像素,如果是相同或者相近色彩趋于白色
  • 略有光源效果

具体如何通过程序实现呢?接下来就来逐一介绍下。

梯度的重构

利用像素之间的梯度值和虚拟深度值对图像进行重构,根据灰度变换来模拟人类视觉的明暗程度。代码如下:

import numpy as np
from PIL import Image

a = np.asarray(Image.open('xxx.jpeg').convert('L')).astype('float')

depth = 10.
grad = np.gradient(a)
grad_x, grad_y = grad
grad_x = grad_x*depth/100.
grad_y = grad_y*depth/100.

下面这行代码是通过pillow库读取原先图像,RGB值转为灰度值。

a = np.asarray(Image.open('xxx.jpeg').convert('L')).astype('float')

这几行代码是计算灰度图像的像素间梯度,并且根据虚拟深度重构梯度值,depth初始化为10,depth取值0~100。

depth = 10.
grad = np.gradient(a)
grad_x, grad_y = grad
grad_x = grad_x*depth/100.
grad_y = grad_y*depth/100.

光源效果

根据灰度变化来模拟人类视觉的远近程度。
手绘风格光源模型图.png

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

代码如下:

vec_el = np.pi/2.2                  # 光源的俯视角度,弧度值
vec_az = np.pi/4.                   # 光源的方位角度,弧度值
dx = np.cos(vec_el)*np.cos(vec_az)  # 光源对x轴的影响
dy = np.cos(vec_el)*np.sin(vec_az)  # 光源对y轴的影响
dz = np.sin(vec_el)                 # 光源对z轴的影响

A = np.sqrt(grad_x**2 + grad_y**2 + 1.)     # 光源归一化
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)

最后,对像素值进行裁剪至0~255,防止越界。

b = b.clip(0, 255)
im = Image.fromarray(b.astype('uint8'))
im.save('xxxHD.jpeg')

最后

程序虽然小,效果还是比较有意思的,我给女儿看了,她说你画画不是很丑的吗,为啥画的这么好?哈哈,我和她说,这是计算机处理的,不是我手画的,小小的年纪充满大大的问号。

其实,这里最重要的是对图像灰度值计算梯度,这是Computer Vision里面传统图像处理的关键,CV相关的技术,由于可以可视化,实现之后,还是比较有意思的。