使用Python制作一盞 3D 花燈喜迎元宵佳節
說起元宵節,各位有沒有覺得這是咱們中國人最浪漫的節日呢?國人向來拘謹古板,一年到頭都是小心謹慎地過日子,唯有元宵節這天可以縱情豪放一把。東風夜放花千樹,寶馬雕車香滿路,火樹銀花霓虹閃爍,豪車遍地美女如雲。細品,你甚至都能嗅到香奈兒的味道!月上柳梢頭,人約黃昏後,這又是何等的浪漫!比起燭光晚宴、鮮花加持,這份浪漫更顯純真。晚至明清,民間元宵節的喜慶氣氛,堪比西班牙的奔牛節、巴西的狂歡節、泰國的潑水節。
由於眾所周知的原因,估計今年的趵突泉元宵節燈會又要黃瞭。去哪兒體驗“花市燈如晝”的節日氣氛呢?Don’t worry,沒有什麼事能夠難倒程序員——用3D技術也可以做出下圖這樣的走馬燈,算是聊勝於無吧。
1.原材料
花燈紙
如下所示,還可以加上自己喜歡的圖案、文字等。
Python環境和模塊
一臺安裝瞭Python環境的電腦,Python環境需要安裝以下模塊。
- numpy
- pillow
- wxgl
如果沒有上述模塊,請參考下面的命令安裝。
pip install numpy pip install pillow pip install wxgl
NumPy和 pillow 是 Python 旗下最常用的科學計算庫和圖像處理庫,屬於常用模塊。WxGL 是一個基於 PyOpenGL 的三維數據可視化庫,以 wx 為顯示後端,提供 Matplotlib 風格的交互式應用模式,同時,也可以和 wxPython 無縫結合,在wx的窗體上繪制三維模型。
2.制作工序
花燈制作工序非常簡單,隻需要三十行代碼,可以直接在Python IDLE中以交互方式逐行執行。
導入模塊
>>> import numpy as np >>> from PIL import Image >>> import wxgl.wxplot as plt
打開花燈紙圖像
>>> fn = r'D:\temp\light0115\res\paper.png' >>> im = np.array(Image.open(fn))/255 >>> im.shape (400, 942, 3)
fn定義的是圖像存儲路徑,請據實修改。Image.open(fn)打開文件,返回一個PIL對象,np.array()將PIL對象轉成numpy.ndarray數組對象。除以255,將圖像數據從0到255的值域范圍變成0到1,適應WxGL的接口要求。查看數組的shape,顯示圖像分辨率為400像素高、942像素寬,每個像素有三種顏色(此處為RGB)。
根據花燈紙的大小制作龍骨
紙長942像素,卷成圓筒,半徑就是149.9像素,如果把半徑視為1個單位,則高度400像素相當於2.668個單位。
>>> rows, cols, deep = im.shape >>> cols/(2*np.pi) 149.9239563925654 >>> r = 1 >>> h = 2*np.pi*rows/cols >>> h 2.6680192387174464
接下來需要制作半徑1個單位、高度2.668個單位的圓筒狀龍骨瞭。
>>> theta = np.linspace(0, 2*np.pi, cols) >>> x = r * np.cos(theta) >>> y = r * np.sin(theta) >>> z = np.linspace(0, h, rows) >>> xs = np.tile(x, (rows,1)) >>> ys = np.tile(y, (rows,1)) >>> zs = z.repeat(cols).reshape((rows,cols))
這裡的xs、ys、zs就是圓筒狀龍骨上各個點的x坐標、y坐標、z坐標。下面的代碼,每隔10個點抽取1個點,用mesh的方法畫出龍骨形狀。當然,也可以畫出全部的點,那樣頂點就會連成一片。
>>> plt.mesh(xs[::10,::10], ys[::10,::10], zs[::10,::10], mode='FLBL') >>> plt.show()
用3D的方式畫出來的龍骨,效果如下。
給龍骨貼上花燈紙
有瞭龍骨,接下來就可以把花燈紙貼在龍骨上瞭。繼續操作之前,記得先把剛才彈出的3D龍骨窗口關閉。
>>> plt.mesh(xs, ys, zs, im) >>> plt.show()
不過,你會立刻發現,花燈紙上下方向貼反瞭。沒關系,我們可以像下面這樣反轉方向。
>>> plt.mesh(xs, ys, zs, im[::-1]) >>> plt.show()
怎麼樣,是不是有一點走馬燈的雛形瞭呢?
制作旋轉葉輪
走馬燈之所以能夠轉動,是因為裡面有蠟燭加熱形成上升氣流,推動頂部的葉輪旋轉,從而帶動花燈旋轉。當然,這裡的葉輪僅僅是個樣子,花燈旋轉依賴另外的機制實現。
>>> theta = np.linspace(0, 2*np.pi, 18, endpoint=False) >>> x = r * np.cos(theta) >>> y = r * np.sin(theta) >>> x[2::3] = x[1::3] >>> x[1::3] = 0 >>> y[2::3] = y[1::3] >>> y[1::3] = 0 >>> z = np.ones(18) * h * 0.9 >>> vs = np.stack((x,y,z), axis=1) >>> plt.mesh(xs, ys, zs, im[::-1]) >>> plt.surface(vs, color='#C03000', method='T', mode='FCBC', alpha=0.8) >>> plt.show()
葉輪設計有6片,用三角形模擬,顏色深紅,透明度0.8,整體效果略顯粗糙瞭一點。
加上照明燈和提系
照明燈用一個白色的圓球表示,提系則是紅色的一條直線,兼做照明燈的電源線。
>>> plt.mesh(xs, ys, zs, im[::-1]) >>> plt.surface(vs, color='#C03000', method='T', mode='FCBC', alpha=0.8) >>> plt.sphere((0,0,h*0.4), 0.4, '#FFFFFF', slices=60, mode='FCBC') >>> plt.plot((0,0), (0,0), (0.4*h, 1.5*h), width=3.0, style='solid', cmap='hsv', caxis='z')
讓花燈轉起來
花燈旋轉的實現非常簡單,隻需要給show方法一個rotation參數就可以。
plt.show(rotation='h-')
最終的花燈效果如下。
3.完整代碼
# -*- coding: utf-8 -*- import numpy as np from PIL import Image import wxgl.wxplot as plt im = np.array(Image.open('res/paper.png'))/255 rows, cols, deep = im.shape r, h = 1, 2*np.pi*rows/cols theta = np.linspace(0, 2*np.pi, cols) x = r*np.cos(theta) y = r*np.sin(theta) z = np.linspace(0, h, rows) xs = np.tile(x, (rows,1)) ys = np.tile(y, (rows,1)) zs = z.repeat(cols).reshape((rows,cols)) theta = np.linspace(0, 2*np.pi, 18, endpoint=False) x = r*np.cos(theta) y = r*np.sin(theta) x[2::3] = x[1::3] x[1::3] = 0 y[2::3] = y[1::3] y[1::3] = 0 z = np.ones(18) * h * 0.9 vs = np.stack((x,y,z), axis=1) plt.mesh(xs, ys, zs, im[::-1]) plt.surface(vs, color='#C03000', method='T', mode='FCBC', alpha=0.8) plt.sphere((0,0,h*0.4), 0.4, '#FFFFFF', slices=60, mode='FCBC') plt.plot((0,0), (0,0), (0.4*h, 1.5*h), width=3.0, style='solid', cmap='hsv', caxis='z') plt.show(rotation='h-')
到此這篇關於使用Python制作一盞 3D 花燈喜迎元宵佳節的文章就介紹到這瞭,更多相關Python制作 3D 花燈內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!
推薦閱讀:
- 使用Python NumPy庫繪制漸變圖案
- python 利用matplotlib在3D空間中繪制平面的案例
- Python opencv醫學處理的實現過程
- 利用Matlab繪制各類特殊圖形的實例代碼
- Python NumPy教程之數組的創建詳解