Программно генерировать видео или анимированный GIF в Python?

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

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

18 ответов


Я бы рекомендовал не использовать images2gif от visvis, потому что он имеет проблемы с PIL/Pillow и не поддерживается активно (я должен знать, потому что я автор).

вместо этого, пожалуйста, используйте imageio, который был разработан для решения этой проблемы и многое другое, и предназначен для пребывания.

быстрое и грязное решение:

import imageio
images = []
for filename in filenames:
    images.append(imageio.imread(filename))
imageio.mimsave('/path/to/movie.gif', images)

для более длинных фильмов используйте потоковый подход:

import imageio
with imageio.get_writer('/path/to/movie.gif', mode='I') as writer:
    for filename in filenames:
        image = imageio.imread(filename)
        writer.append_data(image)

по состоянию на июнь 2009 года первоначально цитируемый пост в блоге имеет метод создания анимированных GIF в комментариях. Скачать скрипт images2gif.py (ранее images2gif.py Обновление учтивость @geographika).

затем, чтобы отменить кадры в gif, например:

#!/usr/bin/env python

from PIL import Image, ImageSequence
import sys, os
filename = sys.argv[1]
im = Image.open(filename)
original_duration = im.info['duration']
frames = [frame.copy() for frame in ImageSequence.Iterator(im)]    
frames.reverse()

from images2gif import writeGif
writeGif("reverse_" + os.path.basename(filename), frames, duration=original_duration/1000.0, dither=0)

Ну, теперь я использую ImageMagick. Я сохраняю свои кадры как PNG-файлы, а затем вызываю преобразование ImageMagick.exe от Python для создания анимированного GIF. Хорошая вещь в этом подходе - я могу указать длительность кадра для каждого кадра отдельно. К сожалению, это зависит от установки ImageMagick на машине. У них есть обертка Python, но она выглядит довольно дерьмовой и неподдерживаемой. Все еще открыт для других предложений.


Я images2gif.py, которым легко пользоваться. Похоже, хоть двойной размер файла..

26 110kb PNG файлов, я ожидал 26 * 110kb = 2860kb, но my_gif.GIF был 5.7 mb

также потому, что GIF был 8bit, хороший png стал немного нечетким в GIF

вот код, который я использую:

__author__ = 'Robert'
from images2gif import writeGif
from PIL import Image
import os

file_names = sorted((fn for fn in os.listdir('.') if fn.endswith('.png')))
#['animationframa.png', 'animationframb.png', 'animationframc.png', ...] "

images = [Image.open(fn) for fn in file_names]

print writeGif.__doc__
# writeGif(filename, images, duration=0.1, loops=0, dither=1)
#    Write an animated gif from the specified images.
#    images should be a list of numpy arrays of PIL images.
#    Numpy images of type float should have pixels between 0 and 1.
#    Numpy images of other types are expected to have values between 0 and 255.


#images.extend(reversed(images)) #infinit loop will go backwards and forwards.

filename = "my_gif.GIF"
writeGif(filename, images, duration=0.2)
#54 frames written
#
#Process finished with exit code 0

вот 3 из 26 кадров:

Here are 3 of the 26 frames

уменьшение изображений уменьшило размер:

size = (150,150)
for im in images:
    im.thumbnail(size, Image.ANTIALIAS)

smaller gif


чтобы создать видео, вы можете использовать opencv,

#load your frames
frames = ...
#create a video writer
writer = cvCreateVideoWriter(filename, -1, fps, frame_size, is_color=1)
#and write your frames in a loop if you want
cvWriteFrame(writer, frames[i])

Как сказал Уоррен в прошлом году, Это старый вопрос. Поскольку люди все еще просматривают страницу, Я хотел бы перенаправить их на более современное решение. Как сказал блейкв!--5-->здесь есть пример подушки на github.

 import ImageSequence
 import Image
 import gifmaker
 sequence = []

 im = Image.open(....)

 # im is your original image
 frames = [frame.copy() for frame in ImageSequence.Iterator(im)]

 # write GIF animation
 fp = open("out.gif", "wb")
 gifmaker.makedelta(fp, frames)
 fp.close()

Примечание: этот пример устарел (gifmaker не является импортируемым модулем, только скриптом). Подушка имеет GifImagePlugin (чей источник на GitHub), но дока на ImageSequence кажется, указывает на ограниченную поддержку (только для чтения)


