web-dev-qa-db-fra.com

Générez par programme des vidéos ou des GIF animés en Python?

J'ai une série d'images dont je veux créer une vidéo. Idéalement, je pourrais spécifier une durée d'image pour chaque image, mais une cadence fixe conviendrait également. Je fais cela dans wxPython, afin que je puisse rendre à un wxDC ou je peux enregistrer les images dans des fichiers, tels que PNG. Existe-t-il une bibliothèque Python qui me permette de créer une vidéo (AVI, MPG, etc.) ou un GIF animé à partir de ces images?

Edit: J'ai déjà essayé PIL et cela ne semble pas fonctionner. Quelqu'un peut-il me corriger avec cette conclusion ou suggérer une autre boîte à outils? Ce lien semble confirmer ma conclusion à propos de PIL: http://www.somethinkodd.com/oddthinking/2005/12/06/python-imaging-library-pil-and-animated-gifs/

164
FogleBird

Eh bien, maintenant j'utilise ImageMagick. J'enregistre mes images sous forme de fichiers PNG, puis j'appelle le fichier convert.exe d'ImageMagick à partir de Python pour créer un fichier GIF animé. La bonne chose à propos de cette approche est que je peux spécifier une durée de trame pour chaque trame individuellement. Malheureusement, cela dépend de l'installation d'ImageMagick sur la machine. Ils ont un wrapper Python mais il a l'air plutôt nul et non supporté. Toujours ouvert à d'autres suggestions.

36
FogleBird

Je vous recommande de ne pas utiliser images2gif de visvis car il a des problèmes avec PIL/Pillow et qu'il n'est pas entretenu de manière active (je devrais le savoir, car je suis l'auteur).

Au lieu de cela, veuillez utiliser imageio , qui a été développé pour résoudre ce problème et plus encore, et qui est destiné à rester.

Solution rapide et sale:

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

Pour les films plus longs, utilisez la méthode de diffusion en continu:

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

Depuis juin 2009, l'article de blog cité à l'origine dispose d'une méthode pour créer des GIF animés dans les commentaires . Téléchargez le script images2gif.py (anciennement images2gif.py , mise à jour avec la permission de @geographika).

Ensuite, pour inverser les images dans un gif, par exemple:

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

J'ai utilisé images2gif.py qui était facile à utiliser. Il semble cependant que la taille du fichier a doublé ..

26 fichiers PNG de 110 Ko, je m'attendais à 26 * 110 Ko = 2860 Ko, mais mon_gif.GIF était de 5,7 Mo

Aussi parce que le GIF était de 8 bits, le png de Nice est devenu un peu flou dans le GIF

Voici le code que j'ai utilisé:

__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

Voici 3 des 26 cadres:

Here are 3 of the 26 frames

rétrécir les images réduit la taille:

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

smaller gif

25
robert king

Pour créer une vidéo, vous pouvez utiliser 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
attwad

Ce n'est pas une bibliothèque python, mais mencoder peut le faire: Encodage à partir de plusieurs fichiers image en entrée . Vous pouvez exécuter mencoder à partir de python comme ceci:

import os

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

Avec windows7, python2.7, opencv 3.0, ce qui suit fonctionne pour moi:

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

Vieille question, beaucoup de bonnes réponses, mais une autre alternative pourrait toujours intéresser ...

Le module numpngw que j'ai récemment mis en place sur github ( https://github.com/WarrenWeckesser/numpngw ) peut écrire des fichiers PNG animés à partir de tableaux numpy. (Update: numpngw est maintenant sur pypi: https://pypi.python.org/pypi/numpngw .)

Par exemple, ce script:

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)

crée:

 animated png

Vous aurez besoin d'un navigateur prenant en charge le format PNG animé (directement ou avec un plugin) pour visualiser l'animation.

4
Warren Weckesser

Je suis tombé sur ce post et aucune des solutions n’a fonctionné. Voici donc ma solution qui fonctionne

Problèmes avec d’autres solutions jusqu’à présent:
1) Pas de solution explicite quant à la façon dont la durée est modifiée
2) Pas de solution pour l'itération d'annuaire hors service, essentielle pour les GIF
3) Pas d'explication sur la façon d'installer imageio pour python 3

installe imageio comme ceci: python3 -m pip installe imageio

Remarque: vous devrez vous assurer que vos cadres ont une sorte d'index dans le nom du fichier afin qu'ils puissent être triés, sinon vous ne pourrez pas savoir où commence ou finit le 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
4
Daniel McGrath

Comme Warren l'a dit l'année dernière, c'est une vieille question. Étant donné que les gens semblent toujours consulter la page, j'aimerais les rediriger vers une solution plus moderne. Comme dit blakev ici , il y a un exemple Pillow sur 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()

Remarque: Cet exemple est obsolète (gifmaker n'est pas un module importable, seulement un script). Oreiller a GifImagePlugin (dont la source est sur GitHub ), mais le document sur ImageSequence semble indiquer un support limité (lecture seule)

4
Nathan

Comme l’a mentionné un membre ci-dessus, imageio est un excellent moyen de le faire. imageio vous permet également de définir la fréquence d'images. En fait, j'ai écrit une fonction en Python qui vous permet de définir un blocage de la dernière image. J'utilise cette fonction pour les animations scientifiques où la boucle est utile mais pas le redémarrage immédiat. Voici le lien et la fonction:

Comment créer un GIF avec 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

4

Avez-vous essayé PyMedia ? Je ne suis pas sûr à 100%, mais il ressemble à cet exemple de didacticiel cible votre problème.

4
Jakub Šturc

Je poste une réponse de plus car c'est plus simple que tout ce qui a été posté jusqu'à présent:

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)

en utilisant des images existantes:

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)

Et, comme les versions trop basses de pillow échouent silencieusement, voici une version bonus avec vérification de version de bibliothèque:

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
Mateusz Konieczny

La solution la plus simple pour moi consiste à appeler une commande Shell en Python.

Si vos images sont stockées telles que dummy_image_1.png, dummy_image_2.png ... dummy_image_N.png, vous pouvez utiliser la fonction:

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

Il suffit d'exécuter: 

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

Cela construira votre fichier gif my_output.gif.

2
Pkjain

La tâche peut être complétée en exécutant le script python de deux lignes à partir du même dossier que la séquence de fichiers image. Pour les fichiers au format png, le script est - 

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

Je recherchais un code à une seule ligne et trouvai ce qui suit pour mon application. Voici ce que j'ai fait:

Première étape:Installez ImageMagick à partir du lien ci-dessous

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

 enter image description here

Deuxième étape:Pointez la ligne de commande sur le dossier où sont placées les images (au format .png dans mon cas)

 enter image description here

Troisième étape:Tapez la commande suivante 

magick -quality 100 *.png outvideo.mpeg

 enter image description here

Merci FogleBird pour l'idée!

1
MedImage

Je viens d'essayer ce qui suit et j'ai été très utile:

Commencez par télécharger les bibliothèques Figtodat et images2gif dans votre répertoire local. 

Deuxièmement, rassemblez les figures dans un tableau et convertissez-les en gif animé:

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

Je suis tombé sur le module ImageSequence de PIL, qui offre une meilleure (et plus standard) information GIF. J'utilise aussi la méthode after () de Tk cette fois, qui est meilleure que 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

Une fonction simple permettant de créer des GIF:

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