问题描述
最近准备写些文章,遇到要将 mp4
视频转换为 gif
格式图片 。最开始想的是找些免费的在线转换的工具试试,但是用了不久发现白嫖一两次之后要么需要注册要么需要收费。那有没有永久免费方式呢,也有使用一些工具软件比如ps
等等也能做到,但为了转个 gif
图片还要安装一个工具软件,不免太过麻烦。既然如此,那就用代码解决吧。这里记录下在使用python
解决的时候遇到的一些问题。方便后续查看。主要问题如下:
1、使用
moviepy
库进行视频
转换为gif
图片问题如下:
- 动态图片帧率非常低、一卡一卡的。
- 转换后格式过大,不符合主流博客网站的上传限制,知乎是
1M以内
,csdn
是5M以内
;
2、之后我就想办法看如何压缩
gif
图片,这里使用的是imageio
库和PIL
库进行的压缩。遇到问题如下:
- 百度现成的代码报错,有计算帧率的参数报错
KeyError: 'duration'
;- 压缩之后的动态图片还是不理想占用的内存空间比较大。
- 图片上传博客网站后只进行了一次循环,无法重复循环。
3、当然还有就是不使用
imageio
库进行压缩方案,只是用PIL
库进行的压缩。
- 这个方案呢,可以将大小压缩,但是帧率问题不可调节,会有一卡一卡的问题,但是可以解决重复循环的问题。
解决方案
流程如下:
1、首先,既然我们要解决问题,首先我们要这些用到的python
库使用起来才行。安装命令如下:
(1)、安装 moviepy 库
pip install moviepy -i https://pypi.tuna.tsinghua.edu.cn/simple
(2)、安装 imageio 库
pip install imageio -i https://pypi.tuna.tsinghua.edu.cn/simple
(3)、安装 PIL 库
pip install pillow -i https://pypi.tuna.tsinghua.edu.cn/simple
2、 接下来,库安装完成了,我们就要写代码进行转换和压缩操作才行。
(1)、使用 moviepy 库进行视频转换为 gif 代码
# -*- coding:utf-8 -*-
'''
实现功能
使用 moviepy 库,视频转gif动图处理
'''
import moviepy.editor as mpy
# 视频文件的本地路径
content = mpy.VideoFileClip("E:\\录像\\01-录制\\05-球体相册.mp4")
# 剪辑0分0秒到0分5秒的片段。resize为修改清晰度、0.5参数代表缩小0.5倍
# c1 = content.subclip((0, 0), (0, 5)).resize((1416,732))
c1 = content.subclip((0, 0), (0, 5)).resize(0.5)
# 将片段保存为gif图到python的指定路径,fps指定帧率,抽帧技术主要解决转换后内存过大的问题
c1.write_gif("E:\\录像\\02-已转\\05-球体相册.gif",fps=15)
# 提示作用
print('转换完成!!!')
(2)、使用 imageio 库和 PIL 库进行的压缩代码
# -*- coding:utf-8 -*-
'''
实现功能
使用ImageIo 和PIL库,对gif动图进行压缩处理
'''
import imageio
from PIL import Image, ImageSequence
# 设置压缩尺寸,这里设置压缩尺寸为500
rp = 500
img_list = []
# 读取原gif动图
img = Image.open("E:\\录像\\02-已转\\05-球体相册.gif")
# 对原动图进行压缩,并存入img_list
for i in ImageSequence.Iterator(img):
i = i.convert('RGBA') # 1,L,P,RGB,RGBA,CMYK,YCbCr,I,F。设置不同的参数效果不同、内存大小不同
if max(i.size[0], i.size[1]) > rp:
i.thumbnail((rp, rp))
img_list.append(i)
# 计算帧的频率
# durt = (img.info)['duration'] / 1000 #这句已经更改了
durt = 1/24 * 1000
# 读取img_list合成新的gif,loop=0是设置只循环一次的问题
imageio.mimsave('E:\\录像\\03-已压缩\\05-球体相册.gif', img_list, duration=durt,loop=0)
print('压缩完成!!!')
(3)、只是用 PIL 库进行的压缩代码
# -*- coding:utf-8 -*-
'''
实现功能
只使用PIL库,对gif动图进行压缩处理
'''
import imageio
from PIL import Image, ImageSequence
# 设置压缩尺寸,这里设置压缩尺寸为500
rp = 400
img_list = []
# 读取原gif动图
# img = Image.open("E:\\录像\\02-已转\\04-发光球体.gif")
img = Image.open("E:\\录像\\02-已转\\05-球体相册.gif")
# 对原动图进行压缩,并存入img_list
for i in ImageSequence.Iterator(img):
i = i.convert('RGBA') # 1,L,P,RGB,RGBA,CMYK,YCbCr,I,F。
if max(i.size[0], i.size[1]) > rp:
i.thumbnail((rp, rp))
img_list.append(i)
# 让不循环的gif循环起来,这是一步非常重要的代码,主要解决csdn不循环测试
img_list[0].save("E:\\录像\\out.gif", save_all=True, append_images=img_list[1:])
print('压缩完成!!!')
问题总结
- 问题描述中的大部分问题都在注释中有标注。其中你比如说刚开转换的动图一卡一卡的,主要解决方案就是
imageio
库进行动图的帧重组,并进行计算好帧率,这个库在重设帧率这一块有些代码使用的从动图属性中获取这个参数,但是有时候要压缩的动图没有这个参数 (出现这个情况是因为可以使用这个库对多组图片实现轮播效果的动图,该步骤下的动图是一般是有这个属性的),这时你就可以自己设定一个固定的参数,1/24 * 1000
这个值是以每秒24帧计算出来的。- 还有比如转换格式过大,在视频转动图的代码中,我们可以设置想要的分辨率,分辨率越低,内存占用越低,或者设置原始分辨率的
0.5
倍、还有设定像fps=15
参数可以抽帧降低内存空间。当然用imageio库
或PIL库
进行图片的压缩,这其中有一个明显效果的是,i.convert('RGBA')
该方法的参数可以设置不同的颜色格式参数。不同参数压缩的大小也不同,实践得出的是RGBA
要比RGB
更省内存空间;还有就是调整分辨率大小也可以改变压缩大小。至于动图只有单次循环的效果的话,解决方法就是在imageio.mimsave
方法中添加loop=0
的参数,虽然我查看api
解释说0
代表循环往复1
则代表单次循环,默认的是0
,但是不写的话却是单次循环,所以还是写一下这个参数,因为时间关系就不深究了。代码如有错误,欢迎指正交流,本文只是记录一下问题总结,没有非常严谨的考究,所以细节不一定很到位,也欢迎大家评论交流。