使用Python制作一盏 3D 花灯喜迎元宵佳节


Posted in Python onFebruary 26, 2021

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

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

使用Python制作一盏 3D 花灯喜迎元宵佳节

1.原材料

花灯纸

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

使用Python制作一盏 3D 花灯喜迎元宵佳节

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

使用Python制作一盏 3D 花灯喜迎元宵佳节

给龙骨贴上花灯纸

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

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

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

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

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

使用Python制作一盏 3D 花灯喜迎元宵佳节

制作旋转叶轮

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

>>> 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,整体效果略显粗糙了一点。

使用Python制作一盏 3D 花灯喜迎元宵佳节

加上照明灯和提系

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

>>> 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-')

最终的花灯效果如下。

使用Python制作一盏 3D 花灯喜迎元宵佳节

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 花灯内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Python 相关文章推荐
简单介绍Python中的floor()方法
May 15 Python
Python面向对象程序设计之类的定义与继承简单示例
Mar 18 Python
python入门之基础语法学习笔记
Feb 08 Python
Python函数默认参数常见问题及解决方案
Mar 26 Python
TensorFLow 数学运算的示例代码
Apr 21 Python
Python selenium模拟手动操作实现无人值守刷积分功能
May 13 Python
将tf.batch_matmul替换成tf.matmul的实现
Jun 18 Python
python matplotlib绘制三维图的示例
Sep 24 Python
python 使用cycle构造无限循环迭代器
Dec 02 Python
Python用Jira库来操作Jira
Dec 28 Python
pytorch下的unsqueeze和squeeze的用法说明
Feb 06 Python
Python实现自动玩连连看的脚本分享
Apr 04 Python
Python plt 利用subplot 实现在一张画布同时画多张图
Feb 26 #Python
Python xlwings插入Excel图片的实现方法
Feb 26 #Python
基于tensorflow __init__、build 和call的使用小结
Feb 26 #Python
python实现MySQL指定表增量同步数据到clickhouse的脚本
Feb 26 #Python
详解python的xlwings库读写excel操作总结
Feb 26 #Python
pytorch 中forward 的用法与解释说明
Feb 26 #Python
浅谈Python xlwings 读取Excel文件的正确姿势
Feb 26 #Python
You might like
php error_log 函数的使用
2009/04/13 PHP
PHP学习笔记之字符串编码的转换和判断
2014/05/22 PHP
session 加入redis的实现代码
2016/07/15 PHP
PHP实现二叉树深度优先遍历(前序、中序、后序)和广度优先遍历(层次)实例详解
2018/04/20 PHP
tp5(thinkPHP5框架)captcha验证码配置及验证操作示例
2019/05/28 PHP
获取焦点时,利用js定时器设定时间执行动作
2010/04/02 Javascript
Extjs4 类的定义和扩展实例
2013/06/28 Javascript
关于javascript event flow 的一个bug详解
2013/09/17 Javascript
javascript自然分类法算法实现代码
2013/10/11 Javascript
JavaScript 学习笔记之变量及其作用域
2015/01/14 Javascript
JavaScript中Window对象的属性及事件
2015/12/25 Javascript
javascript创建含数字字母的随机字符串方法总结
2016/08/01 Javascript
javascript实现瀑布流动态加载图片原理
2016/08/12 Javascript
BootStrap入门教程(二)之固定的内置样式
2016/09/19 Javascript
JavaScript高仿支付宝倒计时页面及代码实现
2016/10/21 Javascript
Vue2 Vue-cli中使用Typescript的配置详解
2017/07/24 Javascript
利用JQuery操作iframe父页面、子页面的元素和方法汇总
2017/09/10 jQuery
微信小程序异步处理详解
2017/11/10 Javascript
在vue项目中使用sass的配置方法
2018/03/20 Javascript
Vue.js获取被选择的option的value和text值方法
2018/08/24 Javascript
webuploader分片上传的实现代码(前后端分离)
2018/09/10 Javascript
JS获取当前时间戳方法解析
2020/08/29 Javascript
Python的迭代器和生成器使用实例
2015/01/14 Python
python使用三角迭代计算圆周率PI的方法
2015/03/20 Python
全面理解Python中self的用法
2016/06/04 Python
Python中的迭代器与生成器高级用法解析
2016/06/28 Python
python subprocess 杀掉全部派生的子进程方法
2017/01/16 Python
对json字符串与python字符串的不同之处详解
2018/12/19 Python
两个元祖T1=('a', 'b'),T2=('c', 'd')使用匿名函数将其转变成[{'a': 'c'},{'b': 'd'}]的几种方法
2019/03/05 Python
python 使用while写猜年龄小游戏过程解析
2019/10/07 Python
Python socket连接中的粘包、精确传输问题实例分析
2020/03/24 Python
基于opencv的selenium滑动验证码的实现
2020/07/24 Python
ivx平台开发之不用代码实现一个九宫格抽奖功能
2021/01/27 HTML / CSS
Saks Fifth Avenue澳洲/亚太地区:萨克斯第五大道精品百货店
2019/06/09 全球购物
家佳咖啡店创业计划书
2013/12/27 职场文书
Java 使用类型为Object的变量指向任意类型的对象
2022/04/13 Java/Android