元宵节

首页 » 常识 » 诊断 » 元宵节到了,手把手教你用Python打造
TUhjnbcbe - 2024/12/25 17:25:00

1前言

说起元宵节,各位有没有觉得这是咱们中国人最浪漫的节日呢?国人向来拘谨古板,一年到头都是小心谨慎地过日子,唯有元宵节这天可以纵情豪放一把。东风夜放花千树,宝马雕车香满路,火树银花霓虹闪烁,豪车遍地美女如云。细品,你甚至都能嗅到香奈儿的味道!月上柳梢头,人约黄昏后,这又是何等的浪漫!比起烛光晚宴、鲜花加持,这份浪漫更显纯真。晚至明清,民间元宵节的喜庆气氛,堪比西班牙的奔牛节、巴西的狂欢节、泰国的泼水节。

由于众所周知的原因,估计今年的趵突泉元宵节灯会又要黄了。去哪儿体验“花市灯如昼”的节日气氛呢?Dontworry,没有什么事能够难倒程序员——用3D技术也可以做出下图这样的走马灯,算是聊胜于无吧。

2原材料

2.1花灯纸

如下所示,还可以加上自己喜欢的图案、文字等。

2.2Python环境和模块

一台安装了Python环境的电脑,Python环境需要安装以下模块。

numpypillowwxgl如果没有上述模块,请参考下面的命令安装。

pipinstallnumpy

pipinstallpillow

pipinstallwxgl

NumPy和pillow是Python旗下最常用的科学计算库和图像处理库,属于常用模块。WxGL是一个基于PyOpenGL的三维数据可视化库,以wx为显示后端,提供Matplotlib风格的交互式应用模式,同时,也可以和wxPython无缝结合,在wx的窗体上绘制三维模型。关于WxGL的更多信息,请参阅我的另一篇博客《十分钟玩转3D绘图:WxGL完全手册》。

3制作工序

花灯制作工序非常简单,只需要三十行代码,可以直接在PythonIDLE中以交互方式逐行执行。

3.1导入模块

importnumpyasnp

fromPILimportImage

importwxgl.wxplotasplt

3.2打开花灯纸图像

fn=rD:\temp\light\res\paper.png

im=np.array(Image.open(fn))/

im.shape

(,,3)

fn定义的是图像存储路径,请据实修改。Image.open(fn)打开文件,返回一个PIL对象,np.array()将PIL对象转成numpy.ndarray数组对象。除以,将图像数据从0到的值域范围变成0到1,适应WxGL的接口要求。查看数组的shape,显示图像分辨率为像素高、像素宽,每个像素有三种颜色(此处为RGB)。

3.3根据花灯纸的大小制作龙骨

纸长像素,卷成圆筒,半径就是.9像素,如果把半径视为1个单位,则高度像素相当于2.个单位。

rows,cols,deep=im.shape

cols/(2*np.pi)

.4

r=1

h=2*np.pi*rows/cols

h

2.019238717

接下来需要制作半径1个单位、高度2.个单位的圆筒状龙骨了。

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的方式画出来的龙骨,效果如下。

3.4给龙骨贴上花灯纸

有了龙骨,接下来就可以把花灯纸贴在龙骨上了。继续操作之前,记得先把刚才弹出的3D龙骨窗口关闭。

plt.mesh(xs,ys,zs,im)

plt.show()

不过,你会立刻发现,花灯纸上下方向贴反了。没关系,我们可以像下面这样反转方向。

plt.mesh(xs,ys,zs,im[::-1])

plt.show()

怎么样,是不是有一点走马灯的雏形了呢?

3.5制作旋转叶轮

走马灯之所以能够转动,是因为里面有蜡烛加热形成上升气流,推动顶部的叶轮旋转,从而带动花灯旋转。当然,这里的叶轮仅仅是个样子,花灯旋转依赖另外的机制实现。

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=#C,method=T,mode=FCBC,alpha=0.8)

plt.show()

叶轮设计有6片,用三角形模拟,颜色深红,透明度0.8,整体效果略显粗糙了一点。

3.6加上照明灯和提系

照明灯用一个白色的圆球表示,提系则是红色的一条直线,兼做照明灯的电源线。

plt.mesh(xs,ys,zs,im[::-1])

plt.surface(vs,color=#C,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)

3.7让花灯转起来

花灯旋转的实现非常简单,只需要给show方法一个rotation参数就可以。

plt.show(rotation=h-)

最终的花灯效果如下。

4完整源代码

有了上面的解说,完整的源代码就不用注释了。全部代码三十余行,各位可自行扩展,制作出更多的花灯来。

#-*-coding:utf-8-*-

importnumpyasnp

fromPILimportImage

importwxgl.wxplotasplt

im=np.array(Image.open(res/paper.png))/

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=#C,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-)

1
查看完整版本: 元宵节到了,手把手教你用Python打造