2
2

More than 1 year has passed since last update.

【Python】OpenCVを使った動画から画像の生成

Last updated at Posted at 2023-09-02

はじめに

当記事では1秒単位で動画を読み込んで、画像の選択範囲部分を画像として保存することを目的としています。

この記事の対象者

 Python * OpenCVを使って:
  ・動画を読み込みたい方
  ・フレーム指定で処理をループさせたい方
  ・範囲選択部分を画像として保存したい方

動作環境

 ・Python:3.10.2
 ・opencv-python:4.8.0.76

読み込む動画について

 ・Windows標準の『クロック』アプリでストップウォッチ機能を1分ほど録画したもの
 ・動画内容は以下
  ・フレーム幅:1920
  ・フレーム高:1080
  ・フレーム率:60フレーム/秒

 ※動画の一部をgif化したもの↓
test.gif

フォルダ構成

フォルダ構成は以下の通り。
読み込み対象の動画ファイルは[movie]フォルダに格納。
結果は[ret]フォルダに[image_インデックス番号.jpg]というファイル名で格納していきます。

root/
    ├movie/
        └sample.mp4
    ├ret/
        ├image_0.jpg
        └image_1.jpg
         …
    └ readMovie.py

プログラム制御

処理全容

readMovie.py
import cv2

FILEPATH = "./movie/sample.mp4" # 動画ファイルの相対パス

# 動画ファイルを読み込む
video = cv2.VideoCapture(FILEPATH)

# 動画情報の取得
frameAll = int(video.get(cv2.CAP_PROP_FRAME_COUNT)) # 動画の総フレームを取得
framerate = int(video.get(cv2.CAP_PROP_FPS)) # 動画フレームレートを取得(当サンプルでは[60]を返す)

# ファイル出力用のインデックス初期化
idx = 0

# 動画1秒単位でのループ処理(※1)
for i in range(0, frameAll, framerate):
    # 動画指定秒数での動画読み込み
    video.set(cv2.CAP_PROP_POS_FRAMES, i)
    ret, image = video.read() # [ret]はread()の処理結果、[image]は処理画像が格納される

    # read()が正常終了した場合に画像ファイル出力を実行
    if ret == True:
        # 画像ファイルとして保存(※2)
        cv2.imwrite('{}{}{}'.format('./ret/image_', idx, '.jpg'), image[390:590, 590:1320]) 

        # ファイル出力用のインデックスをインクリメント
        idx += 1
    else:
        break

※1部分

以下のrange部分について、rangeの引数は[range(start, stop, step)]となるため、以下値を与えている。
 ①[stop=動画の総フレーム]
 ②[step=指定秒数毎のフレーム数]

どちらもVideoCaptureのプロパティから取得することが可能(参考リンクを参照)。
当処理では事前処理として『動画情報の取得』部分で各値を取得している。

動画のフレームレートを[step]に与えることで、1秒毎の動画読み込みが可能となる。
(使用する動画ファイルが60FPSのため、[step=30]とした場合は0.5秒毎の動画読み込み処理となる)

for i in range(0, frameAll, framerate):
    #略
else:

※2部分

imwrite()部分について、受ける引数は[cv2.imwrite(filename, img[, params])となる。
(詳細は参考リンクを参照)

第一引数部分に関しては『保存先+ファイル名+インデックス+拡張子』という文字列を成形しているだけなので割愛。

第二引数部分に関して、[video.read()]で返却された画像について、以下範囲指定をした結果を渡しているイメージ。
範囲指定をしない[image]だけを与えた場合、範囲指定なしの画像を渡すことになる。
 ①Y軸部分を390px~590px
 ②X軸部分を590px~1320px

cv2.imwrite('{}{}{}'.format('./ret/image_', idx, '.jpg'), image[390:590, 590:1320]) 

出力結果

フォルダキャプチャの切り抜きですが、結果は以下のようになります。
jpg形式で画像を出力することができました。

出力結果.png

おわりに

処理を構築してみて思ったのですが、『動画の指定範囲を画像として保存する』という機会は実生活でほぼないかと思います。
画像認識等で指定秒数毎に画像の一部範囲を読み込んでOCRで文字認識させるといったことに派生できたらと思います。

参考

 ・OpenCVのドキュメンテーション:VideoCaptureProperties
https://docs.opencv.org/3.4/d4/d15/group__videoio__flags__base.html#gaeb8dd9c89c10a5c63c139bf7c4f5704d

 ・imwrite()メソッドのドキュメンテーション
https://docs.opencv.org/3.4/d4/da8/group__imgcodecs.html#gabbc7ef1aa2edfaa87772f1202d67e0ce

2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2