Programowo generować wideo lub animowany GIF w Pythonie?

Mam serię zdjęć, z których chcę stworzyć film. Idealnie mógłbym określić czas trwania klatki dla każdej klatki, ale stała liczba klatek też byłaby w porządku. Robię to w wxPython, więc mogę renderować do wxDC lub Mogę zapisać obrazy do plików, takich jak PNG. Czy istnieje Biblioteka Pythona, która pozwoli mi stworzyć albo film (AVI, MPG, itp.), albo animowany GIF z tych klatek?

Edit: próbowałem już PIL i chyba nie działa. Czy ktoś może mnie tym poprawić wniosek lub sugestia innego zestawu narzędzi? Ten link zdaje się potwierdzać moje wnioski dotyczące PIL: http://www.somethinkodd.com/oddthinking/2005/12/06/python-imaging-library-pil-and-animated-gifs/

Author: FogleBird, 2009-04-15

18 answers

Polecam nie używać images2gif z visvis, ponieważ ma problemy z PIL/Pillow i nie jest aktywnie utrzymywany(powinienem wiedzieć, bo jestem autorem).

Zamiast tego użyj imageio , który został opracowany w celu rozwiązania tego problemu i nie tylko, i ma zostać.

Szybkie i brudne rozwiązanie:

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

W przypadku dłuższych filmów, użyj podejścia streamingowego:

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)
 138
Author: Almar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-07-21 04:03:10

Od czerwca 2009 r. pierwotnie cytowany post na blogu ma metodę tworzenia animowanych GIFów w komentarzach . Pobierz skrypt images2gif.py (dawniej images2gif.py , Aktualizacja Dzięki uprzejmości @ geographika).

Następnie, aby odwrócić klatki w gif, na przykład:

#!/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)
 41
Author: kostmo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-07-21 04:55:19

Cóż, teraz używam ImageMagick. Zapisuję ramki jako pliki PNG, a następnie wywołuję konwersję ImageMagick.exe z Pythona do tworzenia animowanego GIFA. Fajną rzeczą w tym podejściu jest to, że mogę określić czas trwania klatki dla każdej klatki indywidualnie. Niestety zależy to od zainstalowania ImageMagick na maszynie. Mają wrapper Pythona, ale wygląda dość gównianie i nieobsługiwany. Wciąż otwarty na inne sugestie.

 35
Author: FogleBird,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-04-15 21:34:42

Użyłem images2gif.py który był łatwy w użyciu. Wydawało się, że podwojono Rozmiar pliku..

26 plików PNG 110KB, spodziewałem się 26 * 110kb = 2860kb, ale my_gif.GIF 5.7 mb

Również dlatego, że GIF był 8bit, ładne png stały się trochę rozmyte w GIF

Oto kod, którego użyłem:

__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

Oto 3 z 26 klatek:

Oto 3 z 26 ramek

Zmniejszanie obrazów zmniejszyło rozmiar:

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

mniejszy gif

 25
Author: robert king,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-04-29 23:05:34

Aby utworzyć film, możesz użyć 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])
 18
Author: attwad,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-07-30 04:29:45

Tak jak Warren powiedział w zeszłym roku, to stare pytanie. Ponieważ ludzie nadal wydają się oglądać stronę, chciałbym przekierować ich do bardziej nowoczesnego rozwiązania. Jak powiedział blakev tutaj , jest przykład poduszki nagithub .

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

Uwaga: Ten przykład jest przestarzały (gifmaker nie jest importowalnym modułem, tylko skryptem). Poduszka ma GifImagePlugin (którego źródło jest na Githubie), ale doc na ImageSequence wydaje się wskazywać ograniczone wsparcie (tylko odczyt)

 5
Author: Nathan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-02-22 11:12:14

To nie jest biblioteka Pythona, ale mencoder może to zrobić: Kodowanie z wielu wejściowych plików graficznych . Możesz wykonać mencoder z Pythona w następujący sposób:

import os

os.system("mencoder ...")
 4
Author: willurd,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-04-15 22:24:43

Czy próbowałeś PyMedia ? Nie jestem w 100% pewien, ale wygląda na to, że Ten przykład samouczka dotyczy Twojego problemu.

 4
Author: Jakub Šturc,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-05-07 06:59:24

Z windows7, python2. 7, opencv 3.0, u mnie działa:

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
Author: Jacek Słoma,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-01-01 12:23:28

Stare pytanie, wiele dobrych odpowiedzi, ale nadal może być zainteresowanie inną alternatywą...

numpngw moduł, który niedawno umieściłem na GitHubie ( https://github.com/WarrenWeckesser/numpngw ) potrafi zapisywać animowane pliki PNG z tablic numpy. (Update: numpngw jest teraz na pypi: https://pypi.python.org/pypi/numpngw.)

Na przykład ten skrypt:

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)

