
Pythonで動画から静止部分を抜き出してみた
Pythonで、動画ファイルの中から静止している部分を選んで静止画として抜き出してみました。
目次
動画から静止画を切り出したい
iPadで「へのへのもへじ」を描いた動画を撮りました。動画を撮る際に、1画毎に数秒静止するようにしました。この動画から、Pythonを使って静止部分を静止画として抜き出してみたいと思います。
これが出来ると、アプリの操作説明の資料が作りやすくなるかもしれません。
動画から静止部分を取り出す手順
PythonでOpenCVを使用します。
OpenCVで1フレームずつ読み取りをして、前後のフレームを画像として比較して、特定の期間の間に変化がない場合にそのフレームを静止画として出力するようにします。
画像が変化しているかどうかは、下記の手順で判定します。
フレームをグレースケールに変換する。
前のフレーム(グレースケール)との差分画像を作る。
差分画像の各ピクセルのうち最大値を調べる。
差分の最大値が閾値より小さければ、画像は変化していないものとする。
コード
下記のようなコードにしました。入力はMP4、出力はPNGです。
import cv2
import sys
import numpy as np
import argparse
# コマンドライン引数の設定
DESC = 'Pick up stop scene, and out put the frame as PNG image.'
parser = argparse.ArgumentParser(description=DESC)
parser.add_argument('fname', help='MP4 Video file name.')
parser.add_argument('--threshold', default=10, type=int, help='Threshold of changed.')
parser.add_argument('--duration', default=2, type=int, help='Duration frames to stop.')
args = parser.parse_args()
# ビデオデータの読み込み
video_data = cv2.VideoCapture(args.fname)
if video_data.isOpened() == False:
print('Video file is not opened.')
sys.exit()
# ビデオのフレーム数を調べる
frame_count = video_data.get(cv2.CAP_PROP_FRAME_COUNT)
print('Number of frames : ', frame_count)
# 静止画像の抜き出し
ret, prev_frame = video_data.read()
prev_frame_gray = cv2.cvtColor(prev_frame, cv2.COLOR_BGR2GRAY)
stop_counter = 0
while True:
ret, frame = video_data.read()
if ret:
frame_gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
frame_diff = cv2.absdiff(prev_frame_gray, frame_gray)
frame_distance = np.max(frame_diff)
if frame_distance < args.threshold:
if stop_counter == args.duration:
c = video_data.get(cv2.CAP_PROP_POS_FRAMES)
cv2.imwrite( str(int(c)) + '.png', frame)
stop_counter = stop_counter + 1
else:
stop_counter = stop_counter + 1
else:
stop_counter = 0
prev_frame_gray = frame_gray
else:
break
# ビデオファイルの解放
video_data.release()
Python環境にNumPyとOpenCVをインストールしておく必要があります。
コマンドライン引数で、ファイル名といくつかの閾値の設定が出来るようにしてみました。閾値の指定をしない場合は、デフォルト値が使われます。
実施例
試してみます。
> python test.py test.mp4
出力される画像は、こんな感じになります。











まずまず、1画ずつの画像になりました。
公開日
広告
作ってみたカテゴリの投稿
- PythonでFizzBuzz問題をやってみた
- PythonでPDFファイルのサムネイル画像を作る
- Pythonでオブジェクトを選択してクロップするツールを作ってみた
- Pythonでデータロガーのログから瞬断を抽出してみる
- Pythonで写真の中の線を抽出してみた
- Pythonで動画から静止部分を抜き出してみた
- Pythonで測定データのピーク値を検出してみる
- Pythonで複数のCSVデータを1つのファイルにまとめてみた
- PythonとExcelでフォルダの使用量を調べてみた
- Sphinx(ablog)の後処理をする
- WordPressのブログを静的サイトに書き換えてみました
- シェルスクリプトでSphinxのビルドの前処理をする
- 数式を中置記法から後置記法(逆ポーランド記法)に変換してみた