视频转高清gif动态图片(Python代码实现)

如何使用Python编写代码来将视频转换为高清动态图片,从而无需依赖费用高昂的第三方工具或忍受低质量的输出呢?

具体的实现可以参考本篇博文,这个技术对于制作演示文稿、社交媒体内容或博客文章都非常有用,因为它可以让你轻松地将视频片段转换为清晰的GIF动画。

背景

最近,我需要为一次PPT答辩准备一些动态图片,而这些图片需要从一个视频中提取。我尝试了一些在线工具和付费软件,但发现要么转换结果模糊不清,要么带有水印,要么需要付费。于是,我决定自己动手写代码来实现这个任务。

技术栈

在开始之前,让我们先了解一下我们将使用的技术栈:

  • Python:作为编程语言的选择,Python是一种功能强大且易于使用的语言,适合处理图像和视频。

  • OpenCV:这是一个广泛用于计算机视觉任务的库,我们将使用它来处理视频帧。

  • imageio:这个库将帮助我们读取视频文件并将帧保存为GIF。

步骤

下面是将视频转换为高清动态图片的主要步骤:

  1. 安装所需库:

使用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")

整个项目的代码已上传至:askxiaozhang/Python_tools: To provide some like practical tools that png turn to gif or mp4 turn to gif by Python. (github.com)

有需要的兄弟姐们可以前往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")
相关推荐
土豆湿3 分钟前
拥抱极简主义前端开发:NoCss.js 引领无 CSS 编程潮流
开发语言·javascript·css
华清远见IT开放实验室6 分钟前
【每天学点AI】实战图像增强技术在人工智能图像处理中的应用
图像处理·人工智能·python·opencv·计算机视觉
界面开发小八哥10 分钟前
更高效的Java 23开发,IntelliJ IDEA助力全面升级
java·开发语言·ide·intellij-idea·开发工具
mqiqe31 分钟前
Elasticsearch 分词器
python·elasticsearch
qystca39 分钟前
洛谷 B3637 最长上升子序列 C语言 记忆化搜索->‘正序‘dp
c语言·开发语言·算法
薯条不要番茄酱39 分钟前
数据结构-8.Java. 七大排序算法(中篇)
java·开发语言·数据结构·后端·算法·排序算法·intellij-idea
今天吃饺子44 分钟前
2024年SCI一区最新改进优化算法——四参数自适应生长优化器,MATLAB代码免费获取...
开发语言·算法·matlab
努力进修1 小时前
“探索Java List的无限可能:从基础到高级应用“
java·开发语言·list
不去幼儿园2 小时前
【MARL】深入理解多智能体近端策略优化(MAPPO)算法与调参
人工智能·python·算法·机器学习·强化学习
Ajiang28247353043 小时前
对于C++中stack和queue的认识以及priority_queue的模拟实现
开发语言·c++