一.项目介绍
1.任务实现目标
要以几张照片为基础制作几个包含一定数量目标移动的模拟视频:例如飞机在跑道上移动,船只在河流中航行等。
2.实现思路
计划从已有图片中截取目标(如飞机,船只等)样例,选定背景图片(如机场、河流图片作为背景)。将目标图片批量粘贴到背景图片上,每次粘贴按图片先后顺序将目标粘贴位置以像素为单位变化,最后将生成的图片合成为视频,放映时就有了目标在背景上移动的效果。
3.设计流程
(1)首先使用PS软件从背景中扣出目标并将其另存为单独的文件,另外如有必要也可以用PS对背景图片进行微调
(2)利用Python中的图像处理库PILLOW中的函数来将目标粘贴到背景图片上,利用for循环可以实现批量操作
(3)使用cv2库(OpenCV,opencv-python)将步骤(2)中合成的图片合成为视频,检查无误后设计完成
二.实现过程详解(附代码)
1.图片处理过程
(1)从已有图片中截取目标
使用PS来完成这一步,用PS打开原始图片后放大(按住左Alt键再用鼠标滑轮即可放大或缩小图片)使用套索工具(推荐使用多边形套索工具,磁性套索工具虽然自动化程度高但是框选目标不准确)将图片中待选目标框选好,之后按Ctrl+J来快速将套索框选好的目标单独生成为一个新的图层(默认名称为“图层1”)。
选定生成的新的图层,使用左侧工具栏中的裁剪工具,将图层1中的目标裁剪出(裁剪框的范围尽可能的贴合目标,多余的空白部分尽量少框进来)
裁剪之后在裁剪好的图层上右键选择“导出为...”,在弹出的窗口选择保存为PNG格式。这是因为我们截取的目标基本上都是不规则的形状,如果选择保存为其他格式(如JPG)格式,那么系统保存时自动就用白色将图片填充成矩形形状,我们在后续的粘贴图片中就会出现目标周围的白色区域也一块粘贴在背景上了,而将图片保存为PNG格式不会出现这种多余的填充部分。
(2)背景图片处理
上面我们将截取好的目标保存成了PNG格式,下面我们也将背景图片保存为PNG格式,只需在PS中选择打开我们选定的背景图片再将其导出为PNG格式即可,另存为过程中也可以根据情况修改背景图片尺寸(一般选择等比例的放大或缩小背景图片的宽度、高度像素)。
如果背景图片中有我们不希望出现的其他物体,我们可以使用简单的PS工具将其涂抹、遮盖掉。例如使用工具栏中的矩形框选工具框选后Ctrl+J新建图层并移动该图层遮挡掉我们不希望出现的物体,也可以采用工具栏中仿制图章工具来对图像不满意的部分进行涂抹遮盖。进行完以上处理后我们将修改后的图片进行导出即可。
2.代码实现部分
(1)目标粘贴到背景上的代码
在这一部分代码中,我主要调用了PIL库中的图像处理函数来进行处理。
PIL,全称 Python Imaging Library,是 Python 平台一个功能非常强大而且简单易用的图像处理库。但是,由于 PIL 仅支持到Python 2.7,加上年久失修,于是一群志愿者在 PIL 的基础上创建了兼容 Python 3 的版本,名字叫 Pillow ,我们可以通过安装 Pillow 来使用 PIL。
下面是将目标粘贴到背景上的函数的代码实现:
from PIL import Image
def mix(src,dst,position):
im1 = src
im2 = dst
layer = Image.new('RGBA', im1.size, (0, 0, 0, 0))
layer.paste(im2,position)
out = Image.composite(layer,im1,layer)
return out
src是背景图片,dst是目标,position是设置目标粘贴到背景图片上的坐标。
我没有直接使用PIL库中的paste方法直接将目标粘贴到背景图片上,因为那样会出现粘贴的目标四周有白色部分的现象。所以这里我是先用Image.new()生成一个于背景图片尺寸大小相同的空白图像layer,再用paste方法将目标图像粘贴到这个空白图像layer上,最后用composite函数将粘贴目标图像后的layer与背景图像叠加合成一个新图像并将其返回。最终效果达到了将目标粘贴到背景指定位置而且不带有白色底边。
(2)利用for循环来生成一系列的图像
因为我的思路就是每次将目标的粘贴位置改变一点点(比如只改变1个像素),那么一系列的生成图像合在一起变成视频就有了目标在背景上移动的效果。在上面的目标粘贴函数的基础上,只需要用for循环来重复调用上面的粘贴函数(每次只需将粘贴位置参数进行改变即可),就可以自动生成这一系列的图像。
代码示例如下:
#生成第0~229帧图像
x_bias=0
y_bias=0
for i in range(0,230):
transit = mix(im1, im2, (600+x_bias, 920-y_bias))
transit.save('E:/temp/video1/generator1'+'/'+str(i)+'.png')
y_bias+=1
if y_bias % 3 == 0:
x_bias+=1
if (i+1)%10 == 0:
print('现在已保存' + str(i + 1) + '张图片')
print('船的运动轨迹:0~229帧生成结束')
(3)将一系列生成的图像合成为视频
上面的图片生成好后就可以将其生成视频,这里我使用cv2库(使用下面的代码时要先在环境中安装cv2库)中的函数来实现。
下面展示代码,以下代码段中包含详细注释来解释代码:
import cv2
#将已生成的图片合成视频
fourcc = cv2.VideoWriter_fourcc(*'XVID')
#这里设置编码器,括号中的参数表示设定生成视频的格式,也可以选择其他格式类型
videoWrite = cv2.VideoWriter('E:/temp/video1/generator1.avi',fourcc,24,(1200,1200))
'''
上面VideoWriter方法的参数含义依次为: 1. 文件保存地址/名称 2. 编码器 3. 视频帧率 4 .size
还要特别注意的是上面VideoWriter方法的参数中第一个参数:文件保存地址/名称中不能带有中文字符否则会出现错误
'''
for i in range(230):
fileName = 'E:/temp/video1/generator1'+'/'+str(i)+'.png'
#这里的filename表示导入的图片
img = cv2.imread(fileName)
videoWrite.write(img)# 写入方法 1 jpg data
if (i + 1) % 10 == 0:
print('已写入'+str(i + 1)+'/230张图片到视频')
print('视频生成完成')
(4)其他实现功能代码
可以对生成好的图片进行局部裁剪并放大到原来尺寸,使得生成的视频看起来有局部对焦放大的效果:
'''
实现对图片的裁剪,并将裁剪后的图片放大到原尺寸,以此来达到看起来像由远及近的放大效果
'''
from PIL import Image
import cv2
left=0
upper=0
right=1200
lower=1200
width=1200
height=1200
for i in range(200):
img = Image.open('E:/temp/picture2'+'/'+str(i)+'.png')
cropped = img.crop((left, upper, right, lower)) # (left, upper, right, lower)
cropped_resize = cropped.resize((width, height), Image.ANTIALIAS)
cropped_resize.save('E:/temp/picture3'+'/'+str(i)+'.png')
upper+=3
right-=3
if i%10 == 0:
print('已剪裁放大'+str(i)+'张图片')
print('全部图片已处理完成!')
print('开始将新处理的图片写入到视频E:/temp/test3.avi')
fourcc = cv2.VideoWriter_fourcc(*'XVID')
videoWrite = cv2.VideoWriter('E:/temp/test3.avi',fourcc,24,(1200,1200))
# 写入对象 1. file name 2. 编码器 3. 帧率 4 .size
for i in range(200):
fileName = 'E:/temp/picture3'+'/'+str(i)+'.png'
img = cv2.imread(fileName)
videoWrite.write(img)# 写入方法 1 jpg data
if i%10 == 0:
print('已写入'+str(i)+'张图片到视频')
print('全部图片已写入!')
使用PIL库中的rotate方法对目标进行旋转在粘贴,可以用来实现目标在背景中旋转的效果:
from PIL import Image
img = Image.open('E:/文件/飞机图像1.png')
img_rotate=im2.rotate(75) #这里将img旋转75度得到新图像img_rotate
使用PIL库中的convert方法,参数输入'L'来将图片转为灰度图,从而使得图片合成的视频看起来是黑白色的:
from PIL import Image
im1 = Image.open('E:/文件/机场图像1.png')
im1_grey=im1.convert('L')
im1_grey.show()
#使用方法举例:将全部的图像转化为灰度图样式
for i in range(230):
im1=Image.open('E:/temp/video3/generator3/'+str(i)+'.png')
transit=im1.convert('L')
transit.save('E:/temp/video3/generator4/'+str(i)+'.png')
if (i+1) % 10 == 0:
print('已经将'+str(i+1)+'张图片转化为灰度图')
print('开始合成视频')