it-swarm.com.de

Programmgesteuertes Erzeugen von Video oder animiertem GIF in Python?

Ich habe eine Reihe von Bildern, aus denen ich ein Video erstellen möchte. Idealerweise könnte ich für jedes Bild eine Bilddauer angeben, aber auch eine feste Bildrate wäre in Ordnung. Ich mache das in wxPython, also kann ich ein wxDC rendern oder die Bilder in Dateien wie PNG speichern. Gibt es eine Python-Bibliothek, mit der ich aus diesen Frames entweder ein Video (AVI, MPG usw.) oder ein animiertes GIF erstellen kann?

Edit: Ich habe PIL bereits probiert und es scheint nicht zu funktionieren. Kann mich jemand mit dieser Schlussfolgerung korrigieren oder ein anderes Toolkit vorschlagen? Dieser Link scheint meine Schlussfolgerung bezüglich PIL zu unterstützen: http://www.somethinkodd.com/oddthinking/2005/12/06/python-imaging-library-pil-and-animated-gifs/

164
FogleBird

Nun, ich benutze jetzt ImageMagick. Ich speichere meine Frames als PNG-Dateien und rufe dann ImageMagicks convert.exe aus Python auf, um ein animiertes GIF zu erstellen. Das Schöne an diesem Ansatz ist, dass ich für jedes Bild eine Framedauer festlegen kann. Leider hängt dies davon ab, dass ImageMagick auf dem Computer installiert ist. Sie haben einen Python-Wrapper, aber er sieht ziemlich beschissen aus und wird nicht unterstützt. Noch offen für andere Vorschläge.

36
FogleBird

Ich würde empfehlen, images2gif von visvis nicht zu verwenden, da es Probleme mit PIL/Pillow hat und nicht aktiv gewartet wird (ich sollte es wissen, da ich der Autor bin).

Verwenden Sie stattdessen imageio , das entwickelt wurde, um dieses Problem und mehr zu lösen, und soll bleiben.

Schnelle und schmutzige Lösung:

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

Verwenden Sie für längere Filme den Streaming-Ansatz:

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)
167
Almar

Seit Juni 2009 enthält der ursprünglich zitierte Blogbeitrag eine Methode zum Erstellen animierter GIFs in den Kommentaren . Laden Sie das Skript images2gif.py (früher images2gif.py , Aktualisierung mit freundlicher Genehmigung von @geographika) herunter.

Um beispielsweise die Frames in einem GIF umzukehren, gehen Sie wie folgt vor:

#!/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
kostmo

Ich habe images2gif.py benutzt, was einfach zu bedienen war. Es schien jedoch die Dateigröße zu verdoppeln ..

26 110kb PNG-Dateien, ich erwartete 26 * 110kb = 2860kb, aber mein_gif.GIF betrug 5,7 MB

Da die GIF 8-Bit-Werte hatte, wurden die Nice-Pngs in der GIF etwas unscharf

Hier ist der Code, den ich verwendet habe:

__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

Hier sind 3 der 26 Frames:

Here are 3 of the 26 frames

das Verkleinern der Bilder hat die Größe reduziert:

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

smaller gif

25
robert king

Um ein Video zu erstellen, können Sie opencv verwenden.

#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
attwad

Es ist keine Python-Bibliothek, aber Mencoder kann das: Encoding aus mehreren Eingabebilddateien . Sie können den Mencoder wie folgt aus Python ausführen:

import os

os.system("mencoder ...")
5
willurd

Mit windows7, python2.7, opencv 3.0 funktioniert Folgendes für mich:

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
Jacek Słoma

Alte Frage, viele gute Antworten, aber vielleicht ist noch eine andere Alternative interessant ...

Das numpngw-Modul, das ich kürzlich in github ( https://github.com/WarrenWeckesser/numpngw ) abgelegt habe, kann animierte PNG-Dateien aus numpy-Arrays schreiben. (Update: numpngw ist jetzt auf pypi: https://pypi.python.org/pypi/numpngw .)

Zum Beispiel dieses Skript:

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)

schafft:

 animated png

Sie benötigen einen Browser, der animiertes PNG unterstützt (entweder direkt oder mit einem Plugin), um die Animation anzuzeigen.

4

