来得瑟一下!用Python做一个缩放自如的圣诞老人

开发 后端
圣诞节又要到了,虽说我们中国人不提倡过西方的节日,但是商家们还是很喜欢的,估计有对象的男孩纸女孩纸们也很喜欢吧。

 圣诞节又要到了,虽说我们中国人不提倡过西方的节日,但是商家们还是很喜欢的,估计有对象的男孩纸女孩纸们也很喜欢吧。

[[286615]]

今天的主题是为大家展示如何用python做一个不断变大的圣诞老人,就像西游记中能够随意变幻大小的神仙妖怪那样,算是送给大家的小礼物,先上个图吧!


不要心急,盯着图片看5秒

思路要点:

  • 通过缩放获取等比大小的一组图片
  • 将上述图片叠加到固定大小的底图中
  • 按顺序组合图片生成动图

1、图片缩放

本篇文章的大部分工作都是基于opencv实现,而opencv进行图片缩放是极其容易的,不过这次我们要生成的是一组等比缩放的图片,所以在cv2.resize方法的使用上可能跟以往略有出入,先来看函数原型:

  1. cv2.resize(src, dsize[, dst[, fx[, fy[, interpolation]]]]) 

其中src是原图片,dsize是目标图片大小,当dsize为0的时候,我们就可以通过fx和fy两个参数来分别设置水平轴和垂直轴方向的缩放比例了。这样说可能有些抽象,我们举个例子来说明:

  1. for i in range(1, 40, 1): 
  2.   img = cv2.resize(image, (0, 0), fx=i/30, fy=i/30) 
  3.   cv2.imwrite(str(i)+'.png', img) 

运行上面这段代码会生成39张不同比例的图片,目标图片的大小由缩放比例fx和fy来控制,最小的一幅图边长是原图的1/30,最大的图片边长是原图的1.3倍(下图):

既然等比缩放的图片有了,是不是可以选定一个坐标原点,直接合成动图呢?答案是不行,因为常规的动图生成方法要求素材图片必须是相同的尺寸(像素),下面我们就来着重解决这一问题。

2、底图叠加

python中实现两幅图片叠加的办法有很多,但是他们都存在缺陷——要么叠加的图片必须是相同大小,要么难以控制图片叠加的具体位置。对此,小编采取的办法是在两幅图之间进行“像素级”的替换。

1).生成底图

待叠加的图片中,上层图片就使用刚才获取到的一系列等比缩放图,下层图片我们就生成一张固定大小的空白图片。需要注意,这里生成的空白图片必须大于最大的一幅缩放图。

生成空白底图分两步完成,第一步生成固定大小(垂直轴和水平轴的长度)的二维数组;第二步使用cv2.cvtColor进行颜色空间变换。代码如下:

  1. blank = np.ones((blankh, blankw), dtype=np.uint8) * 255 
  2. ret = cv2.cvtColor(blank, cv2.COLOR_GRAY2BGR) 

其实上面代码中的ret本质上是一个三维数组,我们可以把它打印出来查看(下图),但是通过cv2.imshow方法展示出来就是一张空白图片了。这其中涉及一些较为底层的内容,大家了解就好,文中不再赘述。

2).像素替换

正如刚才所说,opencv中的一幅图其实是一个三维数组,其实也可以把它看作是二维数组,数组中的

每个元素是形如 [255, 255, 255] 的列表,其中存放的是图片每个像素的颜色参数。也就是说,如果我们想实现一幅图片叠加到另一幅图片这样的视觉效果,可以对被叠加图片对应位置的

像素进行替换赋值。代码形式如下图所示,其中i和j分别为图片在垂直方向和水平方向的坐标。

  1. ret[i, j, 0] = image[i, j, 0] 
  2. ret[i, j, 1] = image[i, j, 1] 
  3. ret[i, j, 2] = image[i, j, 2] 

