Программно генерировать видео или анимированный GIF в Python? - PullRequest
176 голосов
/ 15 апреля 2009

У меня есть серия изображений, из которых я хочу создать видео. В идеале я мог бы указать длительность кадра для каждого кадра, но фиксированная частота кадров тоже подойдет. Я делаю это в wxPython, так что я могу рендерить в wxDC или я могу сохранить изображения в файлы, такие как PNG. Существует ли библиотека Python, которая позволит мне создавать из этих кадров видео (AVI, MPG и т. Д.) Или анимированный GIF?

Редактировать: я уже пробовал PIL, и, похоже, он не работает. Может кто-то исправить меня с этим выводом или предложить другой инструментарий? Эта ссылка, кажется, подтверждает мое заключение относительно PIL: http://www.somethinkodd.com/oddthinking/2005/12/06/python-imaging-library-pil-and-animated-gifs/

Ответы [ 20 ]

4 голосов
/ 01 января 2016

С windows7, python2.7, opencv 3.0 у меня работает следующее:

import cv2
import os

vvw           =   cv2.VideoWriter('mymovie.avi',cv2.VideoWriter_fourcc('X','V','I','D'),24,(640,480))
frameslist    =   os.listdir('.\\frames')
howmanyframes =   len(frameslist)
print('Frames count: '+str(howmanyframes)) #just for debugging

for i in range(0,howmanyframes):
    print(i)
    theframe = cv2.imread('.\\frames\\'+frameslist[i])
    vvw.write(theframe)
4 голосов
/ 06 октября 2015

Старый вопрос, много хороших ответов, но еще может быть интерес к другой альтернативе ...

