目录
  • 运行环境
  • 如何从 mp4 视频中提取帧
  • 将帧变成 gif
  • 创建 mp4 到 gif gui

python 可用于读取常见的 mp4 视频格式并将其转换为 gif动画。当然,如果你愿意,你可以使用预先构建的软件,但是自己做很有趣(并且是一种很好的学习体验)。

在本教程中,你将学习以下内容:

  • 如何从 mp4 视频中提取帧
  • 将帧转换为 gif
  • 创建 mp4 到 gif gui

让我们开始吧!

运行环境

你需要安装 opencv 绑定以读取 mp4 文件并将视频中的每一帧转换为 jpg 文件。安装教程:

python3 -m pip install opencv-python

你还需要pillow从你从视频中提取的 jpg 创建动画 gif。也可以用pip安装:

python3 -m pip install pillow

要创建 gui,我这里会用到pysimplegui。要安装该库,请使用以下命令:

python3 -m pip install pysimplegui

如果你使用的是 anaconda,则包含 opencv-python 和 pillow。你只需要单独安装 pysimplegui。

如何从 mp4 视频中提取帧

从 mp4 视频中提取帧的第一步是找到要转换为 gif 的视频。

要从上面的视频中提取单个帧,你需要编写一些 python。创建一个新文件并将其命名为mp4_converter.py。然后输入以下代码:

import cv2


def convert_mp4_to_jpgs(path):
    video_capture = cv2.videocapture(path)
    still_reading, image = video_capture.read()
    frame_count = 0
    while still_reading:
        cv2.imwrite(f"output/frame_{frame_count:03d}.jpg", image)
        
        # read next image
        still_reading, image = video_capture.read()
        frame_count += 1


if __name__ == "__main__":
    convert_mp4_to_jpgs("flask_demo.mp4")

此代码采用 mp4 视频文件的路径。然后使用cv2.videocapture(path)打开视频。你可以使用此方法通读整个视频并提取每一帧。提取帧时,可以使用cv2.imwrite()将其写出。

当你运行这段代码时,你会发现这个 7 秒的视频产生了 235 帧!

现在准备好拍摄这些帧并将它们转换为动画 gif。

将帧变成 gif

该过程的下一步是将使用 opencv 从 mp4 文件中提取的帧转换为动画 gif。

这就是 pillow 包的用武之地。你可以使用它来接收图像文件夹并创建你的 gif。打开一个新文件并将其命名为gif_maker.py。然后输入以下代码:

import glob

from pil import image


def make_gif(frame_folder):
    images = glob.glob(f"{frame_folder}/*.jpg")
    images.sort()
    frames = [image.open(image) for image in images]
    frame_one = frames[0]
    frame_one.save("flask_demo.gif", format="gif", append_images=frames,
                   save_all=true, duration=50, loop=0)
    

if __name__ == "__main__":
    make_gif("output")

在这里,你使用 python 的glob模块在输出文件夹中搜索 jpg 文件。然后对帧进行排序,使它们按正确的顺序排列。最后,你将它们保存为 gif.

创建 mp4 到 gif gui

pysimplegui 是一个跨平台的 gui 框架,可在 linux、mac 和 windows 上运行。它封装了 tkinter、wxpython、pyqt 和其他几个 gui 工具包,为它们提供了一个通用接口。

在本文前面安装 pysimplegui 时,你安装了包装 tkinter 的默认版本。

打开一个新的 python 文件并将其命名为mp4_converter_gui.py。然后将此代码添加到你的文件中:

# mp4_converter_gui.py

import cv2
import glob
import os
import shutil
import pysimplegui as sg

from pil import image

file_types = [("mp4 (*.mp4)", "*.mp4"), ("all files (*.*)", "*.*")]


def convert_mp4_to_jpgs(path):
    video_capture = cv2.videocapture(path)
    still_reading, image = video_capture.read()
    frame_count = 0
    if os.path.exists("output"):
        # remove previous gif frame files
        shutil.rmtree("output")
    try:
        os.mkdir("output")
    except ioerror:
        sg.popup("error occurred creating output folder")
        return
    
    while still_reading:
        cv2.imwrite(f"output/frame_{frame_count:05d}.jpg", image)
        
        # read next image
        still_reading, image = video_capture.read()
        frame_count += 1


def make_gif(gif_path, frame_folder="output"):
    images = glob.glob(f"{frame_folder}/*.jpg")
    images.sort()
    frames = [image.open(image) for image in images]
    frame_one = frames[0]
    frame_one.save(gif_path, format="gif", append_images=frames,
                   save_all=true, duration=50, loop=0)


def main():
    layout = [
        [
            sg.text("mp4 file"),
            sg.input(size=(25, 1), key="-filename-", disabled=true),
            sg.filebrowse(file_types=file_types),
        ],
        [
            sg.text("gif file save location"),
            sg.input(size=(25, 1), key="-outputfile-", disabled=true),
            sg.saveas(file_types=file_types),
            
        ],
        [sg.button("convert to gif")],
    ]

    window = sg.window("mp4 to gif converter", layout)

    while true:
        event, values = window.read()
        mp4_path = values["-filename-"]
        gif_path = values["-outputfile-"]
        if event == "exit" or event == sg.win_closed:
            break
        if event in ["convert to gif"]:
            if mp4_path and gif_path:
                convert_mp4_to_jpgs(mp4_path)
                make_gif(gif_path)
                sg.popup(f"gif created: {gif_path}")

    window.close()


if __name__ == "__main__":
    main()

这是一段相当长的代码。我们来一段一段分析。

要开始,请查看导入部分:

# mp4_converter_gui.py

import cv2
import glob
import os
import shutil
import pysimplegui as sg

from pil import image

file_types = [("mp4 (*.mp4)", "*.mp4"), ("all files (*.*)", "*.*")]

在这里,你导入创建 gui 应用程序所需的所有模块和包。这包括 opencv (cv2)、pillow 的 image clas 和 pysimplegui,以及许多 python 自己的模块。

你还创建了一个变量来保存可以加载到 gui 中的文件类型。这是一个元组列表。

现在是时候将注意力转向程序中的第一个函数:

def convert_mp4_to_jpgs(path):
    video_capture = cv2.videocapture(path)
    still_reading, image = video_capture.read()
    frame_count = 0
    if os.path.exists("output"):
        # remove previous gif frame files
        shutil.rmtree("output")
    try:
        os.mkdir("output")
    except ioerror:
        sg.popup("error occurred creating output folder")
        return
    
    while still_reading:
        cv2.imwrite(f"output/frame_{frame_count:05d}.jpg", image)
        
        # read next image
        still_reading, image = video_capture.read()
        frame_count += 1

这是你之前创建的 mp4 转换器代码的修改版本。在这个版本中,你仍然使用videocapture()来读取 mp4 文件并将其转换为单独的帧。

但是,你还添加了一些额外的代码来删除“输出”文件夹(如果存在)。这可以防止你意外地将两个 mp4 文件合并到一个输出文件中,这会导致 gif 混乱。

你还添加了一些代码来尝试在删除后创建“输出”文件夹。如果创建文件夹时出现错误,则会显示错误对话框。

其余代码与之前相同。

现在你已准备好查看下一个函数:

def make_gif(gif_path, frame_folder="output"):
    images = glob.glob(f"{frame_folder}/*.jpg")
    images.sort()
    frames = [image.open(image) for image in images]
    frame_one = frames[0]
    frame_one.save(gif_path, format="gif", append_images=frames,
                   save_all=true, duration=50, loop=0)

你可以使用make_gif()将帧文件夹转换为 gif 文件。此代码与原始代码几乎相同,只是你传入 gif 文件的路径以使其唯一。

最后一段代码是你的 gui 代码:

def main():
    layout = [
        [
            sg.text("mp4 file"),
            sg.input(size=(25, 1), key="-filename-", disabled=true),
            sg.filebrowse(file_types=file_types),
        ],
        [
            sg.text("gif file save location"),
            sg.input(size=(25, 1), key="-outputfile-", disabled=true),
            sg.saveas(file_types=file_types),
            
        ],
        [sg.button("convert to gif")],
    ]

    window = sg.window("mp4 to gif converter", layout)

    while true:
        event, values = window.read()
        mp4_path = values["-filename-"]
        gif_path = values["-outputfile-"]
        if event == "exit" or event == sg.win_closed:
            break
        if event in ["convert to gif"]:
            if mp4_path and gif_path:
                convert_mp4_to_jpgs(mp4_path)
                make_gif(gif_path)
                sg.popup(f"gif created: {gif_path}")

    window.close()


if __name__ == "__main__":
    main()

在 pysimplegui 中,当你想在用户界面中“布局”元素时,你可以将项目添加到 python 列表中。对于此示例,你添加以下元素:

  • sg.text – 此元素有两个实例。它们用作输入(文本框)的标签
  • sg.input – 这个元素有两个实例,它是一个文本框类型的元素。一个保存 mp4 文件的位置,一个保存你要保存 gif 的位置
  • sg.filebrowse – 打开文件浏览对话框的按钮
  • sg.saveas – 打开文件另存为对话框的按钮
  • sg.button – 一个可以做任何你想做的事情的按钮

接下来,你获取元素列表并将其传递给sg.window,它表示包含所有其他元素的窗口。你的窗口还有一个退出按钮、一个最小化按钮和一个标题栏。

要启动 gui 的事件循环,你需要创建一个 while 循环并从 window 对象中读取数据。这允许你提取两个sg.input()对象的值,其中包含 mp4 和 gif 文件的路径。

当用户按下标记为“转换为 gif”的按钮时,你会捕获该事件并调用convert_mp4_to_jpgs()和make_gif()。如果一切顺利,视频将被转换,你将看到一个弹出对话框,说明新创建的 gif 的保存位置。

尝试运行此代码。你应该会看到如下内容:

现在你拥有了将 mp4 视频文件转换为 gif 所需的所有内容。你可以采取多种不同的措施来改进你的代码。例如,你可以向代码中添加更多错误处理,以免意外覆盖 gif。

你还可以添加一些新的 ui 元素来告诉你的代码调整各个帧的大小以帮助缩小 gif。另一种选择是更改每个单独的 jpg 的压缩,这也将减小 gif 的大小。

还有很多其他有趣的方法可以使这段代码变得更好。考虑一下,你一定会自己想出一些新功能! 

到此这篇关于通过python将mp4视频转换为gif动画的文章就介绍到这了,更多相关python视频转为gif动画内容请搜索www.887551.com以前的文章或继续浏览下面的相关文章希望大家以后多多支持www.887551.com!