Python備忘録:ジェネレータの実際

ジェネレータはnext関数を使って呼び出す。この関数の呼び出し毎にジェネレータは一定の長さのデータを吐き出す。この機構を使って動画ファイルをフレーム毎に読みこむことにする。このような例をimageioモジュールで見てみる。このモジュールは様々な画像ファイル(動画ファイルを含む)を処理することができる。今回の例は動画ファイルを読み込みヴィデオ表示するPythonプログラムである。

プログラム例


#coding: utf-8
import tkinter as tk, threading
import imageio
from PIL import Image, ImageTk

video_name = "test.mp4" #ここにヴィデオ・ファイル名を書く
video = imageio.get_reader(video_name)
gen = video.iter_data()
def stream(label):
    def showlabel():
        global count
        try:
            image=next(gen)
        except: 
            return
        frame_image = ImageTk.PhotoImage(Image.fromarray(image))
        label.config(image=frame_image)
        label.image = frame_image
        label.after(14, showlabel) #フレーム・レイトの調整
    showlabel()

if __name__ == "__main__":

    root = tk.Tk()
    root.title('TKinterでヴィデオを見る')
    my_label = tk.Label(root)
    my_label.pack()
    thread = threading.Thread(target=stream, args=(my_label,))
    thread.daemon = 1
    thread.start()
    root.mainloop()

赤い文字の部分がジェネレータに関連する部分で、video = imageio.get_reader(video_name)はファイルを読み込む機構の設定で、video.iter_data()でその機構にジェネレータの性格を付与している。

iter_data()
Iterate over all images in the series. (Note: you can also iterate over the reader object.)

と説明がある。
image=next(gen)でフレーム毎にデータを読み込みそれをimageに代入している。フレーム毎にデータを読みこみデータが尽きるとエラーになるのでエラー処理をしている。