用Python制作一盞 3D 花燈,喜迎元宵佳節


前言

本文的文字及圖片來源於網絡,僅供學習、交流使用,不具有任何商業用途,如有問題請及時聯系我們以作處理。

PS:如有需要Python學習資料的小伙伴可以點擊下方鏈接自行獲取

Python免費學習資料、代碼以及交流解答點擊即可加入


 

說起元宵節,各位有沒有覺得這是咱們中國人最浪漫的節日呢?國人向來拘謹古板,一年到頭都是小心謹慎地過日子,唯有元宵節這天可以縱情豪放一把。東風夜放花千樹,寶馬雕車香滿路,火樹銀花霓虹閃爍,豪車遍地美女如雲。細品,你甚至都能嗅到香奈兒的味道!月上柳梢頭,人約黃昏后,這又是何等的浪漫!比起燭光晚宴、鮮花加持,這份浪漫更顯純真。晚至明清,民間元宵節的喜慶氣氛,堪比西班牙的奔牛節、巴西的狂歡節、泰國的潑水節。

由於眾所周知的原因,估計今年的趵突泉元宵節燈會又要黃了。去哪兒體驗“花市燈如晝”的節日氣氛呢?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-')


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM