プログラムでPythonでビデオまたはアニメーションGIFを生成しますか?


221

動画を作成したい一連の画像があります。理想的には、各フレームのフレーム期間を指定できますが、固定フレームレートでもかまいません。これはwxPythonで行っているので、wxDCにレンダリングしたり、画像をPNGなどのファイルに保存したりできます。これらのフレームからビデオ(AVI、MPGなど)またはアニメーションGIFを作成できるPythonライブラリはありますか?

編集:私はすでにPILを試しましたが、うまくいかないようです。誰かがこの結論で私を訂正したり、別のツールキットを提案できますか?このリンクは、PILに関する私の結論をバックアップするようです:http : //www.somethinkodd.com/oddthinking/2005/12/06/python-imaging-library-pil-and-animated-gifs/

回答:


281

PIL / Pillowに問題があり、アクティブにメンテナンスされていないため、visvisのimages2gifを使用しないことをお勧めします(筆者は知っているので、知っておく必要があります)。

代わりに、この問題などを解決するために開発された、残りの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)

37
また、パラメータduration = 0.5は、各フレームの0.5秒の持続時間を設定します。
Alleo

3
ValueError:モード 'i'で指定されたファイルを読み取るためのフォーマットが見つかりませんでした-Windows 2.7 winpythonでこのエラーが発生します。手がかりはありますか?
Vanko 2016年

1
エラーは、ファイルの読み込みに関連すると思わ@Vanko、あなたはimagio.mimreadを試す、または可能性が多くのフレームとの映画は、ここのようなリーダーオブジェクトを使用する場合:imageio.readthedocs.io/en/latest/...
アルマール2016年

2
@Alleo:「また、パラメーターduration = 0.5は、各フレームの0.5秒の持続時間を設定します」。imageioの期間機能はありますか?もしそうなら、これはどこに文書化されていますか?私はすべてのドキュメントを読みましたが、duration引数についての言及は見つかりませんでした。
Chris Nielsen

3
優れた!imageio in anaconda収量True、イェーイ!
uhoh

47

さて、私は今ImageMagickを使用しています。フレームをPNGファイルとして保存してから、PythonからImageMagickのconvert.exeを呼び出して、アニメーションGIFを作成します。このアプローチの良い点は、各フレームのフレーム期間を個別に指定できることです。残念ながら、これはマシンにインストールされているImageMagickに依存します。彼らはPythonラッパーを持っていますが、それはかなり安っぽく、サポートされていません。まだ他の提案を受け入れる。


21
私はPythonの男ですが、ImageMagickの方がはるかに簡単です。画像のシーケンスを作成し、次のようなものを実行しましたconvert -delay 20 -loop 0 *jpg animated.gif
Nick

私が同意する、これは私が出会った中で最高のソリューションです。ここでは(スティーブBのサンプルコードはで投稿したユーザーに基づいて、最小限の例ですstackoverflow.com/questions/10922285/...は:)pastebin.com/JJ6ZuXdz
andreasdr

ImageMagickを使用すると、次のようなアニメーションGIFのサイズを簡単に変更することもできますconvert -delay 20 -resize 300x200 -loop 0 *jpg animated.gif
Jun Wang

@ニック、どのようにそのコードを実行してGIFを作成しますか?Spyder IDEに何かをインポートする必要がありますか?
MOON

@MOON上記で追加したImageMagicコマンドは、コマンドラインから実行するだけです。
Nick

43

2009年6月の時点で、最初に引用されたブログ投稿には、コメントにアニメーション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)

2
このスクリプトの新しいバージョンがvisvis.googlecode.com/hg/vvmovie/images2gif.pyにあります。これは、パッケージとは別のスタンドアロンスクリプトとして使用できます。
geographika

1
このコメントで言及されているスクリプトは、Macで使用すると、単純に実行した場合でも(name __ == '__ main 'の例を使用して)、常にセグメンテーション違反を引き起こします。正しく動作することを期待して、答えに記載されているスクリプトを試しています。編集-上記の回答で参照されているスクリプトが私のMacで正しく動作することを確認できます。
スキューボ2013年

6
スクリプトをダウンロードするだけでなく、pip egを使用してから、スクリプトで使用pip install visvisしてくださいfrom visvis.vvmovie.images2gif import writeGif
Daniel Farrell 2013年

8
私はこれをPython 2.7.3でWindows 8で試してみましたが、UnicodeDecodeErrorが発生しました: 'ascii'コーデックは、位置6のバイト0xc8をデコードできません。Pythonのimages2gif.pyを実行しているから
reckoner

3
私はvisivis(およびimages2gif)の作成者であり、この目的での使用はお勧めしません。私はimageioプロジェクトの一部としてより良いソリューションに取り組んでいます(私の答えを参照してください)。
アルマー、2016年

40

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)

4
これは受け入れられる答えになるはずです。ありがとう@クリス
ted930511

1
アスタリスク変数は何を保持していますか( "* imgs")?
denisb411

3
これはpython言語の機能です。それはありません反復可能アンパックを。あなたはおおよそ開梱と考えることができますx = [a, b, c]*xのように考えることができたa, b, c(囲む括弧なし)。関数呼び出しでは、これらは同義ですf(*x) == f(a, b, c)。タプルのアンパックでは、反復可能オブジェクトを先頭(最初の要素)と末尾(残りの要素)に分割する場合に特に便利です。これは、この例で行う方法です。
クリス

25

私はimages2gif.pyを使用しました使用するように簡単でした。ただし、ファイルサイズが2倍になっているようです。

26 110kbのPNGファイル、26 * 110kb = 2860kbと予想しましたが、my_gif.GIFは5.7MBでした

また、GIFが8ビットだったため、GIFでnice pngが少しぼやけた

これが私が使ったコードです:

__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

26フレームのうち3フレームは次のとおりです。

26フレームのうち3フレームです

画像を縮小するとサイズが小さくなります:

size = (150,150)
for im in images:
    im.thumbnail(size, Image.ANTIALIAS)

小さいgif


私はこれについてブログに投稿しました。robert
robert king

2
エラーが発生します..ファイル "C:\ Python27 \ lib \ images2gif.py"、行418、writeGifToFile globalPalette = palettes [Occurres.index(max(occur))]のValueError:max()argは空のシーケンス
ハリー

発生はおそらく空です。私のimages2gif.pyファイルには「globalPalette」変数がありません。
ロバート・キング、

どうすれば変更できますか?私はそこにある最新のimages2gif.pyスクリプト(bit.ly/XMMn5h)を使用しています
Harry

4
@robertkingコードでエラーが発生しましたfp.write(globalPalette) TypeError: must be string or buffer, not list
LWZ

19

ビデオを作成するには、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])

9

私はこの投稿に遭遇しましたが、解決策はどれも機能しなかったので、これが機能する私の解決策です

これまでの他のソリューションの問題:
1)期間の変更方法に関する明確なソリューションはありません
2)順不同のディレクトリ反復のソリューションはありません。これはGIFに不可欠です
3) Python用ImageIOでのインストール方法の説明はありません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

1
sort番号付けスキームに先行ゼロが含まれていない場合、予期しない結果が生じる可能性があります。また、なぜ単純なリスト内包の代わりにマップを使用したのですか?
NOH、

私はそうすることをお勧めしますfilenames.append(os.path.join(path, filename))
真実の

Secodning Nohs images = [imageio.imread(f) for f in filenames]は、よりクリーンで、より高速で、よりpythonicです。
Brandon Dube、

6

ウォーレンが昨年言ったように、これは古い質問です。人々はまだページを表示しているようなので、私は彼らをより新しいソリューションにリダイレクトしたいと思います。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インポート可能なモジュールではなく、スクリプトのみです)。PillowにはGifImagePlugin(ソースはGitHubにあります)がありますが、ImageSequenceのドキュメントはサポートが制限されていることを示しているようです(読み取り専用)


5

これはpythonライブラリではありませんが、mencoderはそれを行うことができます。次のようにpythonからmencoderを実行できます。

import os

os.system("mencoder ...")

5

古い質問、良い答えがたくさんありますが、まだ別の選択肢に興味があるかもしれません...

