Programowo generować wideo lub animowany GIF w Pythonie?


221

Mam serię zdjęć, z których chcę utworzyć film. Idealnie mógłbym określić czas trwania ramki dla każdej ramki, ale stała częstotliwość klatek też byłaby w porządku. Robię to w wxPython, więc mogę renderować do wxDC lub zapisywać obrazy do plików, takich jak PNG. Czy istnieje biblioteka Python, która pozwala mi tworzyć wideo (AVI, MPG itp.) Lub animowany GIF z tych ramek?

Edycja: Próbowałem już PIL i wydaje się, że nie działa. Czy ktoś może mnie poprawić tym wnioskiem lub zasugerować inny zestaw narzędzi? Ten link wydaje się potwierdzać mój wniosek dotyczący PIL: http://www.somethinkodd.com/oddthinking/2005/12/06/python-imaging-library-pil-and-animated-gifs/

Odpowiedzi:


281

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

Zamiast tego skorzystaj z imageio , który został opracowany w celu rozwiązania tego problemu i nie tylko, i który ma pozostać.

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 metody strumieniowania:

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)

37
również parametr czas trwania = 0,5 ustawia czas trwania 0,5 sekundy dla każdej ramki.
Alleo

3
ValueError: Nie można znaleźć formatu do odczytu określonego pliku w trybie „i” - otrzymuję ten błąd w systemie Windows 2.7 Winpython. Jakieś wskazówki?
Vanko,

1
@Vanko błąd wydaje się być związany z odczytem pliku, możesz wypróbować imagio.mimread, lub jeśli jest to film z wieloma ramkami, użyj obiektu czytnika jak tutaj: imageio.readthedocs.io/en/latest/…
Almar,

2
@Alleo: „także parametr duration = 0,5 ustawia czas trwania 0,5 sekundy dla każdej ramki”. Czy istnieje funkcja Duration dla imageio? Jeśli tak, to gdzie jest to udokumentowane? Przeczytałem wszystkie dokumenty i nie mogłem znaleźć żadnej wzmianki o argumencie dotyczącym czasu trwania.
Chris Nielsen,

3
Doskonały! imageio in anacondaplony True, tak!
uhoh

47

Teraz używam ImageMagick. Zapisuję swoje ramki jako pliki PNG, a następnie wywołuję program.exe.exe z Python ImageMagick, aby utworzyć animowany plik GIF. Zaletą tego podejścia jest to, że mogę określić czas trwania klatki indywidualnie dla każdej klatki. Niestety zależy to od zainstalowania ImageMagick na komputerze. Mają otoki Pythona, ale wygląda to dość kiepsko i nie jest obsługiwane. Nadal otwarte na inne sugestie.


21
Jestem facetem w Pythonie, ale ImageMagick znalazł tutaj znacznie łatwiej. Właśnie zrobiłem sekwencję zdjęć i uruchomiłem coś w styluconvert -delay 20 -loop 0 *jpg animated.gif
Nick

Zgadzam się, to najlepsze rozwiązanie, na jakie się natknąłem. Oto minimalny przykład (oparty na przykładowym kodzie użytkownika Steve'a B opublikowanym na stackoverflow.com/questions/10922285/… ): pastebin.com/JJ6ZuXdz
andreasdr

Za pomocą ImageMagick możesz łatwo zmienić rozmiar animowanego gifa, np.convert -delay 20 -resize 300x200 -loop 0 *jpg animated.gif
Jun Wang

@Nick, jak uruchomić ten kod, aby utworzyć GIF? Czy powinienem zaimportować coś do Spyder IDE?
KSIĘŻYC

@ MOON Komendę ImageMagic, którą dodałem powyżej, uruchamia się po prostu z linii poleceń.
Nick

43

W czerwcu 2009 r. Pierwotnie cytowany post na blogu zawiera metodę tworzenia animowanych plików GIF w komentarzach . Pobierz skrypt images2gif.py (wcześniej images2gif.py , aktualizacja dzięki uprzejmości @geographika).

Następnie, aby odwrócić ramki w gifie, 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)

2
Dostępna jest nowa wersja tego skryptu, która zapewnia znacznie lepszą jakość danych wyjściowych na visvis.googlecode.com/hg/vvmovie/images2gif.py . Można go używać jako niezależnego skryptu oddzielnie od pakietu.
geographika

1
Skrypt wspomniany w tym komentarzu konsekwentnie powoduje błąd segmentacji, gdy jest używany na komputerze Mac, nawet po prostu uruchomiony (używając nazwy __ == '__ main ' przykład). Próbuję skryptu wymienionego w odpowiedzi, w nadziei, że będzie on działał poprawnie. EDYCJA - mogę potwierdzić, że skrypt wymieniony w powyższej odpowiedzi działa poprawnie na moim komputerze Mac.
scubbo

6
Zamiast po prostu pobrać skrypt użyj pip np. pip install visvisNastępnie w swoim skrypcie from visvis.vvmovie.images2gif import writeGif.
Daniel Farrell,

