大家好,我是萍乡李兴球,专业从事Python教研的,主要方向为Python创意程序的编写与教学。编程是细活,在本次要讲的程序中,我们要听到一首曲子。它是日本民谣四季歌。让我们先来听一下这首歌曲吧。
下面是歌词:
喜爱春天的人儿啊 心地纯洁的人,象紫罗兰的花儿一样,是我知心的朋友。
喜爱夏天的人儿啊 意志坚强的人,象冲击岩石的波浪一样,是我敬爱的父亲。
喜爱秋天的人儿啊 感情深重的人,象抒发爱情的海涅一样,是我心上的人。
喜爱冬天的人儿啊 胸怀宽广的人,象融化冰雪的大地一样,是我亲爱的母亲。
相信能慢慢地聆听完这首歌的人,都是有耐心的人,恭喜你,已经具备学习编程的重大品质之一了!
所谓,快不如慢,意思就是说,我们有时候需要慢,才能体会到过程中的乐趣。在我们上网的时候,有时候网速很慢,我们能看到图片是逐像素显示出来的。在本次程序介绍中,我们是人为地让一幅图形逐行像素地慢慢显示出来。就像下面这样:
本次编程需要用到的模块有兰姆派模块,即numpy模块。如果计算机中没有安装兰姆派模块,那么在命令提示符下使用pip install numpy即可安装。
还有就是要有枕头模块,即pillow模块。安装方法也一样,输入pip install pillow即可。
最后,要有一个显示图形的模块,这里选用的是tkinter模块。当然用turtle模块也可以。
俗话说,打蛇打七寸,这里先说一下将要编写的程序的主要工作原理。
那就是用numpy模块的split命令把数组辟开成若干行,每一行都是一行像素!接下来就转换成高度只有一个像素的图形列表。看到这里,读者蒙了吧。我们先从简单的开始。
下面用’red’,’orange’等来表示一个像素值!按照我老李的习惯,先上代码:
>>> import numpy as np >>> cs = [['red','orange','yellow','green'], ['white','cyan','blue','magenta'], ['gray','blue','orange','lime']] >>> colors = np.array(cs) # 把cs转换成np二维数组 >>> a = len(colors) # a表示数组的行数,本例是3行 >>> rows = np.split(colors,a) # 辟开为a行, >>> rows # rows是一个列表,存储了3行np数组 [array([['red', 'orange', 'yellow', 'green']], dtype='<U7'), array([['white', 'cyan', 'blue','magenta']], dtype='<U7'), array([['gray', 'blue', 'orange', 'lime']], dtype='<U7')] >>> rows[0] array([['red', 'orange', 'yellow', 'green']], dtype='<U7') >>>
在上面的程序中,给兰姆派取了一个叫np的别名。有一个叫cs的嵌套列表,colors则是np二维数组。关键就是np.split命令,就是它把colors数组一行一行的辟开了!每一行都放在了rows列表中。也就是说rows[0]就是红橙黄绿,rows[1]就是白青蓝品红,rows[2]就是灰蓝橙亮绿!
在一幅图像中,我们把图像也辟开成一行一行的像素,然后把每行像素在tkinter的画布的不同位置显示出来,那么就能看到逐行显示图像的效果。下面就是核心函数!代码如下所示:
def split_image(pic): """pic是一张图片,返回图片的每行像素""" im = Image.open(pic) # 打开图形 ims = np.array(im) # 转为数组 rows = np.split(ims,len(ims)) # 按行辟开 return [Image.fromarray(row) for row in rows] # 返回每行
接下来,我们只要把每一行像素在画布的不同位置显示即可。由于画布的坐标系和图像是一样的。所以,每行像素在画布显示的y坐标逐步加1即可。以下是逐行像素显示图形的所有代码!
""" 逐行像素显示图形.py """ __author__ = '李兴球' __blog__ = 'www.lixingqiu.com' __date__ = '2021/2/20' import time import numpy as np from tkinter import * from PIL import Image,ImageTk def split_image(pic): """pic是一张图片,返回图片的每行像素""" im = Image.open(pic) # 打开图形 ims = np.array(im) # 转为数组 rows = np.split(ims,len(ims)) # 按行辟开 return [Image.fromarray(row) for row in rows] # 返回每行 root = Tk() # 新建窗口 cv = Canvas(width=480,height=360,bg='white') # 新建画布 cv.pack() # 放置画布 turtle = cv.create_image(240,180,image='') # 创建图形对象 rows = split_image('turtle.png') # 调用函数辟开图 a = len(rows) # 行数 ps = [ImageTk.PhotoImage(im) for im in rows] # 包装每行为PhotoImage对象 items = [cv.create_image(240,180+i,image='') for i in range(a)] for i in range(a): cv.itemconfig(items[i],image=ps[i]) # 配置一行像素 cv.update() # 更新画布显示 time.sleep(0.1) # 等待0.1秒 root.mainloop()
在上面的代码中,ps列表是每行像素的PhotoImage包装。items则是所有要在画布上显示的图形!为什么要准备这么多图形的item?这是由于,虽然我们是显示一幅图,但是由于要慢慢地显示这幅图,所以把它拆成了很多很多的图像来显示。这些图的高度只有一个像素!宽度则和原图相同。
如果显示一张名为turtle.png图的宽度是220像素,高度是166像素。通过split命令及转换后,把它拆分成了166张图。它们的宽度都是220,高度都是1个像素。在最后的for循环中,就是重新配置每一个item编号的图形。
好了,上面已经讲了如何逐行像素的显示图形了。下面就是发挥想像力,制作的一个小作品。视频效果如下所示:
实现上面效果的程序有本次讲的程序稍有区别,主要是采用了面向对象编程的思想。在程序中设计了一个名叫Shower的类。它有display方法,实现慢慢地显示图形。它有disappear方法,实现慢慢地消失图形。关注公众号: 李兴球Python,回复pythonzhi可免费得到本程序源代码及所有素材。谢谢你认真阅读了我写的文章。
发表评论