Pregunta

Tengo una serie de imágenes a partir de las cuales quiero crear un video.Lo ideal sería especificar una duración de fotograma para cada fotograma, pero una velocidad de fotogramas fija también estaría bien.Estoy haciendo esto en wxPython, para poder renderizar en un wxDC o guardar las imágenes en archivos, como PNG.¿Existe una biblioteca de Python que me permita crear un vídeo (AVI, MPG, etc.) o un GIF animado a partir de estos fotogramas?

Editar:Ya probé PIL y no parece funcionar.¿Alguien puede corregirme con esta conclusión o sugerir otro conjunto de herramientas?Este enlace parece respaldar mi conclusión sobre PIL: http://www.somethinkodd.com/oddthinking/2005/12/06/python-imaging-library-pil-and-animated-gifs/

¿Fue útil?

Solución 3

Bueno, ahora estoy usando ImageMagick. Puedo guardar mis cuadros como archivos PNG y luego llamar a convert.exe de ImageMagick desde Python para crear un GIF animado. Lo bueno de este enfoque es que puedo especificar una duración de trama para cada fotograma individual. Por desgracia, esto depende de ImageMagick está instalado en la máquina. Tienen un envoltorio de Python pero parece bastante horrible y sin apoyo. Aún abierto a otras sugerencias.

Otros consejos

Me gustaría recomendar no usar images2gif de visvis porque tiene problemas con el PIL / almohada y no se mantiene de forma activa (debería saber, porque yo soy el autor).

En su lugar, utiliza ImageIO , que fue desarrollado para resolver este problema y más, y se intentará que sea.

solución rápida y sucia:

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

Para las películas más largas, utilice el método de streaming:

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)

A partir de junio de 2009, el citado principio de blog tiene un método para crear GIF animados en el comentarios. Descargar el guión images2gif.py (anteriormente images2gif.py , actualizar cortesía de @geographika).

A continuación, para revertir los marcos en un gif, por ejemplo:

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

solía imagenes2gif.py que era fácil de usar.Sin embargo, pareció duplicar el tamaño del archivo.

26 archivos PNG de 110 kb, esperaba 26*110 kb = 2860 kb, pero my_gif.GIF tenía 5,7 MB

Además, debido a que el GIF era de 8 bits, los bonitos png se volvieron un poco borrosos en el GIF.

Aquí está el código que utilicé:

__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

Aquí están 3 de los 26 fotogramas:

Here are 3 of the 26 frames

reducir las imágenes redujo el tamaño:

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

smaller gif

Para crear un vídeo, se puede usar 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])

Me encontré con este post y ninguna de las soluciones trabajado, por lo que aquí está mi solución que funciona

Los problemas con otras soluciones hasta el momento: Read 1) Sin solución explícita en cuanto a cómo la duración se modifica
2) No hay solución para la iteración de directorio de pedidos, que es esencial para los GIF
3) No hay ninguna explicación de cómo instalar ImageIO para Python 3

instalar ImageIO como esto: python3 -m pip instalar ImageIO

Nota: usted querrá asegurarse de que sus cuadros tienen algún tipo de índice en el nombre del archivo para que puedan ser ordenados, de lo contrario no tiene manera de saber dónde empieza o termina el 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

No es una biblioteca de Python, pero mencoder puede hacer eso: codificación desde múltiples archivos de imagen de entrada . Puede ejecutar el mencoder del pitón de esta manera:

import os

os.system("mencoder ...")

Al igual que Warren dijo año pasado , esto es una cuestión de edad. Dado que las personas todavía parecen estar viendo la página, me gustaría redirigirlos a una solución más moderna. Como dijo blakev aquí , hay un ejemplo de almohadilla en 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()

Nota: Este ejemplo es obsoleta (gifmaker no es un módulo importable, solamente un script). Almohada tiene un GifImagePlugin (cuya fuente es en GitHub ), pero el doc en ImageSequence parece indicar un apoyo limitado (sólo lectura)