对一幅图片而言,坐标原点是在左上角(下图所示)。此外,为了保证最终得到动图的效果,不能简单的将图片以坐标原点为基准进行叠加,比较好的办法是把叠加原点设在底图下边缘的中心位置。

原理搞清楚后就可以开始图片叠加操作了,在此期间需要进行一些像素对应位置的计算,虽然稍微有点绕但是并不复杂,详细的转化公式就不写了,我们直接看代码:

上面代码中的image是已经缩放完毕的圣诞老人图片,blankh和blankw分别是空白图片的高度和宽度,这个尺寸可以根据需求自行设置。

下图展示的是一幅缩放比例1/2左右的图片和底图叠加后的效果,为了观察方便,我给图片加了一个边框。

3、生成动图

之前我们已经解决了单幅图片与底图的叠加,为了准备合成动图所需素材,还要对多个等比缩放的图片进行底图叠加操作。缩放比例间隔越小、准备的图片素材越多,生成的动图也就越平滑。

当然,动图的效果如何还要综合考虑多个因素,这里小编还是采用39幅图片组合动图。其中最小的图形高度是原图的1/30,最大的图形高度是原图的1.3倍。与底图叠加后的图片就是下面这个样子。

下面来说说动图的合成,将多个相同尺寸的图片合成动图可以使用imageio这个库来实现,核心代码只有一条:

  1. imageio.mimwrite('目标文件名称.gif', gifList, duration=0.15) 

其中第一个参数是git目标文件名称;gifList是一组列待合成的图片,也就是上面图片中展示的那些;最后一个参数duration表示画面切换间隔,单位为秒。

现在通过下面这段代码进行动图合成。

  1. file_path = 'pic' 
  2. imgList = os.listdir(file_path) 
  3. imgList = ['pic/'+img for img in imgList] 
  4. gifList = [imageio.imread(img) for img in imgList] 
  5. imageio.mimwrite('gif.gif', gifList, duration=0.15) 

来看合成后的动图效果(下图),仔细看看好像有点问题,怎么图中的圣诞老人忽大忽小?这跟我们预想的不一样啊。


其实这个问题是出在合成图片的顺序上,我们尝试打印上面代码中的imgList变量,结果如下:

可以看到,素材图片并不是按照我们预想的顺序排序。这在python的文件处理中也算是个比较常见的问题,解决方案之一是可以按照图片的创建时间排序,具体操作是在上面的第二行代码之后插入一条语句:

  1. imgList = sorted(imgList,key=lambda x: os.path.getmtime(os.path.join(file_path, x))) 

现在再次进行动图合成,就可以实现文章开头的效果了。

当然了,这种动图制作方法不仅限于圣诞老人,任何图片理论上都是可以的。比如说,我们还可以做一棵不断长大的圣诞树!

 

责任编辑:华轩 来源: 菜鸟学Python
相关推荐

2012-12-25 15:29:46

Google微软圣诞老人

2022-12-22 08:22:17

Python图像图像处理

2019-12-26 12:30:54

摄像头漏洞攻击

2020-07-20 10:00:52

Python翻译工具命令行

2021-12-01 07:02:55

Python 记录器按键

2013-08-26 11:21:02

Fedora 20

2022-03-30 15:11:26

Python房价工具

2017-12-27 14:49:26

大数据派送礼物圣诞老人

2023-08-02 08:11:58

Gaussdb系统厂商

2010-01-06 15:41:07

Linux操作系统

2015-07-03 11:27:30

程序员自己神器

2020-12-01 17:46:24

FossilGit

2020-01-14 11:19:38

网络安全网络安全技术周刊

2018-09-03 14:05:08

编程语言Python编程技巧

2023-12-10 15:24:32

AI圣诞

2021-12-30 06:59:27

视频通话网页

2021-07-07 11:08:21

机器学习数据集PHP

2021-12-23 09:50:46

Python游戏脚本

2018-01-04 16:04:35

圆环放大动画

2024-05-06 08:34:17

GolangGo程序
点赞
收藏

51CTO技术栈公众号