Tworzy:

animowane png

Będziesz potrzebował przeglądarki, która obsługuje animowane PNG (bezpośrednio lub za pomocą wtyczki), aby zobaczyć animację.

 4
Author: Warren Weckesser,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-07-11 18:22:54

Zadanie można wykonać uruchamiając dwuliniowy skrypt Pythona z tego samego folderu co Sekwencja plików graficznych. Dla plików sformatowanych w formacie png skrypt to -

from scitools.std import movie
movie('*.png',fps=1,output_file='thisismygif.gif')
 3
Author: ArKE,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-02-02 10:07:11

Najprostszą rzeczą, która sprawia, że działa to dla mnie, jest wywołanie polecenia powłoki w Pythonie.

Jeśli są przechowywane obrazy takie jak dummy_image_1.png, dummy_image_2.png ... dummy_image_N. png, wtedy możesz użyć funkcji:

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

Po prostu wykonaj:

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

To stworzy plik gif my_output.gif.

 3
Author: Pkjain,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-15 17:07:25

Szukałem kodu pojedynczej linii i znalazłem następujące działanie dla mojej aplikacji. Oto co zrobiłem:

Pierwszy Krok: zainstaluj ImageMagick z poniższego linku

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

Tutaj wpisz opis obrazka

Drugi etap: wskaż linię cmd do folderu, w którym znajdują się obrazy (w moim przypadku .format png) są umieszczone

Tutaj wpisz opis obrazka

Trzeci Krok: wpisz następujące polecenie

magick -quality 100 *.png outvideo.mpeg

Tutaj wpisz opis obrazka

Dzięki FogleBird za pomysł!

 2
Author: MedImage,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-07-07 09:40:05

Jak wspomniano powyżej, imageio jest świetnym sposobem na to. imageio pozwala również ustawić liczbę klatek na sekundę, a właściwie napisałem funkcję w Pythonie, która pozwala ustawić przytrzymanie ostatecznej klatki. Używam tej funkcji do animacji naukowych, gdzie pętla jest przydatna, ale natychmiastowy restart nie jest. oto link i Funkcja:

Jak zrobić GIF za pomocą Pythona

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)

Przykładowy GIF wykorzystujący tę metodę

 2
Author: Engineer's Maker Portal,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-07-28 20:24:44

Po prostu próbowałem następujących I było bardzo przydatne:

Najpierw pobierz biblioteki Figtodat i images2gif do lokalnego katalogu.

Po Drugie Zbierz figury w tablicy i przekonwertuj je na animowany 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)
 1
Author: Cro-Magnon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-07-24 03:27:03

Natknąłem się na moduł Pil ImageSequence , który oferuje lepszą (i bardziej standardową) aninmację GIF. Używam również metody TK after () Tym Razem, która jest lepsza niż czas .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
Author: Apostolos,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-04-27 07:57:20

Natknąłem się na ten post i Żadne z rozwiązań nie zadziałało, więc oto moje rozwiązanie, które działa

Problemy z dotychczasowymi rozwiązaniami:
1) Brak jednoznacznego rozwiązania co do sposobu modyfikacji czasu trwania
2) Brak rozwiązania dla iteracji katalogu out of order, która jest niezbędna dla GIFów
3) brak wyjaśnienia jak zainstalować imageio dla Pythona 3

Zainstaluj imageio TAK: python3-m pip install imageio

Uwaga: będziesz chciał się upewnić, że Twoje ramki mają jakiś indeks w nazwie pliku, aby mogły być sortowane, w przeciwnym razie nie będziesz miał możliwości poznania, gdzie GIF się zaczyna lub kończy

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
 1
Author: Daniel McGrath,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-09-06 11:59:25

To naprawdę niesamowite ... Wszyscy proponują jakiś specjalny pakiet do odtwarzania animowanego GIFA, w tej chwili można to zrobić z Tkinter i klasycznym modułem PIL!

Oto moja własna metoda animacji GIF (stworzyłem jakiś czas temu). Bardzo proste:

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

Możesz ustawić własne środki, aby zatrzymać animację. Daj mi znać, jeśli chcesz uzyskać pełną wersję z przyciskami play/pause / quit.

Uwaga: Nie jestem pewien czy kolejne klatki są odczytywane z pamięci czy z plik (dysk). W drugim przypadku byłoby bardziej wydajne, gdyby wszystkie odczytywały się jednocześnie i zapisywały do tablicy (listy). (Nie jestem tak zainteresowany, aby dowiedzieć się! :)

 -1
Author: Apostolos,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-04-16 15:18:28