Tengo una serie de imágenes de las que quiero crear un video. Idealmente, podría especificar una duración de cuadro para cada cuadro, pero una velocidad de cuadro fija también estaría bien. Estoy haciendo esto en wxPython, para poder renderizar a un wxDC o guardar las imágenes en archivos, como PNG. ¿Hay una biblioteca de Python que me permita crear un video (AVI, MPG, etc.) o un GIF animado a partir de estos marcos?
Edit: Ya probé PIL y parece que no funciona. ¿Puede alguien corregirme con esta conclusión o sugerir otro conjunto de herramientas? Este enlace parece respaldar mi conclusión respecto a la PIL: http://www.somethinkodd.com/oddthinking/2005/12/06/python-imaging-library-pil-and-animated-gifs/
Bueno, ahora estoy usando ImageMagick. Guardo mis marcos como archivos PNG y luego invoco el convert.exe de ImageMagick de Python para crear un GIF animado. Lo bueno de este enfoque es que puedo especificar una duración de cuadro para cada cuadro individualmente. Desafortunadamente, esto depende de que ImageMagick esté instalado en la máquina. Tienen un envoltorio de Python, pero se ve bastante horrible y no es compatible. Todavía abierto a otras sugerencias.
Recomiendo no usar images2gif de visvis porque tiene problemas con PIL/Almohada y no se mantiene activamente (debería saberlo porque soy el autor).
En su lugar, use imageio , que fue desarrollado para resolver este problema y más, y está destinado a permanecer.
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 películas más largas, utilice el enfoque de transmisión:
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, la publicación del blog originalmente citada tiene un método para crear GIF animados en los comentarios . Descargue el script images2gif.py (anteriormente images2gif.py , actualización cortesía de @geographika).
Luego, 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)
Utilicé images2gif.py que fue fácil de usar. Aunque parecía duplicar el tamaño del archivo ...
26 archivos PNG de 110kb, esperaba 26 * 110kb = 2860kb, pero my_gif.GIF era de 5.7 mb
También debido a que el GIF era de 8 bits, los png de Niza 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 cuadros:
encogiendo las imágenes redujo el tamaño:
size = (150,150)
for im in images:
im.thumbnail(size, Image.ANTIALIAS)
Para crear un video, 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])
No es una biblioteca de Python, pero mencoder puede hacer eso: Codificación de múltiples archivos de imagen de entrada . Puedes ejecutar mencoder desde python así:
import os
os.system("mencoder ...")
Me encontré con esta publicación y ninguna de las soluciones funcionó, así que aquí está mi solución que funciona
Problemas con otras soluciones hasta el momento:
1) No hay una solución explícita en cuanto a cómo se modifica la duración
2) No hay solución para la iteración del directorio fuera de orden, que es esencial para los GIF
3) No hay explicación de cómo instalar imageio para python 3
Instala imageio de esta manera: python3 -m pip install imageio
Nota: querrá asegurarse de que sus marcos tengan algún tipo de índice en el nombre del archivo para que puedan ordenarse, de lo contrario no tendrá forma de saber dónde comienza 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
Como dijo Warren el año pasado , esta es una vieja pregunta. Como la gente todavía parece estar viendo la página, me gustaría redirigirlos a una solución más moderna. Al igual que blakev dijo aquí , hay un ejemplo de almohada 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 está desactualizado (gifmaker
no es un módulo importable, solo un script). La almohada tiene un GifImagePlugin (cuya fuente es en GitHub ), pero el documento en ImageSequence parece indicar un soporte limitado (solo lectura)
Con windows7, python2.7, opencv 3.0, lo siguiente funciona 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)
Antigua pregunta, muchas buenas respuestas, pero aún podría haber interés en otra alternativa ...
El módulo numpngw
que recientemente instalé en github ( https://github.com/WarrenWeckesser/numpngw ) puede escribir archivos PNG animados desde una gran cantidad de arrays. ( Actualizar : numpngw
ahora está en pypi: https://pypi.python.org/pypi/numpngw .)
Por ejemplo, este 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)
crea:
Necesitará un navegador que admita PNG animado (ya sea directamente o con un complemento) para ver la animación.
Como un miembro mencionado anteriormente, imageio es una excelente manera de hacer esto. imageio también te permite establecer la velocidad de cuadros, y en realidad escribí una función en Python que te permite establecer una retención en el cuadro final. Utilizo esta función para animaciones científicas donde el bucle es útil pero el reinicio inmediato no lo es. Aquí está el enlace y la función:
Cómo 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)
¿Has probado PyMedia ? No estoy 100% seguro, pero parece que este ejemplo de tutorial aborda su problema.
Estoy publicando una respuesta más, ya que es más simple 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)
utilizando 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, como las versiones demasiado bajas de la almohada están fallando silenciosamente aquí es como una versión adicional con la versión de la 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)
Lo más fácil que lo hace funcionar para mí es llamar un comando de Shell en Python.
Si sus imágenes se almacenan como dummy_image_1.png, dummy_image_2.png ... dummy_image_N.png, entonces puede usar 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)
Solo ejecuta:
grid2gif("dummy_image*.png", "my_output.gif")
Esto construirá su archivo gif my_output.gif.
La tarea se puede completar ejecutando el script de python de dos líneas desde la misma carpeta que la secuencia de archivos de imágenes. Para archivos formateados en png el script es -
from scitools.std import movie
movie('*.png',fps=1,output_file='thisismygif.gif')
Estaba buscando un código de línea única y encontré que lo siguiente funciona para mi aplicación. Aquí esta lo que hice:
Primer paso: Instale ImageMagick desde el siguiente enlace
https://www.imagemagick.org/script/download.php
Segundo paso: Señale la línea cmd a la carpeta donde se colocan las imágenes (en mi caso, formato .png)
Tercer paso: Escriba el siguiente comando
magick -quality 100 *.png outvideo.mpeg
Gracias FogleBird por la idea!
Acabo de probar lo siguiente y fue muy útil:
Primero descargue las bibliotecas Figtodat
y images2gif
a su directorio local.
En segundo lugar, reúne las figuras en una matriz y conviértelas en 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 topé con el módulo ImageSequencede PIL, que ofrece una mejor (y más estándar) información GIF. También uso el método after () de Tk esta vez, 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()