Программно генерировать видео или анимированный GIF в Python?
У меня есть серия снимков, которые я хочу создать видео. В идеале я мог бы указать длительность кадра для каждого кадра, но фиксированная частота кадров тоже была бы прекрасной. Я делаю это в wxPython, поэтому я могу визуализировать в wxDC или сохранять изображения в файлы, например PNG. Есть ли библиотека Python, которая позволит мне создать либо видео (AVI, MPG и т. д.), либо анимированный GIF из этих кадров?
Edit: я уже пробовал PIL, и это, похоже, не работает. Может кто-нибудь поправить меня с этим выводом или предложить другой инструментарий? Эта ссылка, похоже, подтверждает мой вывод относительно PIL: http://www.somethinkodd.com/oddthinking/2005/12/06/python-imaging-library-pil-and-animated-gifs/
18 ответов
Я бы рекомендовал не использовать images2gif от visvis, потому что он имеет проблемы с PIL/Pillow и не поддерживается активно (я должен знать, потому что я автор).
вместо этого, пожалуйста, используйте imageio, который был разработан для решения этой проблемы и многое другое, и предназначен для пребывания.
быстрое и грязное решение:
import imageio
images = []
for filename in filenames:
images.append(imageio.imread(filename))
imageio.mimsave('/path/to/movie.gif', images)
для более длинных фильмов используйте потоковый подход:
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)
по состоянию на июнь 2009 года первоначально цитируемый пост в блоге имеет метод создания анимированных GIF в комментариях. Скачать скрипт images2gif.py (ранее images2gif.py Обновление учтивость @geographika).
затем, чтобы отменить кадры в gif, например:
#!/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)
Ну, теперь я использую ImageMagick. Я сохраняю свои кадры как PNG-файлы, а затем вызываю преобразование ImageMagick.exe от Python для создания анимированного GIF. Хорошая вещь в этом подходе - я могу указать длительность кадра для каждого кадра отдельно. К сожалению, это зависит от установки ImageMagick на машине. У них есть обертка Python, но она выглядит довольно дерьмовой и неподдерживаемой. Все еще открыт для других предложений.
Я images2gif.py, которым легко пользоваться. Похоже, хоть двойной размер файла..
26 110kb PNG файлов, я ожидал 26 * 110kb = 2860kb, но my_gif.GIF был 5.7 mb
также потому, что GIF был 8bit, хороший png стал немного нечетким в GIF
вот код, который я использую:
__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
вот 3 из 26 кадров:
уменьшение изображений уменьшило размер:
size = (150,150)
for im in images:
im.thumbnail(size, Image.ANTIALIAS)
чтобы создать видео, вы можете использовать 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])
Как сказал Уоррен в прошлом году, Это старый вопрос. Поскольку люди все еще просматривают страницу, Я хотел бы перенаправить их на более современное решение. Как сказал блейкв!--5-->здесь есть пример подушки на 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()
Примечание: этот пример устарел (gifmaker
не является импортируемым модулем, только скриптом). Подушка имеет GifImagePlugin (чей источник на GitHub), но дока на ImageSequence кажется, указывает на ограниченную поддержку (только для чтения)
это не библиотека python, но mencoder может это сделать: кодирование из нескольких входных файлов изображений. Вы можете выполнить mencoder из python следующим образом:
import os
os.system("mencoder ...")
вы пробовали PyMedia? Я не уверен на 100%, но похоже, что учебник цели своей проблемы.
С windows7, python2.7, opencv 3.0, для меня работает следующее:
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)
старый вопрос, много хороших ответов, но все еще может быть интересен другой вариант...
на numpngw
модуль, который я недавно поставил на github (https://github.com/WarrenWeckesser/numpngw) можно писать анимированные PNG-файлы из массивов numpy. (обновление: numpngw
теперь на pypi:https://pypi.python.org/pypi/numpngw.)
например, это сценарий:
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)
обеспечивает:
вам понадобится браузер, который поддерживает анимированный PNG (напрямую или с помощью плагина), чтобы увидеть анимацию.
задача может быть выполнена путем запуска двухстрочного скрипта python из той же папки, что и последовательность файлов изображений. Для файлов в формате png скрипт -
from scitools.std import movie
movie('*.png',fps=1,output_file='thisismygif.gif')
самое простое, что заставляет его работать для меня, - это вызов команды оболочки в Python.
Если ваши изображения хранятся, такие как dummy_image_1.png, dummy_image_2.формат PNG. .. dummy_image_N.png, то вы можете использовать функцию:
import subprocess
def grid2gif(image_str, output_gif):
str1 = 'convert -delay 100 -loop 1 ' + image_str + ' ' + output_gif
subprocess.call(str1, shell=True)
просто выполнить:
grid2gif("dummy_image*.png", "my_output.gif")
это создаст ваш gif-файл my_output.файл gif.
Я искал однострочный код и нашел следующее, чтобы работать для моего приложения. Вот что я сделал:--4-->
Первый Этап: установите ImageMagick по ссылке ниже
https://www.imagemagick.org/script/download.php
Шаг Второй: укажите строку cmd в папку, где находятся изображения (в моем случае .формат png) являются помещено
Шаг Третий: введите следующую команду
magick -quality 100 *.png outvideo.mpeg
спасибо FogleBird за идею!
как один из членов, упомянутых выше, imageio-отличный способ сделать это. imageio также позволяет установить частоту кадров, и я фактически написал функцию в Python, которая позволяет установить удержание на последнем кадре. Я использую эту функцию для научной анимации, где цикл полезен, но немедленного перезапуска нет. Вот ссылка и функция:
как сделать GIF с помощью 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)
Я просто попробовал следующее и был очень полезен:
сначала загрузите библиотеки Figtodat
и images2gif
в локальный каталог.
во-вторых, соберите фигуры в массив и преобразуйте их в анимированный 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)
Я пришел на пильном это ImageSequence модуль, который предлагает для лучшей (и более стандартной) анинмации GIF. Я также использую ТЗ после() метод на этот раз, который лучше, чем времени.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()
я наткнулся на этот пост и ни одно из решений работал, так вот мой решение, что работает
проблемы с другими решениями до сих пор:
1) нет явного решения о том, как изменяется продолжительность
2) нет решения для итерации каталога вне порядка, что важно для GIFs
3) нет объяснения того, как установить imageio для python 3
установить imageio, как это: python3-m pip установить imageio
Примечание: вы хотите убедиться, что ваши кадры имеют какой-то индекс в имени файла, чтобы их можно было отсортировать, иначе вы не сможете узнать, где начинается или заканчивается 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(path, 'movie.gif'), images, duration = 0.04) # modify duration as needed
Это действительно невероятно ... Все предлагают какой-то специальный пакет для воспроизведения анимированного GIF, на данный момент это можно сделать с помощью Tkinter и классического модуля PIL!
вот мой собственный метод анимации GIF (я создал некоторое время назад). Очень просто:
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()
вы можете установить свои собственные средства, чтобы остановить анимацию. Дайте мне знать, если вы хотите получить полную версию с кнопками воспроизведения/паузы/выхода.
примечание: Я не уверен, что последовательные кадры читаются из памяти или из файла (диска). Во втором случае было бы более эффективно, если бы все они читались сразу и сохранялись в массиве (списке). (Мне не так интересно это знать! :)