天天看點

用python畫雪花飄落_故宮下雪了!我花了45秒,用Python給它畫了一組手繪圖

原标題:故宮下雪了!我花了45秒,用Python給它畫了一組手繪圖

作者:戀習Python / 丁彥軍 (本文來自作者投稿)

這幾天,許多城市,迎來了2019年的第一場雪

13日早晨,當北京市民拉開窗簾時發現,窗外雪花紛紛揚揚在空中飄落

而且越下越大,樹上、草地、屋頂、道路上...都落滿雪花

京城銀裝素裹,這是今冬以來北京迎來的第二場降雪

一下雪,北京就變成了北平,故宮就變成了紫禁城

八萬張門票在雪花飄下來之前,便早已預訂一空

看着朋友圈、微網誌好友都在紛紛曬圖,小編隻能羨慕不已。

不過,戀習Python突然想到,可以通過Python将故宮的建築物圖檔,轉化為手繪圖(素描效果)。效果圖如下:

用python畫雪花飄落_故宮下雪了!我花了45秒,用Python給它畫了一組手繪圖

一、概念與原理

我們都知道手繪圖效果的特征主要有:

黑白灰色;邊界線條較重;相同或相近色彩趨于白色;略有光源效果

核心原理:利用像素之間的梯度值和虛拟深度值對圖像進行重構,根據灰階變化來模拟人類視覺的模拟程度

把圖像看成二維離散函數,灰階梯度其實就是這個二維離散函數的求導,用差分代替微分,求取圖像的灰階梯度。常用的一些灰階梯度模闆有:Roberts 梯度、Sobel 梯度、Prewitt 梯度、Laplacian 梯度。

以Sobel 梯度計算來解釋:

首先計算出、,然後計算梯度角

梯度方向及圖像灰階增大的方向,其中梯度方向的梯度夾角大于平坦區域的梯度夾角。如下圖所示,灰階值增加的方向梯度夾角大,此時梯度夾角大的方向為梯度方向。對應在圖像中尋找某一點的梯度方向即通過計算該點與其8鄰域點的梯度角,梯度角最大即為梯度方向。

用python畫雪花飄落_故宮下雪了!我花了45秒,用Python給它畫了一組手繪圖

二、圖像的數組形式與變換

用python畫雪花飄落_故宮下雪了!我花了45秒,用Python給它畫了一組手繪圖

其中,需要用到的方法:

Image.open( ): 打開圖檔

np.array( ) : 将圖像轉化為數組

convert("L"): 将圖檔轉換成二維灰階圖檔

Image.fromarray( ): 将數組還原成圖像uint8格式

代碼如下:

fromPIL importImage

importnumpy asnp

im = Image.open( r"C:UsersAdministratorDesktopgugong微信圖檔_20190216152248.jpg").convert( 'L')

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

print(a.shape,a.dtype)

( 1080, 608) float64

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

三、圖像的手繪效果處理

實作思路步驟:

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

建立光源對各點梯度值的影響函數

運算出各點的新像素值

用python畫雪花飄落_故宮下雪了!我花了45秒,用Python給它畫了一組手繪圖

其中:

np.cos(evc.el) : 機關光線在地平面上的投射長度

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

3、梯度歸一化

構造x和y軸梯度的三維歸一化機關坐标系;

梯度與光源互相作用,将梯度轉化為灰階。

4、圖像生成

具體詳情代碼如下:

fromPIL importImage

importnumpy asnp

importos

importjoin

importtime

defimage(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)

defmain():

xs= 10

start_time = time.clock()

startss = os.listdir( r"C:UsersAdministratorDesktopgugong")

time.sleep( 2)

forstarts instartss:

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畫雪花飄落_故宮下雪了!我花了45秒,用Python給它畫了一組手繪圖

其他圖檔就不一一列舉;你也可以通過此代碼為自己畫一張手繪圖;也可以為自己的家鄉或母校畫。

參考資料:北京理工大學的嵩天老師的網絡課程

http://www.icourse163.org/learn/BIT-1001870002?tid=1001963001#/learn/announce

【本文作者】

丁彥軍:一名癡戀于 Python 的碼農,個人公号:「戀習Python」,在這裡我們一起用Python 做些有意義的事。

(點選标題可跳轉閱讀)傳回搜狐,檢視更多

責任編輯: