如何使用Python编写代码来将视频转换为高清动态图片,从而无需依赖费用高昂的第三方工具或忍受低质量的输出呢?
具体的实现可以参考本篇博文,这个技术对于制作演示文稿、社交媒体内容或博客文章都非常有用,因为它可以让你轻松地将视频片段转换为清晰的GIF动画。
背景
最近,我需要为一次PPT答辩准备一些动态图片,而这些图片需要从一个视频中提取。我尝试了一些在线工具和付费软件,但发现要么转换结果模糊不清,要么带有水印,要么需要付费。于是,我决定自己动手写代码来实现这个任务。
技术栈
在开始之前,让我们先了解一下我们将使用的技术栈:
Python:作为编程语言的选择,Python是一种功能强大且易于使用的语言,适合处理图像和视频。
OpenCV:这是一个广泛用于计算机视觉任务的库,我们将使用它来处理视频帧。
imageio:这个库将帮助我们读取视频文件并将帧保存为GIF。
步骤
下面是将视频转换为高清动态图片的主要步骤:
- 安装所需库:
使用pip或conda安装所需的Python库:
bash
pip install opencv-python imageio
整个过程我分为三个板块进行实现:
第一步:视频转化为图片 借助opencv
通过VideoCapture读取视频,然后imwrite保存图片。代码如下:
python
def video_to_image(videoPath,imgPath,save_format = '.jpg',imgNumber = 0,nameLength = 4):
'''
params:
videoPath : 视频路径 例如 u'E:\Test/123.mp4'
imgPath : 图片路径 例如 r'F:\Test/tu/' #保存图片路径,路径最后加/斜杠
save_format : 保存的图片格式,默认为jpg可以改为'.png'
imgNumber : 图片保存的名字数量默认为0开始
'''
print("视频转图片的方法")
if imgPath[-1] != '/':imgPath + '/'
capture = cv2.VideoCapture(videoPath)
frame_num = int(capture.get(cv2.CAP_PROP_FRAME_COUNT))
suc = capture.isOpened() # 是否成功打开
frame_count = imgNumber # 图片张数从多少开始
while suc:
try:
frame_count += 1
suc, frame = capture.read()
cv2.imwrite(imgPath + str(frame_count).zfill(4) + save_format, frame)
# zfill() 方法返回指定长度的字符串,原字符串右对齐,前面填充0
#:str.zfill(width) 参数width
if frame_num == frame_count:
suc = False
except:
break
capture.release()
print("视频转图片结束! ")
第二步视频导出的图片集转化为gif图片
用到的imageio.get_writer作为gif文件流写入图片,
python
imageio.get_writer(uri = gifname,mode = "I",fps = 25)
其中这三个参数分别表示:
uri:合成后的gif动图的名字,可以随意更改。 mode:操作模式,I表示多图,不用更改。 fps:帧率,也就是画面每秒传输帧数,值越大,gif动图的播放速度越大。
代码如下:
python
def image_to_gif(st_imagename=1,end_imagename=1,gifname = "demo.gif"):
import imageio
'''
uri:合成后的gif动图的名字,可以随意更改。
mode:操作模式,I表示多图,不用更改。
fps:帧率,也就是画面每秒传输帧数,值越大,gif动图的播放速度越大。
gifname:保存的gif名字
'''
os.chdir(os.getcwd())
if not os.path.exists("images"):
os.makedirs("images")
with imageio.get_writer(uri = gifname,mode = "I",fps = 25) as writer:
for i in range(st_imagename, end_imagename + 1): #选择多少张
print(f"正在处理第{i}张")
filename = str(i).zfill(4)
file_path = os.path.join(os.getcwd(),'images',filename)
writer.append_data(imageio.imread(file_path+".jpg"))
最后就是将上述2步进行整合,实现视频转化为gif图片
以下是第三步的代码
python
def video_to_gif(videoPath,resultName,fps=25):
'''
:param videoPath: 视频路径 绝对路径。且路径不要含中文
:param resultName: 输出的gif文件名
:param fps: 保存的gif帧率,fps默认为25
'''
sample = [chr(i) for i in range(97,97+26)] + [str(i) for i in range(10)]
random_name = "_" + "".join(random.sample(sample,10)) #用于临时存储数据图片
#shutil.rmtree(file_path) #删除
if not os.path.exists(random_name):
os.makedirs(random_name)
tmp_path = os.path.join(os.getcwd(),random_name) + '/'
print("step 1 loading:video_to_image start")
video_to_image(videoPath,tmp_path) #视频转化完毕
print("step 1 finished:video_to_image end")
image_nums = len(os.listdir(tmp_path))
image_nums = 375 if image_nums > 375 else image_nums #TODO 默认上限为15s 即:25 * 15 = 375张照片
print("step 2 loading:image_to_gif start")
image_to_gif(st_imagename=1,end_imagename=image_nums,gifname = resultName)
print("step 2 finished:image_to_gif end")
shutil.rmtree(random_name)
print("All Finished")
有需要的兄弟姐们可以前往Fork、star一下,,欢迎大家加入本项目一起为开源做贡献!~
下面是整个项目代码:
python
import string
import imageio
import os
import cv2
import shutil
import base64
import random
def video_to_image(videoPath,imgPath,save_format = '.jpg',imgNumber = 0,nameLength = 4):
'''
params:
videoPath : 视频路径 例如 u'E:\Test/123.mp4'
imgPath : 图片路径 例如 r'F:\Test/tu/' #保存图片路径,路径最后加/斜杠
save_format : 保存的图片格式,默认为jpg可以改为'.png'
imgNumber : 图片保存的名字数量默认为0开始
'''
print("视频转图片的方法")
if imgPath[-1] != '/':imgPath + '/'
capture = cv2.VideoCapture(videoPath)
frame_num = int(capture.get(cv2.CAP_PROP_FRAME_COUNT))
suc = capture.isOpened() # 是否成功打开
frame_count = imgNumber # 图片张数从多少开始
while suc:
try:
frame_count += 1
suc, frame = capture.read()
cv2.imwrite(imgPath + str(frame_count).zfill(4) + save_format, frame)
# zfill() 方法返回指定长度的字符串,原字符串右对齐,前面填充0
#:str.zfill(width) 参数width
if frame_num == frame_count:
suc = False
except:
break
capture.release()
print("视频转图片结束! ")
def image_to_gif(st_imagename=1,end_imagename=1,gifname = "demo.gif"):
import imageio
'''
uri:合成后的gif动图的名字,可以随意更改。
mode:操作模式,I表示多图,不用更改。
fps:帧率,也就是画面每秒传输帧数,值越大,gif动图的播放速度越大。
gifname:保存的gif名字
'''
os.chdir(os.getcwd())
if not os.path.exists("images"):
os.makedirs("images")
with imageio.get_writer(uri = gifname,mode = "I",fps = 25) as writer:
for i in range(st_imagename, end_imagename + 1): #选择多少张
print(f"正在处理第{i}张")
filename = str(i).zfill(4)
file_path = os.path.join(os.getcwd(),'images',filename)
writer.append_data(imageio.imread(file_path+".jpg"))
def video_to_gif(videoPath,resultName,fps=25):
'''
:param videoPath: 视频路径 绝对路径。且路径不要含中文
:param resultName: 输出的gif文件名
:param fps: 保存的gif帧率,fps默认为25
'''
sample = [chr(i) for i in range(97,97+26)] + [str(i) for i in range(10)]
random_name = "_" + "".join(random.sample(sample,10)) #用于临时存储数据图片
#shutil.rmtree(file_path) #删除
if not os.path.exists(random_name):
os.makedirs(random_name)
tmp_path = os.path.join(os.getcwd(),random_name) + '/'
print("step 1 loading:video_to_image start")
video_to_image(videoPath,tmp_path) #视频转化完毕
print("step 1 finished:video_to_image end")
image_nums = len(os.listdir(tmp_path))
image_nums = 375 if image_nums > 375 else image_nums #TODO 默认上限为15s 即:25 * 15 = 375张照片
print("step 2 loading:image_to_gif start")
image_to_gif(st_imagename=1,end_imagename=image_nums,gifname = resultName)
print("step 2 finished:image_to_gif end")
shutil.rmtree(random_name)
print("All Finished")
if __name__ == '__main__':
video_to_gif(r"E:\Python_tools\Python_tools\video\test.mp4","test1.gif")