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

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

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

背景

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

技术栈

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

- Python:作为编程语言的选择,Python是一种功能强大且易于使用的语言,适合处理图像和视频。
- OpenCV:这是一个广泛用于计算机视觉任务的库,我们将使用它来处理视频帧。
- imageio:这个库将帮助我们读取视频文件并将帧保存为GIF。

步骤

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

1. 安装所需库:

   使用pip或conda安装所需的Python库:

   pip install opencv-python imageio

整个过程我分为三个板块进行实现:

第一步:视频转化为图片 借助opencv

通过VideoCapture读取视频,然后imwrite保存图片。代码如下:

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文件流写入图片,

imageio.get_writer(uri = gifname,mode = "I",fps = 25)

其中这三个参数分别表示:

uri:合成后的gif动图的名字,可以随意更改。
mode:操作模式,I表示多图,不用更改。
fps:帧率,也就是画面每秒传输帧数,值越大,gif动图的播放速度越大。

代码如下:

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图片

以下是第三步的代码

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一下,,欢迎大家加入本项目一起为开源做贡献!~

下面是整个项目代码:

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(file_path, 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)
            file_path2 = file_path + filename + ".jpg"
            writer.append_data(imageio.imread(file_path2))


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(tmp_path, 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")

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

askxiaozhang

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值