8
Próbowałem tego z Pythonem 2.7.3 na Windowsie 8 i otrzymuję UnicodeDecodeError: kodek „ascii” nie może dekodować bajtu 0xc8 na pozycji 6: porządek poza zakresem (128). Z systemem Pythona images2gif.py
Reckoner

3
Jestem autorem visivis (i images2gif) i odradzam używanie go w tym celu. Pracowałem nad lepszym rozwiązaniem w ramach projektu imageio (patrz moja odpowiedź).
Almar

40

Oto, jak to zrobić, używając tylko PIL (zainstaluj za pomocą :)pip install Pillow :

import glob
from PIL import Image

# filepaths
fp_in = "/path/to/image_*.png"
fp_out = "/path/to/image.gif"

# https://pillow.readthedocs.io/en/stable/handbook/image-file-formats.html#gif
img, *imgs = [Image.open(f) for f in sorted(glob.glob(fp_in))]
img.save(fp=fp_out, format='GIF', append_images=imgs,
         save_all=True, duration=200, loop=0)

4
to powinna być zaakceptowana odpowiedź, dziękuję @Kris
ted930511

1
Co zawiera zmienna gwiazdka („* imgs”)?
denisb411

3
To jest funkcja języka python. Wykonuje iterowalne rozpakowywanie . Możesz z grubsza myśleć o tym jako o rozpakowaniu, x = [a, b, c]do *xktórego można pomyśleć jako a, b, c(bez załączających nawiasów). W wywołań funkcji są synonimami: f(*x) == f(a, b, c). W rozpakowywaniu krotek jest to szczególnie przydatne w przypadkach, gdy chcesz podzielić iterowalną głowę (pierwszy element) i ogon (reszta), co robię w tym przykładzie.
Kris

25

Użyłem images2gif.py, który był łatwy w użyciu. Wydaje się, że podwoił rozmiar pliku ...

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

Również dlatego, że GIF był 8-bitowy, ł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 ramek:

Oto 3 z 26 ramek

zmniejszenie zdjęć zmniejszyło rozmiar:

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

mniejszy gif



2
Dostaję błędy .. Plik „C: \ Python27 \ lib \ images2gif.py”, wiersz 418, w writeGifToFile globalPalette = palettes [instance.index (max (wystąpić))] ValueError: max () arg jest pustą sekwencją
Harry

wystąpienie jest prawdopodobnie puste. Mój plik images2gif.py nie ma zmiennej „globalPalette”.
Robert King

jak to zmienić? Korzystam z najnowszego skryptu images2gif.py ( bit.ly/XMMn5h )
Harry

4
@robertking z kodem dostałem komunikat o błędziefp.write(globalPalette) TypeError: must be string or buffer, not list
LWZ

19

Aby utworzyć wideo, 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])

9

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

Dotychczasowe problemy z innymi rozwiązaniami:
1) Brak jednoznacznego rozwiązania dotyczącego sposobu modyfikacji czasu trwania
2) Brak rozwiązania dla iteracji katalogu poza kolejnością, co jest niezbędne w przypadku plików GIF
3) Brak wyjaśnienia, jak zainstalować imageio dla Pythona 3

zainstaluj imageio w ten sposób: python3 -m pip zainstaluj imageio

Uwaga: musisz upewnić się, że ramki mają indeks w nazwie pliku, aby można je było posortować, w przeciwnym razie nie będziesz w stanie wiedzieć, gdzie zaczyna się lub kończy 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('movie.gif'), images, duration = 0.04) # modify duration as needed

1
sortmoże przynieść nieoczekiwane wyniki, jeśli Twój schemat numerowania nie zawiera zer wiodących. A także dlaczego użyłeś mapy zamiast prostego zrozumienia listy?
NOhs

Proponuję zrobićfilenames.append(os.path.join(path, filename))
trueter

Secodning Nohs images = [imageio.imread(f) for f in filenames]jest czystszy, szybszy i bardziej pythoniczny.
Brandon Dube,

6

Jak powiedział Warren w zeszłym roku , to stare pytanie. Ponieważ ludzie nadal wydają się przeglądać stronę, chciałbym przekierować ich do bardziej nowoczesnego rozwiązania. Jak powiedział tu Blakev , na github istnieje przykład poduszki .

 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 nieaktualny ( gifmakernie jest modułem do importowania, tylko skrypt). Poduszka ma GifImagePlugin (którego źródłem jest GitHub ), ale dokument na ImageSequence wydaje się wskazywać na ograniczone wsparcie (tylko do odczytu)



5

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