Estoy publicar una respuesta más, ya que es más sencillo que todo lo publicado hasta ahora:

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)

usando imágenes existentes:

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)

Y, versiones como demasiado bajos de almohada están fallando en silencio aquí es como una versión de la prima con comprobación de versión de biblioteca:

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)

¿Ha tratado PyMedia ? No estoy 100% seguro, pero parece que este ejemplo tutorial se dirige a su problema .

Con Windows 7, python2.7, OpenCV 3.0, las siguientes obras para mí:

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)

pregunta antiguo, un montón de buenas respuestas, pero que aún puede haber interés en otra alternativa ...

El módulo numpngw que recientemente he puesto en GitHub ( https://github.com/WarrenWeckesser/numpngw ) se puede escribir archivos PNG animados a partir de matrices numpy. ( Actualizar : numpngw es ahora en PyPI: https: //pypi.python. org / PyPI / numpngw .)

Por ejemplo, esta secuencia de comandos:

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)

crea:

png animada

Usted necesitará un navegador que soporte animada PNG (ya sea directamente o con un plug-in) para visualizar la animación.

Como uno de los miembros se ha mencionado anteriormente, ImageIO es una gran manera de hacer esto. ImageIO también le permite establecer la velocidad de fotogramas, y que en realidad escribió una función en Python que le permite establecer un alto en el cuadro final. Yo uso esta función para animaciones científicas donde bucle es útil, pero no es reiniciar inmediatamente. Aquí está el enlace y la función:

Como hacer un GIF usando 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)

Ejemplo GIF usando este método

Lo más fácil que hace que funcione para mí está llamando un comando shell en Python.

Si las imágenes se almacenan como dummy_image_1.png, dummy_image_2.png ... dummy_image_N.png, a continuación, puede utilizar la función:

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

Simplemente ejecute:

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

Esto construir su my_output.gif archivo GIF.

La tarea puede completarse mediante la ejecución del script en Python dos líneas de la misma carpeta que la secuencia de archivos de imágenes. Para los archivos con formato PNG es el guión -

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

Yo estaba buscando un código de una sola línea y encontré lo siguiente para trabajar para mi aplicación. Esto es lo que hice:

Primer paso: Instalar ImageMagick desde el siguiente enlace

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

introducir descripción de la imagen aquí

Segundo paso: punto de la línea de cmd a la carpeta donde las imágenes (en formato .png mi caso) se colocan

introducir descripción de la imagen aquí

Tercer paso: escriba el siguiente comando

magick -quality 100 *.png outvideo.mpeg

introducir descripción de la imagen aquí

Gracias a la idea FogleBird!

he intentado lo siguiente y era muy útil:

En primer Descargar las bibliotecas Figtodat y images2gif a su directorio local.

En segundo lugar Recoger las figuras en una matriz y convertirlos a un gif animado:

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)

Me encontré con Módulo de PIL ImageSequence, que ofrece una aninmation GIF mejor (y más estándar). También uso después () método de este tiempo de Tk, que es mejor 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()

Una función simple que hace que los archivos 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 __name__ == "__main__":
    main()

Aquí es cómo lo hace usando Sólo PIL (instalación con: 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)

Es realmente increíble ... Todos están proponiendo algún paquete especial para la reproducción de un archivo GIF animado, en el momento en que se puede hacer con Tkinter y el módulo PIL clásico!

Aquí está mi propio método de animación GIF (que creé hace un tiempo). Muy simple:

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

Puede configurar sus propios medios para detener la animación. Déjame saber si te gusta para obtener la versión completa con botones de reproducción / pausa / dejar de fumar.

Nota: No estoy seguro de si las tramas consecutivas se leen de la memoria o del archivo (disco). En el segundo caso, sería más eficiente si todos leen a la vez y se guardan en una matriz (lista). (No estoy tan interesado en saber! :)

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top