numpngw私は最近、githubの(上に置くことをモジュールhttps://github.com/WarrenWeckesser/numpngw numpyの配列からアニメーションPNGファイルを書き込むことができます)。(更新numpngwpypi: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

アニメーションを表示するには、(直接またはプラグインを使用して)アニメーション化されたPNGをサポートするブラウザーが必要です。


ところで、Chromeも今はそうです。1つの質問-seqは反復可能ですか?「ストリーミング」(つまり、ターゲットAPNGを開き、フレームを1つずつループで追加する)をサポートしていますか?
Tomasz Gandor

任意のイテラブルやストリーミングはサポートしていませんが、将来的にそれが不可能になったわけではありません。:) 提案された拡張機能を使用して、githubページに問題を作成します。この機能のAPIについてアイデアがある場合は、問題でそれらについて説明してください。
Warren Weckesser

私はあなたのレポで問題を引き起こしたいくつかの奇妙なエラーがありました。
mLstudent33

5

上記の1人のメンバーとして、imageioはこれを行うための優れた方法です。imageioを使用すると、フレームレートを設定することもできます。実際に、最終フレームにホールドを設定できる関数をPythonで作成しました。この関数は、ループは役立つが即時の再起動は役に立たない科学的なアニメーションに使用します。リンクと機能は次のとおりです。

Pythonを使用してGIFを作成する方法

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)

このメソッドを使用したGIFの例



4

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)

3

これを機能させる最も簡単な方法は、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が作成されます。


2

画像ファイルのシーケンスと同じフォルダーから2行のpythonスクリプトを実行することにより、タスクを完了することができます。png形式のファイルの場合、スクリプトは-

from scitools.std import movie
movie('*.png',fps=1,output_file='thisismygif.gif')

1
試してみましたが、Python 2.6では動作しませんでした。返される: "scitools.easyviz.movi​​e関数がコマンドを実行します:/ convert -delay 100 g4testC _ *。png g4testC.gif / Invalid Parameter-100"
Dan H

確かに問題はPythonにありません。システムにimagemagickを再インストールして、再試行してください。
ArKE、2015年

2

1 行のコードを探していましたをところ、次のアプリケーションで機能することがわかりました。これが私がしたことです:

最初のステップ: 下のリンクからImageMagickをインストールします

https://www.imagemagick.org/script/download.php

ここに画像の説明を入力してください

2番目のステップ: 画像(私の場合は.png形式)が配置されているフォルダーにcmd行をポイントします

ここに画像の説明を入力してください

3番目のステップ: 次のコマンドを入力します

magick -quality 100 *.png outvideo.mpeg

ここに画像の説明を入力してください

FogleBirdに感謝します。


0

私は次のことを試してみましたが、とても役に立ちました:

まず、ライブラリFigtodatimages2gifローカルディレクトリにダウンロードします。

次に、数字を配列で収集し、アニメーション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)

0

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()

0

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()

0

画像のgifへの変換についてお問い合わせいただきありがとうございます。ただし、元の形式がMP4の場合は、FFmpegを使用できます。

ffmpeg -i input.mp4 output.gif

-1

それは本当に素晴らしいです... Tkinterと古典的なPILモジュールでそれができる現時点で、すべてがアニメーションGIFを再生するためのいくつかの特別なパッケージを提案しています!

これが私自身の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()

アニメーションを停止する独自の方法を設定できます。再生/一時停止/終了ボタン付きの完全版を入手したい場合はお知らせください。

注:連続したフレームがメモリから読み取られたか、ファイル(ディスク)から読み取られたかはわかりません。2番目のケースでは、すべてを一度に読み取り、配列(リスト)に保存する方が効率的です。(私は調べるのにそれほど興味がない!:)


1
通常sleep、GUIのメインスレッドで呼び出すことはお勧めしません。このafterメソッドを使用して、定期的に関数を呼び出すことができます。
ブライアンオークリー

おっしゃる通りですが、これがポイントではありませんね。ポイントはメソッド全体です。だから、私はむしろそれに対する反応を期待しています!
Apostolos

1
私はあなたの答えを改善する方法について助言しようとしていた。
ブライアンオークリー

ところで、私は通常tk.after()自分を使用しています。しかし、ここではコードをできるだけ単純にする必要がありました。このGIFアニメーションメソッドを使用する人は誰でも、独自の遅延関数を適用できます。
Apostolos

やっと!はい、これは確かに非常に良い点です。私は話題外でした!ありがとう、@ Novel。(時間遅延法について話していたブライアンなど、他の人がこれをどのように見逃したかを知るのは興味深いです!)
Apostolos
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.