Программно генерировать видео или анимированный 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])
Как сказал Уоррен в прошлом году, Это старый вопрос. Поскольку люди все еще просматривают страницу, Я хотел бы перенаправить их на более современное решение. Как сказал блейкв здесь есть пример подушки на 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)
старый вопрос, много хороших ответов, но все еще может быть интересен другой вариант...
The
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.
Я искал однострочный код и нашел следующее, чтобы работать для моего приложения. Вот что я сделал:
Первый Этап:установите 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 aninmation. Я также использую ТЗ после() метод на этот раз, который лучше, чем времени.сон().
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) нет решения для итерации каталога out of order, что важно для GIFs
3) нет объяснений, как установить imageio для python 3установить imageio, как это: python3-m pip install 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()
вы можете установить свои собственные средства, чтобы остановить анимацию. Дайте мне знать, если вы хотите получить полную версию с кнопками play/pause/quit.
примечание: Я не уверен, если последовательные кадры читать из памяти или из файла (диска). Во втором случае было бы более эффективно, если бы они все читали сразу и сохраняли в массив (список). (Мне не очень интересно это выяснять! :)