サイトアイコン RのWeb制作

Jupyter Notebook「7ブロック」でかんたん複数動画のフレームの切り出し(Movie To Image)

はじめに

機械学習のために、動画から画像のデータセットを取り出す必要がありました。
動画 → 画像の変換には多くのフリーソフトはありますが、
今回使おうとした「MOV」ファイルが読み込めるまともなフリーソフトがありませんでした。
※更新停止していたり、ウイルスだと判定されたり散々でした…。

というわけで、Pythonで書いたほうが早いなとなりました。

下記にコードを載せています。
よくわからない人はダウンロードにあるzipファイル(テスト動画付き)を使ってください。

Windows、Macどちらでも使用可能です。

ダウンロード

MovieToImage.zip

コード

使用するモジュールを読み込みます。

import os
import cv2
import glob
from tqdm import tqdm

※インストールできていなければインストールしてください。

基礎設定を行います。
デフォルトでは、Jupyterファイルのあるフォルダの中にimageフォルダを作り、その中に保存します。

file_name = 'IMG_0001.MOV' # 読み込みファイル
fps = 30 # fps(1秒に1枚切り取る)
dir_name = 'image' # 保存dir
image_name = '_img%s.jpg' # 出力ファイル名

保存用関数を設定します。
1フレーム単位で保存するとほぼ動きがない画像になるので、1秒単位で切り分けます。

def video_to_images(video_file=file_name, root_dir='', save_dir=dir_name, image_file=image_name, fps=fps):
    # saveディレクトリを作成
    if not os.path.exists(save_dir):
        os.makedirs(save_dir)
    
    # 各ムービーのディレクトリを作成
    image_dir = save_dir + '/' + video_file + '/'
    if not os.path.exists(image_dir):
        os.makedirs(image_dir)
        
    # 未設定の場合fpsを設定
    fps = 60 if fps is None else fps
    
    # ビデオファイル名を設定
    read_file = root_dir + video_file
    
    # Videoをフレーム単位で切り取る
    i = 0
    cap = cv2.VideoCapture(read_file)
    while(cap.isOpened()):
        flag, frame = cap.read()
        # 読み込めなかったら終了
        if flag == False:
            break
        # 1枚進める
        i += 1
        if i % fps != 0: # 1秒1枚を出力
            continue
        fname = image_dir + video_file + image_file % str(int(i/fps)).zfill(6)
        cv2.imwrite(fname, frame)
        print('No.%s Save [%s]' % (i, fname))

    cap.release() # capリリース

テストとして1動画ファイルを切り取ってみます。
エラーでなければ、imageフォルダの中に動画ファイル名ごとにフォルダが作成されています。
1枚ずつ切り出すことができました。

# 1画像ファイルを加工
video_to_images()

複数動画の加工を行います。
複数動画を入れるフォルダと拡張子名を設定します。

# 基礎設定
dir_mov = 'mov' # ムービー用dir
file_ex = '.mov' # ムービー拡張子名

globでファイル検索をかけ、filesに格納します。

files = glob.glob(dir_mov + "/*" + file_ex)

実行します。
簡単に処理が終わりました。

# Cut開始
for path in tqdm(files):
    print("#-----------------------------------------------------------#")
    print("# Start MovieToImage... file:%s" % path)
    print("#-----------------------------------------------------------#")
    file_name_one = path.split("\\")[-1]
    video_to_images(video_file=file_name_one, root_dir=dir_mov)

おわりに

Yahoo知恵袋か何かで、「動画ソフトでプリントスクリーン→ペイントすると良い」と当たり前のように書かれていて驚きました。
それちょっと辛くない?時間かかりすぎでしょ・・・というわけで今回作成しました。
何かあればメッセージを残してくださいませ。

モバイルバージョンを終了