это не библиотека python, но mencoder может это сделать: кодирование из нескольких входных файлов изображений. Вы можете выполнить mencoder из python следующим образом:

import os

os.system("mencoder ...")

вы пробовали PyMedia? Я не уверен на 100%, но похоже, что учебник цели своей проблемы.


С 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)

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

на numpngw модуль, который я недавно поставил на github (https://github.com/WarrenWeckesser/numpngw) можно писать анимированные PNG-файлы из массивов numpy. (обновление: 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 (напрямую или с помощью плагина), чтобы увидеть анимацию.


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

from scitools.std import movie
movie('*.png',fps=1,output_file='thisismygif.gif')

самое простое, что заставляет его работать для меня, - это вызов команды оболочки в 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.


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

Первый Этап: установите 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 за идею!


как один из членов, упомянутых выше, imageio-отличный способ сделать это. imageio также позволяет установить частоту кадров, и я фактически написал функцию в Python, которая позволяет установить удержание на последнем кадре. Я использую эту функцию для научной анимации, где цикл полезен, но немедленного перезапуска нет. Вот ссылка и функция:

как сделать GIF с помощью Python

import matplotlib.pyplot as plt
import os
import imageio

def gif_maker(gif_name,png_dir,gif_indx,num_gifs,dpi=90):
    # make png path if it doesn't exist already
    if not os.path.exists(png_dir):
        os.makedirs(png_dir)

    # save each .png for GIF
    # lower dpi gives a smaller, grainier GIF; higher dpi gives larger, clearer GIF
    plt.savefig(png_dir+'frame_'+str(gif_indx)+'_.png',dpi=dpi)
    plt.close('all') # comment this out if you're just updating the x,y data

    if gif_indx==num_gifs-1:
        # sort the .png files based on index used above
        images,image_file_names = [],[]
        for file_name in os.listdir(png_dir):
            if file_name.endswith('.png'):
                image_file_names.append(file_name)       
        sorted_files = sorted(image_file_names, key=lambda y: int(y.split('_')[1]))

        # define some GIF parameters

        frame_length = 0.5 # seconds between frames
        end_pause = 4 # seconds to stay on last frame
        # loop through files, join them to image array, and write to GIF called 'wind_turbine_dist.gif'
        for ii in range(0,len(sorted_files)):       
            file_path = os.path.join(png_dir, sorted_files[ii])
            if ii==len(sorted_files)-1:
                for jj in range(0,int(end_pause/frame_length)):
                    images.append(imageio.imread(file_path))
            else:
                images.append(imageio.imread(file_path))
        # the duration is the time spent on each image (1/duration is frame rate)
        imageio.mimsave(gif_name, images,'GIF',duration=frame_length)

Example GIF using this method


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

сначала загрузите библиотеки 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)

Я пришел на пильном это ImageSequence модуль, который предлагает для лучшей (и более стандартной) анинмации GIF. Я также использую ТЗ после() метод на этот раз, который лучше, чем времени.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()

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

проблемы с другими решениями до сих пор:
1) нет явного решения о том, как изменяется продолжительность
2) нет решения для итерации каталога вне порядка, что важно для GIFs
3) нет объяснения того, как установить imageio для python 3

установить imageio, как это: python3-m pip установить imageio

Примечание: вы хотите убедиться, что ваши кадры имеют какой-то индекс в имени файла, чтобы их можно было отсортировать, иначе вы не сможете узнать, где начинается или заканчивается GIF

import imageio
import os

path = '/Users/myusername/Desktop/Pics/' # on Mac: right click on a folder, hold down option, and click "copy as pathname"

image_folder = os.fsencode(path)

filenames = []

for file in os.listdir(image_folder):
    filename = os.fsdecode(file)
    if filename.endswith( ('.jpeg', '.png', '.gif') ):
        filenames.append(filename)

filenames.sort() # this iteration technique has no built in order, so sort the frames

images = list(map(lambda filename: imageio.imread(filename), filenames))

imageio.mimsave(os.path.join(path, 'movie.gif'), images, duration = 0.04) # modify duration as needed

Это действительно невероятно ... Все предлагают какой-то специальный пакет для воспроизведения анимированного 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()

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

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