numpngwModuł, który niedawno wystawiony na github ( https://github.com/WarrenWeckesser/numpngw ) można napisać animowanych plików PNG z NumPy tablic. ( Aktualizacja : numpngwjest 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

Aby zobaczyć animację, potrzebujesz przeglądarki obsługującej animowany PNG (bezpośrednio lub za pomocą wtyczki).


Teraz Chrome też tak działa, BTW. Jedno pytanie - czy sekwencja może być iterowalna? Czy obsługujesz „streaming” (tj. Otwieranie docelowego APNG i dodawanie ramek jeden po drugim w pętli)?
Tomasz Gandor,

Nie obsługuje arbitralnej iteracji ani streamingu, ale to nie znaczy, że nie będzie w przyszłości. :) Utwórz problem na stronie github z proponowanym rozszerzeniem. Jeśli masz jakieś pomysły na temat interfejsu API dla tej funkcji, opisz je w numerze.
Warren Weckesser,

Miałem dziwny błąd, który popełniłem na Twoim repozytorium.
mLstudent33

5

Jak wspomniał jeden z członków, imageio to świetny sposób na zrobienie tego. imageio pozwala również ustawić liczbę klatek na sekundę, a tak naprawdę napisałem funkcję w Pythonie, która pozwala ci zatrzymać ostatnią klatkę. Używam tej funkcji do animacji naukowych, w których zapętlenie jest przydatne, ale natychmiastowe ponowne uruchomienie nie. 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ład GIF za pomocą tej metody



4

W systemie Windows7, python2.7, opencv 3.0, dla 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)

3

Najłatwiejszą rzeczą, która sprawia, że ​​to działa, jest wywołanie polecenia powłoki w Pythonie.

Jeśli przechowywane są takie obrazy, jak dummy_image_1.png, dummy_image_2.png ... dummy_image_N.png, 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")

Spowoduje to utworzenie pliku gif my_output.gif.


2

Zadanie można wykonać, uruchamiając dwuwierszowy skrypt Pythona z tego samego folderu, co sekwencja plików obrazów. W przypadku plików sformatowanych png skrypt to -

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

1
Próbowałem ... nie działało dla mnie w Pythonie 2.6. Zwrócono: "Funkcja scitools.easyviz.movie uruchamia polecenie: / convert -delay 100 g4testC _ *. Png g4testC.gif / Nieprawidłowy parametr - 100"
Dan H

Problem z pewnością nie dotyczy Pythona. Ponownie zainstaluj imagemagick w systemie i spróbuj ponownie.
ArKE

2

Szukałem kodu jednoliniowego i znalazłem następujące elementy do mojej aplikacji. Oto co zrobiłem:

Pierwszy krok: zainstaluj ImageMagick z linku poniżej

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

wprowadź opis zdjęcia tutaj

Drugi krok: skieruj linię cmd do folderu, w którym znajdują się obrazy (w moim przypadku .png)

wprowadź opis zdjęcia tutaj

Trzeci krok: wpisz następujące polecenie

magick -quality 100 *.png outvideo.mpeg

wprowadź opis zdjęcia tutaj

Dzięki FogleBird za pomysł!


0

Właśnie wypróbowałem następujące i bardzo się przydałem:

Najpierw pobierz biblioteki Figtodati images2gifdo lokalnego katalogu.

Po drugie Zbierz figurki z 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)

0

Natknąłem się na moduł ImageSequence firmy PIL , który oferuje lepszą (i bardziej standardową) animację GIF. Tym razem używam również metody after () Tk , co jest lepsze niż 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

Prosta funkcja tworząca GIF-y:

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

Rozumiem, że pytałeś o konwersję obrazów do gif; jednak jeśli oryginalnym formatem jest MP4, możesz użyć FFmpeg :

ffmpeg -i input.mp4 output.gif

-1

To naprawdę niewiarygodne ... Wszyscy proponują teraz specjalny pakiet do gry w animowany GIF, który można teraz zrobić za pomocą Tkintera i klasycznego modułu PIL!

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

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 odtwarzania / pauzy / wyjścia.

Uwaga: Nie jestem pewien, czy kolejne klatki są odczytywane z pamięci czy z pliku (dysku). W drugim przypadku byłoby bardziej wydajne, gdyby wszyscy czytali jednocześnie i zapisywali w tablicy (liście). (Nie jestem tak zainteresowany, aby się dowiedzieć! :)


1
Zasadniczo wywołanie sleepw głównym wątku GUI nie jest dobrym pomysłem . Możesz użyć tej aftermetody do okresowego wywoływania funkcji.
Bryan Oakley

Masz rację, ale nie o to w ogóle chodzi, prawda? Chodzi o całą metodę. Wolałbym raczej zareagować na to!
Apostolos

1
Chciałem tylko udzielić porady, jak poprawić twoją odpowiedź.
Bryan Oakley,

BTW, zwykle używam tk.after()siebie. Ale tutaj musiałem uczynić kod tak prostym, jak to możliwe. Każdy, kto korzysta z tej metody animacji GIF, może zastosować własną funkcję opóźnienia.
Apostolos

W końcu! Tak, to rzeczywiście bardzo dobra uwaga. Byłem nie na temat! Dzięki, @Novel. (Ciekawe, jak inni to przeoczyli, np. Bryan, który mówił o metodzie opóźnienia czasowego!)
Apostolos
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.