Программно генерировать видео или анимированный GIF в Python? - PullRequest
176 голосов
/ 15 апреля 2009

У меня есть серия изображений, из которых я хочу создать видео. В идеале я мог бы указать длительность кадра для каждого кадра, но фиксированная частота кадров тоже подойдет. Я делаю это в wxPython, так что я могу рендерить в wxDC или я могу сохранить изображения в файлы, такие как PNG. Существует ли библиотека Python, которая позволит мне создавать из этих кадров видео (AVI, MPG и т. Д.) Или анимированный GIF?

Редактировать: я уже пробовал PIL, и, похоже, он не работает. Может кто-то исправить меня с этим выводом или предложить другой инструментарий? Эта ссылка, кажется, подтверждает мое заключение относительно PIL: http://www.somethinkodd.com/oddthinking/2005/12/06/python-imaging-library-pil-and-animated-gifs/

Ответы [ 20 ]

192 голосов
/ 11 марта 2016

Я бы рекомендовал не использовать 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)
41 голосов
/ 04 марта 2010

По состоянию на июнь 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)
38 голосов
/ 16 апреля 2009

Ну, теперь я использую ImageMagick. Я сохраняю свои кадры в виде файлов PNG, а затем вызываю ImageMagick convert.exe из Python для создания анимированного GIF-файла. Хорошая вещь об этом подходе - я могу указать длительность кадра для каждого кадра отдельно. К сожалению, это зависит от установки ImageMagick на компьютере. У них есть оболочка Python, но это выглядит довольно дрянно и не поддерживается. Все еще открыты для других предложений.

25 голосов
/ 30 апреля 2012

Я использовал images2gif.py , который был прост в использовании. Похоже, он удвоил размер файла ..

26 PNG-файлов размером 110 КБ, я ожидал 26 * 110 КБ = 2860 КБ, но my_gif.GIF был 5,7 МБ

Также из-за того, что 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

18 голосов
/ 30 июля 2009

Для создания видео вы можете использовать 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 голосов
/ 11 июня 2016

Как сказал Уоррен в прошлом году , это старый вопрос. Поскольку люди все еще просматривают страницу, я бы хотел перенаправить их на более современное решение. Как сказал Блекев здесь , есть пример Pillow на 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 , кажется, указывает на ограниченную поддержку (только чтение)

5 голосов
/ 15 августа 2018

Я наткнулся на этот пост, и ни одно из решений не сработало, поэтому вот мое решение, которое работает

Проблемы с другими решениями на данный момент:
1) Нет явного решения относительно того, как изменяется продолжительность
2) Нет решения для итерации каталога не по порядку, что важно для GIF
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('movie.gif'), images, duration = 0.04) # modify duration as needed
5 голосов
/ 16 апреля 2009

Это не библиотека Python, но Mencoder может сделать это: Кодирование из нескольких файлов входных изображений . Вы можете выполнить mencoder из python следующим образом:

import os

os.system("mencoder ...")
4 голосов
/ 28 июля 2018

Как отметил один из участников, 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

4 голосов
/ 22 апреля 2009

Вы пробовали PyMedia ? Я не уверен на 100%, но похоже, этот учебный пример нацелен на вашу проблему

...