Программно генерировать видео или анимированный GIF в Python?
У меня есть серия изображений, с которых я хочу создать видео. В идеале я мог бы указать продолжительность кадра для каждого кадра, но фиксированная частота кадров тоже будет прекрасной. Я делаю это в wxPython, поэтому я могу отображать wxDC или я могу сохранить изображения в файлах, например PNG. Есть ли библиотека Python, которая позволит мне создавать либо видео (AVI, MPG и т.д.), Либо анимированный GIF из этих фреймов?
Изменить: я уже пробовал PIL и, похоже, не работает. Может ли кто-то поправить меня этим заключением или предложить другой инструментарий? Эта ссылка, похоже, подкрепляет мой вывод о PIL: http://www.somethinkodd.com/oddthinking/2005/12/06/python-imaging-library-pil-and-animated-gifs/
Ответы
Ответ 1
Хорошо, теперь я использую ImageMagick. Я сохраняю свои кадры в виде файлов PNG, а затем запускаю ImageMagick convert.exe из Python для создания анимированного GIF. Самое приятное в этом подходе - я могу указать продолжительность кадра для каждого кадра отдельно. К сожалению, это зависит от установки ImageMagick на машине. У них есть оболочка Python, но она выглядит довольно дрянной и неподдерживаемой. Все еще открыт для других предложений.
Ответ 2
Я бы рекомендовал не использовать 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)
Ответ 3
По состоянию на июнь 2009 года в опубликованном выше сообщении в блоге есть способ создания анимированных GIF в комментариях. Загрузите script 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)
Ответ 4
Я использовал images2gif.py, который был прост в использовании. Кажется, он удваивает размер файла, но..
26 110kb PNG файлов, я ожидал 26 * 110kb = 2860kb, но my_gif.GIF был 5.7mb
Кроме того, поскольку GIF был 8 бит, хороший 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 кадров:
![Here are 3 of the 26 frames]()
сокращение изображений уменьшило размер:
size = (150,150)
for im in images:
im.thumbnail(size, Image.ANTIALIAS)
![smaller gif]()
Ответ 5
Чтобы создать видео, вы можете использовать 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])
Ответ 6
Я наткнулся на этот пост, и ни одно из решений не сработало, так что вот мое решение, которое работает
Проблемы с другими решениями до сих пор:
1) Нет явного решения относительно того, как изменяется продолжительность
2) Нет решения для итерации каталога не по порядку, что важно для GIF файлов
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('movie.gif'), images, duration = 0.04) # modify duration as needed
Ответ 7
Как сказал Уоррен в прошлом году, это старый вопрос. Поскольку люди все еще, кажется, просматривают страницу, я бы хотел перенаправить их на более современное решение. Как сказал blakev здесь, есть пример подушки на 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, по- видимому, указывает на ограниченную поддержку (только чтение)
Ответ 8
Это не библиотека Python, но Mencoder может сделать это: Кодирование из нескольких входных файлов изображений. Вы можете выполнить mencoder из python следующим образом:
import os
os.system("mencoder ...")
Ответ 9
Я отправляю еще один ответ, так как он проще, чем все, что опубликовано до сих пор:
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)
используя существующие изображения:
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)
И, поскольку слишком низкие версии подушек молча терпят неудачу, вот как бонусная версия с проверкой версии библиотеки:
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)
Ответ 10
Вы пробовали PyMedia? Я не уверен на 100%, но это выглядит как этот пример учебника нацелен на вашу проблему.
Ответ 11
Старый вопрос, много хороших ответов, но все равно может быть интерес к другой альтернативе...
Модуль 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)
создает:
![animated png]()
Для просмотра анимации вам понадобится браузер, который поддерживает анимированный PNG (либо напрямую, либо с помощью плагина).
Ответ 12
С 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)
Ответ 13
Как один из упомянутых выше участников, 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)
![Example GIF using this method]()
Ответ 14
Самое простое, что заставляет его работать для меня, - это вызвать команду оболочки в 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.
Ответ 15
Задача может быть выполнена путем запуска двухстрочного python script из той же папки, что и последовательность файлов изображений. Для файлов в формате png script есть -
from scitools.std import movie
movie('*.png',fps=1,output_file='thisismygif.gif')
Ответ 16
Я искал одиночный код и нашел следующее для работы в моем приложении. Вот что я сделал:
Первый шаг: Установите ImageMagick по ссылке ниже
https://www.imagemagick.org/script/download.php
![введите описание изображения здесь]()
Второй шаг: Направьте строку cmd в папку, где размещены изображения (в моем случае .png)
![введите описание изображения здесь]()
Третий шаг: Введите следующую команду
magick -quality 100 *.png outvideo.mpeg
![введите описание изображения здесь]()
Спасибо FogleBird за идею!
Ответ 17
Я просто попробовал следующее и был очень полезен:
Сначала загрузите библиотеки 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)
Ответ 18
Я пришел к модулю PIL ImageSequence, который предлагает лучшее (и более стандартное) GIF-анонс. На этот раз я также использую метод Tk after(), который лучше, чем 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()
Ответ 19
Простая функция, которая делает 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()
Ответ 20
Вот как вы это делаете, используя только PIL (установка с: 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)
Ответ 21
Это действительно невероятно... Все предлагают специальный пакет для игры в анимированный 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()
Вы можете настроить свои собственные средства, чтобы остановить анимацию. Дайте мне знать, если вы хотите получить полную версию с кнопками play/pause/quit.
Примечание. Я не уверен, что последовательные кадры считываются из памяти или из файла (диска). Во втором случае было бы более эффективно, если бы все они сразу читались и сохранялись в массив (список). (Мне не интересно узнать! :)