圣诞节又到了。 虽然我们中国人不提倡西方的节日,但是商人还是很喜欢西方的节日。 估计有兴趣的男生女生也会喜欢的。
今天的主题是教大家如何制作一个成长中的圣诞老人,就像西游里的神怪们一样可以随意改变大小,算是送给大家的小礼物吧,先来发个图吧!
别担心,盯着图片看5秒
主要思考点:
1
图像缩放
本文的大部分工作都是基于实现,图像缩放极其容易,但是这次我们要生成一组按比例缩放的图像,因此使用了 cv2. 方法可能与过去略有不同。 进进出出,先看函数原型:
cv2.resize(src, dsize[, dst[, fx[, fy[, interpolation]]]])
其中,src为原始图像,dsize为目标图像的大小。 当dsize为0时,我们可以通过fx和fy参数设置横轴和纵轴的缩放比例。 这可能有点抽象,我们举个例子来说明一下:
for i in range(1, 40, 1):
img = cv2.resize(image, (0, 0), fx=i/30, fy=i/30)
cv2.imwrite(str(i)+'.png', img)
运行上面的代码会生成39张不同比例的图片。 目标图片的大小由缩放比例fx和fy控制。 最小图片的边长是原图的1/30,最大图片的边长是原图。 1.3倍(下):
既然已经有了按比例缩放的图片,那我们是不是可以选择一个坐标原点,直接合成动画呢? 答案是否定的,因为传统的动画生成方法要求素材图像必须具有相同的尺寸(像素),下面我们将重点解决这个问题。
2
底图叠加
中将两张图片叠加的方式有很多种,但都存在缺陷——要么叠加的图片必须大小相同,要么很难控制叠加的图片的具体位置。 对此,小编采取的方法是在两幅图像之间进行“像素级”的替换。
1)。 生成底图
在要叠加的图像中,上层图像使用刚刚获得的一系列比例缩放图像,下层图像我们生成固定大小的空白图像。 需要注意的是,这里生成的空白图片必须大于最大的缩放图片。
生成空白底图分两步完成。 第一步,生成固定大小(纵轴和横轴的长度)的二维数组; 第二步是使用cv2。 执行色彩空间变换。 代码如下所示:
blank = np.ones((blankh, blankw), dtype=np.uint8) * 255
ret = cv2.cvtColor(blank, cv2.COLOR_GRAY2BGR)
其实上面代码中的ret本质上是一个三维数组,我们可以把它打印出来查看(下图),但是cv2显示的却是一张空白图片。 方法。 这涉及到一些比较底层的内容,好让大家理解,文章中不再重复。
2)。 像素更换
刚才说了,里面的一张图其实就是一个三维数组,也可以看成是一个二维数组。
每个元素都是一个[255, 255, 255]形式的列表,里面存储了图像每个像素点的颜色参数。也就是说,如果我们要实现一张图片叠加在另一张图片上的视觉效果,我们可以控制叠加图片的对应位置
用于替换分配的像素。 代码形式如下图所示,其中i和j分别是图片的纵坐标和横坐标。
ret[i, j, 0] = image[i, j, 0]
ret[i, j, 1] = image[i, j, 1]
ret[i, j, 2] = image[i, j, 2]
对于图片来说,坐标原点在左上角(如下图所示)。 另外,为了保证动画的最终效果,不能简单的根据坐标原点进行图片的叠加。 最好的方法是将叠加原点设置在基础图像下边缘的中心。
弄清楚原理后,就可以开始进行图像叠加操作了。 这期间需要计算一些像素对应的位置。 虽然有点绕,但其实并不复杂。 详细的换算公式就不写了。 我们直接看代码:
上面代码中的图像是经过缩放的圣诞老人图像,以及空白图像的高度和宽度。 这个尺寸可以根据自己的需要来设置。
下图是一张缩放比例约为1/2的图片与底图的叠加效果。 为了方便观察,我给图片加了边框。
3
生成动画
之前我们已经解决了单图与底图的叠加。 为了准备合成动画所需的素材,我们还需要对多张按比例缩放的图片进行底图叠加操作。 缩放间隔越小,准备的图像素材越多,生成的动画就越流畅。
当然,动画的效果必须综合考虑多种因素。 这里,小编依然用了39张图片来组合动画。 其中,最小图形高度为原图的1/30,最大图形高度为原图的1.3倍。 与底图叠加的图像如下所示。
我们来说说动画的合成。 使用该库可以实现将多张相同尺寸的图片组合成动画。 核心代码只有一段:
imageio.mimwrite('目标文件名称.gif', gifList, duration=0.15)
第一个参数是git目标文件的名称; 是一组要合成的图片,即上图所示的那些; 最后一个参数表示屏幕切换的时间间隔,单位为秒。
现在使用以下代码进行动画合成。
file_path = 'pic'
imgList = os.listdir(file_path)
imgList = ['pic/'+img for img in imgList]
gifList = [imageio.imread(img) for img in imgList]
imageio.mimwrite('gif.gif', gifList, duration=0.15)
我们来看看合成动画的效果(下图)。 仔细一看,似乎有些不对劲。 为什么图中的圣诞老人这么大又这么小? 这与我们的预期不同。
其实问题就出在合成图像的顺序上。 我们尝试打印上面代码中的变量,结果如下:
可以看到,素材图片并没有按照我们预期的顺序排序。 这也是文件处理中比较常见的问题。 解决方案之一是根据图片的创建时间对图片进行排序。 具体操作是在上面第二行代码后面插入一条语句:
imgList = sorted(imgList,key=lambda x: os.path.getmtime(os.path.join(file_path, x)))
现在再次进行动画合成,就可以达到文章开头的效果了。
当然,这种动画制作方法并不局限于圣诞老人,任何图片理论上都是可以的。 例如,我们还可以制作一棵不断生长的圣诞树!
观看下面的视频一睹为快!
趣味游戏文章:
技巧和窍门: