Python实现MP4转GIF:从帧提取到GUI界面构建

林舟
林舟
发布时间:2026-10-15 | 1人浏览过
原创

本文详细介绍如何使用Python将MP4视频转换为GIF动画。通过OpenCV提取视频帧,利用Pillow库合成GIF,并结合PySimpleGUI构建图形用户界面。教程涵盖环境配置、核心代码实现及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

为了创建图形界面,这里将使用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类以及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文件并将其转换为单独的帧。

但是,还添加了一些额外代码来删除“output”文件夹(如果已存在)。这样可以防止意外将两个MP4文件合并到一个输出文件中,从而导致GIF混乱。

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

其余代码与之前相同。

现在,准备查看下一个函数:


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动画的内容,请搜索本站以前的文章或继续浏览下面的相关文章。希望大家以后多多支持本站!

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表