Программно генерировать видео или анимированный 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 147

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

Как сказал Уоррен в прошлом году, Это старый вопрос. Поскольку люди все еще просматривают страницу, Я хотел бы перенаправить их на более современное решение. Как сказал блейкв здесь есть пример подушки на 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)

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

The 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.

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

Первый Этап:установите 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 aninmation. Я также использую ТЗ после() метод на этот раз, который лучше, чем времени.сон().

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) нет решения для итерации каталога out of order, что важно для GIFs
3) нет объяснений, как установить imageio для python 3

установить imageio, как это: python3-m pip install 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()

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

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