首页
学习
活动
专区
工具
TVP
发布

故宫下雪了!我用Python给它画了一组手绘图,仅用45秒

来源:恋习Python

本文约1300字,建议阅读7分钟

本文介绍图像处理的基本概念与原理,并手把手教你图片的手绘效果处理。

这几天,许多城市,迎来了2019年的第一场雪。

13日早晨,当北京市民拉开窗帘时发现,窗外雪花纷纷扬扬在空中飘落

而且越下越大,树上、草地、屋顶、道路上...都落满雪花

京城银装素裹,这是今冬以来北京迎来的第二场降雪

一下雪,北京就变成了北平,故宫就变成了紫禁城

八万张门票在雪花飘下来之前,便早已预订一空。

看着朋友圈、微博好友都在纷纷晒图,小编只能羡慕不已。

不过,我们突然想到,可以通过Python将故宫的建筑物图片,转化为手绘图(素描效果)。效果图如下:

一、概念与原理

我们都知道手绘图效果的特征主要有:

黑白灰色;

边界线条较重;

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

略有光源效果。

核心原理:利用像素之间的梯度值虚拟深度值对图像进行重构,根据灰度变化来模拟人类视觉的模拟程度。

把图像看成二维离散函数,灰度梯度其实就是这个二维离散函数的求导,用差分代替微分,求取图像的灰度梯度。常用的一些灰度梯度模板有:Roberts 梯度、Sobel 梯度、Prewitt 梯度、Laplacian 梯度。

以Sobel梯度计算来解释:

首先计算出、,然后计算梯度角梯度方向及图像灰度增大的方向,其中梯度方向的梯度夹角大于平坦区域的梯度夹角。如下图所示,灰度值增加的方向梯度夹角大,此时梯度夹角大的方向为梯度方向。对应在图像中寻找某一点的梯度方向即通过计算该点与其8邻域点的梯度角,梯度角最大即为梯度方向。

二、图像的数组形式与变换

其中,需要用到的方法:

Image.open( ):打开图片

np.array( ) :将图像转化为数组

convert("L"):将图片转换成二维灰度图片

Image.fromarray( ):将数组还原成图像uint8格式

代码如下:

from PIL import Image

import numpy as np

im = Image.open(r"C:\Users\Administrator\Desktop\gugong\微信图片_20190216152248.jpg").convert('L')

a=np.asarray(im).astype('float')

print(a.shape,a.dtype)

(1080, 608) float64

#(1080, 608)分别表示高度,宽度

三、图像的手绘效果处理

实现思路步骤:

梯度的重构

构造guan光源效果

梯度归一化

图像生成

1. 梯度的重构

numpy的梯度函数的介绍:

np.gradient(a) :计算数组a中元素的梯度,f为多维时,返回每个维度的梯度

离散梯度:xy坐标轴连续三个x轴坐标对应的y轴值:a, b, c 其中b的梯度是(c-a)/2 ,而c的梯度是: (c-b)/1

当为二维数组时,np.gradient(a) 得出两个数组,第一个数组对应最外层维度的梯度,第二个数组对应第二层维度的梯度。

代码如下:

grad=np.gradient(a)

grad_x,grad_y=grad

grad_x = grad_x * depth / 100.#对grad_x值进行归一化

grad_y = grad_y * depth / 100.#对grad_y值进行归一化

2.构造guan光源效果

设计一个位于图像斜上方的虚拟光源

光源相对于图像的视角为Elevation,方位角为Azimuth

建立光源对各点梯度值的影响函数

运算出各点的新像素值

其中:

np.cos(evc.el) :单位光线在地平面上的投射长度

dx,dy,dz:光源对x,y,z三方向的影响程度

3. 梯度归一化

构造x和y轴梯度的三维归一化单位坐标系;

梯度与光源相互作用,将梯度转化为灰度。

4. 图像生成

具体详情代码如下:

from PIL import Image

import numpy as np

import os

import join

import time

def image(sta,end,depths=10):

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

depth = depths # 深度的取值范围(0-100),标准取10

grad = np.gradient(a) # 取图像灰度的梯度值

grad_x, grad_y = grad # 分别取横纵图像梯度值

grad_x = grad_x * depth / 100.#对grad_x值进行归一化

grad_y = grad_y * depth / 100.#对grad_y值进行归一化

A = np.sqrt(grad_x ** 2 + grad_y ** 2 + 1.)

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) # 光源对x 轴的影响

dy = np.cos(vec_el) * np.sin(vec_az) # 光源对y 轴的影响

dz = np.sin(vec_el) # 光源对z 轴的影响

b = 255 * (dx * uni_x + dy * uni_y + dz * uni_z) # 光源归一化

b = b.clip(0, 255)

im = Image.fromarray(b.astype('uint8')) # 重构图像

im.save(end)

def main():

xs=10

start_time = time.clock()

startss = os.listdir(r"C:\Users\Administrator\Desktop\gugong")

time.sleep(2)

for starts in startss:

start = ''.join(starts)

sta = 'C:/Users/Administrator/Desktop/gugong/' + start

end = 'C:/Users/Administrator/Desktop/gugong/' + 'HD_' + start

image(sta=sta,end=end,depths=xs)

end_time = time.clock()

print('程序运行了 ----' + str(end_time - start_time) + ' 秒')

time.sleep(3)

main()

程序运行了 ----43.01828205879955 秒 #一共35张图片

最终效果图对比:

最后温馨提示:

人生苦短,我用Python;

除了生娃,啥都能干!!

欢迎大家在留言处,留言自己曾经用Python做过哪些有意思的事!

参考资料

北京理工大学的嵩天老师的网络课程

编辑:黄继彦

校对:陈瑞清

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20190220A13IRE00?refer=cp_1026
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券