Модуль numpngw, который я недавно установил на github (https://github.com/WarrenWeckesser/numpngw), может записывать анимированные файлы PNG из пустых массивов. ( Обновление : numpngw теперь на pypi: https://pypi.python.org/pypi/numpngw.)

Например, этот скрипт:

import numpy as np
import numpngw


img0 = np.zeros((64, 64, 3), dtype=np.uint8)
img0[:32, :32, :] = 255
img1 = np.zeros((64, 64, 3), dtype=np.uint8)
img1[32:, :32, 0] = 255
img2 = np.zeros((64, 64, 3), dtype=np.uint8)
img2[32:, 32:, 1] = 255
img3 = np.zeros((64, 64, 3), dtype=np.uint8)
img3[:32, 32:, 2] = 255
seq = [img0, img1, img2, img3]
for img in seq:
    img[16:-16, 16:-16] = 127
    img[0, :] = 127
    img[-1, :] = 127
    img[:, 0] = 127
    img[:, -1] = 127

numpngw.write_apng('foo.png', seq, delay=250, use_palette=True)

создает

animated png

Для просмотра анимации вам потребуется браузер, поддерживающий анимированный PNG (напрямую или с плагином).

3 голосов
/ 26 января 2019

Я отправляю еще один ответ, так как он проще, чем все, что было опубликовано:

from PIL import Image

width = 300
height = 300
im1 = Image.new("RGBA", (width, height), (255, 0, 0))
im2 = Image.new("RGBA", (width, height), (255, 255, 0))
im3 = Image.new("RGBA", (width, height), (255, 255, 255))
im1.save("out.gif", save_all=True, append_images=[im2, im3], duration=100, loop=0)

с использованием существующих изображений:

from PIL import Image

im1 = Image.open('a.png')
im2 = Image.open('b.png')
im3 = Image.open('c.png')
im1.save("out.gif", save_all=True, append_images=[im2, im3], duration=100, loop=0)

И, поскольку слишком низкие версии подушек молча терпят неудачу, это бонусная версия с проверкой версии библиотеки:

from packaging import version
from PIL import Image

im1 = Image.open('a.png')
im2 = Image.open('b.png')
im3 = Image.open('c.png')
if version.parse(Image.PILLOW_VERSION) < version.parse("3.4"):
    print("Pillow in version not supporting making animated gifs")
    print("you need to upgrade library version")
    print("see release notes in")
    print("https://pillow.readthedocs.io/en/latest/releasenotes/3.4.0.html#append-images-to-gif")
else:
    im1.save("out.gif", save_all=True, append_images=[
             im2, im3], duration=100, loop=0)
3 голосов
/ 15 мая 2017

Самая простая вещь, которая заставляет меня работать, - это вызвать команду оболочки в Python.

Если ваши изображения хранятся, например, dummy_image_1.png, dummy_image_2.png ... dummy_image_N.png, то вы можете использовать функцию:

import subprocess
def grid2gif(image_str, output_gif):
    str1 = 'convert -delay 100 -loop 1 ' + image_str  + ' ' + output_gif
    subprocess.call(str1, shell=True)

Просто выполните:

grid2gif("dummy_image*.png", "my_output.gif")

Это создаст ваш gif-файл my_output.gif.

2 голосов
/ 02 февраля 2015

Задача может быть выполнена путем запуска двухстрочного скрипта Python из той же папки, что и последовательность файлов изображений. Для файлов в формате png скрипт -

from scitools.std import movie
movie('*.png',fps=1,output_file='thisismygif.gif')
1 голос
/ 07 июля 2017

Я искал однострочный код и обнаружил следующее, чтобы работать для моего приложения. Вот что я сделал:

Первый шаг: Установите ImageMagick по ссылке ниже

https://www.imagemagick.org/script/download.php

enter image description here

Второй шаг: Укажите строку cmd на папку, в которой находятся изображения (в моем случае формат .png)

enter image description here

Третий шаг: Введите следующую команду

magick -quality 100 *.png outvideo.mpeg

enter image description here

Спасибо FogleBird за идею!

0 голосов
/ 13 июня 2019

Простая функция, которая делает GIF:

import imageio
import pathlib
from datetime import datetime


def make_gif(image_directory: pathlib.Path, frames_per_second: float, **kwargs):
    """
    Makes a .gif which shows many images at a given frame rate.
    All images should be in order (don't know how this works) in the image directory

    Only tested with .png images but may work with others.

    :param image_directory:
    :type image_directory: pathlib.Path
    :param frames_per_second:
    :type frames_per_second: float
    :param kwargs: image_type='png' or other
    :return: nothing
    """
    assert isinstance(image_directory, pathlib.Path), "input must be a pathlib object"
    image_type = kwargs.get('type', 'png')

    timestampStr = datetime.now().strftime("%y%m%d_%H%M%S")
    gif_dir = image_directory.joinpath(timestampStr + "_GIF.gif")

    print('Started making GIF')
    print('Please wait... ')

    images = []
    for file_name in image_directory.glob('*.' + image_type):
        images.append(imageio.imread(image_directory.joinpath(file_name)))
    imageio.mimsave(gif_dir.as_posix(), images, fps=frames_per_second)

    print('Finished making GIF!')
    print('GIF can be found at: ' + gif_dir.as_posix())


def main():
    fps = 2
    png_dir = pathlib.Path('C:/temp/my_images')
    make_gif(png_dir, fps)

if __name__ == "__main__":
    main()
0 голосов
/ 27 апреля 2018

Я наткнулся на модуль PIL ImageSequence , который предлагает более качественную (и более стандартную) GIF-анимацию. В этот раз я также использую метод Tk's after () , который лучше, чем time.sleep () .

from Tkinter import * 
from PIL import Image, ImageTk, ImageSequence

def stop(event):
  global play
  play = False
  exit() 

root = Tk()
root.bind("<Key>", stop) # Press any key to stop
GIFfile = {path_to_your_GIF_file}
im = Image.open(GIFfile); img = ImageTk.PhotoImage(im)
delay = im.info['duration'] # Delay used in the GIF file 
lbl = Label(image=img); lbl.pack() # Create a label where to display images
play = True;
while play:
  for frame in ImageSequence.Iterator(im):
    if not play: break 
    root.after(delay);
    img = ImageTk.PhotoImage(frame)
    lbl.config(image=img); root.update() # Show the new frame/image

root.mainloop()
0 голосов
/ 16 апреля 2018

Это действительно невероятно ... Все предлагают какой-то специальный пакет для воспроизведения анимированного GIF, в настоящее время это можно сделать с помощью Tkinter и классического модуля PIL!

Вот мой собственный метод анимации GIF (я его создал недавно). Очень просто:

from Tkinter import * 
from PIL import Image, ImageTk
from time import sleep

def stop(event):
  global play
  play = False
  exit() 

root = Tk()
root.bind("<Key>", stop) # Press any key to stop
GIFfile = {path_to_your_GIF_file}    
im = Image.open(GIFfile); img = ImageTk.PhotoImage(im)
delay = float(im.info['duration'])/1000; # Delay used in the GIF file 
lbl = Label(image=img); lbl.pack() # Create a label where to display images
play = True; frame = 0
while play:
  sleep(delay);
  frame += 1
  try:
    im.seek(frame); img = ImageTk.PhotoImage(im)
    lbl.config(image=img); root.update() # Show the new frame/image
  except EOFError:
    frame = 0 # Restart

root.mainloop()

Вы можете установить свои собственные средства, чтобы остановить анимацию. Дайте мне знать, если вы хотите получить полную версию с кнопками воспроизведения / паузы / выхода.

Примечание. Я не уверен, что последовательные кадры считываются из памяти или из файла (диска). Во втором случае было бы более эффективно, если бы они все читали одновременно и сохраняли в массив (список). (Мне не так интересно это выяснять! :)

0 голосов
/ 24 февраля 2017

Я только что попробовал следующее и было очень полезно:

Сначала Загрузите библиотеки Figtodat и images2gif в локальный каталог.

Во-вторых, соберите фигуры в массив и конвертируйте их в анимированный GIF:

import sys
sys.path.insert(0,"/path/to/your/local/directory")
import Figtodat
from images2gif import writeGif
import matplotlib.pyplot as plt
import numpy

figure = plt.figure()
plot   = figure.add_subplot (111)

plot.hold(False)
    # draw a cardinal sine plot
images=[]
y = numpy.random.randn(100,5)
for i in range(y.shape[1]):
    plot.plot (numpy.sin(y[:,i]))  
    plot.set_ylim(-3.0,3)
    plot.text(90,-2.5,str(i))
    im = Figtodat.fig2img(figure)
    images.append(im)

writeGif("images.gif",images,duration=0.3,dither=0)
...