视频转高清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")
相关推荐
晓纪同学24 分钟前
QT-简单视觉框架代码
开发语言·qt
威桑24 分钟前
Qt SizePolicy详解:minimum 与 minimumExpanding 的区别
开发语言·qt·扩张策略
飞飞-躺着更舒服27 分钟前
【QT】实现电子飞行显示器(简易版)
开发语言·qt
明月看潮生33 分钟前
青少年编程与数学 02-004 Go语言Web编程 16课题、并发编程
开发语言·青少年编程·并发编程·编程与数学·goweb
明月看潮生36 分钟前
青少年编程与数学 02-004 Go语言Web编程 17课题、静态文件
开发语言·青少年编程·编程与数学·goweb
Java Fans38 分钟前
C# 中串口读取问题及解决方案
开发语言·c#
盛派网络小助手1 小时前
微信 SDK 更新 Sample,NCF 文档和模板更新,更多更新日志,欢迎解锁
开发语言·人工智能·后端·架构·c#
算法小白(真小白)1 小时前
低代码软件搭建自学第二天——构建拖拽功能
python·低代码·pyqt
唐小旭1 小时前
服务器建立-错误:pyenv环境建立后python版本不对
运维·服务器·python
007php0071 小时前
Go语言zero项目部署后启动失败问题分析与解决
java·服务器·网络·python·golang·php·ai编程