Ich bin auf diesen Beitrag gestoßen und keine der Lösungen hat funktioniert, also hier meine Lösung, die funktioniert

Probleme mit anderen Lösungen bisher:
1) Keine explizite Lösung, wie die Dauer geändert wird
2) Keine Lösung für die Verzeichniswiederholung außerhalb der Reihenfolge, was für GIFs unerlässlich ist
3) Keine Erklärung zur Installation von imageio für Python 3

installiere imageio wie folgt: python3 -m pip install imageio

Hinweis: Sie sollten sicherstellen, dass Ihre Frames eine Art Index im Dateinamen haben, damit sie sortiert werden können. Andernfalls haben Sie keine Möglichkeit zu wissen, wo die GIF beginnt oder endet

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
4
Daniel McGrath

Wie Warren sagte letztes Jahr, ist dies eine alte Frage. Da die Benutzer die Seite immer noch anzeigen, möchte ich sie auf eine modernere Lösung umleiten. Wie blakev hier sagte, gibt es auf github ein Kissenbeispiel.

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

Hinweis: Dieses Beispiel ist veraltet (gifmaker ist kein importierbares Modul, nur ein Skript). Kissen hat ein GifImagePlugin (dessen Quelle in GitHub ist), aber das Dokument in ImageSequence scheint eine eingeschränkte Unterstützung anzuzeigen (nur Lesen).

4
Nathan

Als eines der oben genannten Mitglieder ist imageio eine großartige Möglichkeit, dies zu tun. In imageio können Sie auch die Bildrate einstellen. In Python habe ich tatsächlich eine Funktion geschrieben, mit der Sie das endgültige Bild festlegen können. Ich verwende diese Funktion für wissenschaftliche Animationen, bei denen das Schleifen nützlich ist, der sofortige Neustart jedoch nicht. Hier ist der Link und die Funktion:

So erstellen Sie ein GIF mit 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

Hast du PyMedia probiert? Ich bin nicht zu 100% sicher, aber es sieht so aus, als dieses Tutorial-Beispiel Ihr Problem anspricht.

4
Jakub Šturc

Ich poste eine weitere Antwort, da sie einfacher ist als alles, was bisher veröffentlicht wurde:

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)

bestehende Bilder verwenden:

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)

Und da zu niedrige Versionen des Kissens lautlos versagen, ist hier eine Bonusversion mit Bibliotheksversionsprüfung:

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

Das Einfachste, was für mich funktioniert, ist das Aufrufen eines Shell-Befehls in Python.

Wenn Ihre Bilder wie dummy_image_1.png, dummy_image_2.png ... dummy_image_N.png gespeichert sind, können Sie die Funktion verwenden:

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

Einfach ausführen: 

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

Dadurch wird Ihre GIF-Datei my_output.gif erstellt.

2
Pkjain

Die Aufgabe kann abgeschlossen werden, indem das zweizeilige Python-Skript im selben Ordner wie die Bilddatei ausgeführt wird. Für png-formatierte Dateien lautet das Skript - 

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

Ich suchte nach einem Single-Line-Code und fand Folgendes für meine Bewerbung. Folgendes habe ich getan:

Erster Schritt: _ ​​Installieren Sie ImageMagick über den Link unten

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

 enter image description here

Zweiter Schritt: _ ​​Richten Sie die cmd-Zeile auf den Ordner, in dem sich die Bilder (in meinem Fall .png-Format) befinden.

 enter image description here

Dritter Schritt: _ ​​Geben Sie den folgenden Befehl ein 

magick -quality 100 *.png outvideo.mpeg

 enter image description here

Danke FogleBird für die Idee!

1
MedImage

Ich habe gerade folgendes ausprobiert und war sehr nützlich:

Laden Sie zuerst die Bibliotheken Figtodat und images2gif in Ihr lokales Verzeichnis herunter. 

Zweitens Sammeln Sie die Figuren in einem Array und konvertieren Sie sie in ein animiertes 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
Cro-Magnon

Ich bin auf PILs ImageSequence Modul gestoßen, das für eine bessere (und mehr Standard) GIF-Animation sorgt. Ich benutze auch dieses Mal die Methode after () von Tk, die besser ist als 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
Apostolos

Eine einfache Funktion, die GIFs erstellt:

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 __== "__main__":
    main()
0
Willem