OpenCVを使って動画から画像を出力してみよう

こんにちは。グローバルウェイの與那覇です。

先日OpenCVを使って機械学習を試してみました。
OpneCVは画像処理、画像解析が可能なライブラリです。

今回はそれを使った画像処理の方法について紹介していきます。

目次

この記事は以下の方を対象としています。

★4 Python開発経験が3年以上
★3 Python開発経験が1年以上
★2 Python 初級者。簡単なプログラムコードが書けます
★1 プログラミング未経験

今回行ったこと

今回、ある画像から特定の物体を判断することが可能かを試てみました。

具体的には養蜂場の蜜蜂の巣箱に配置された水差しを、蜜蜂がたくさん飛来している状態でも判断可能かといった内容になります。

その際に大変だったのが、学習データとなる画像の用意です。OpenCVは動画の操作も可能なので、動画から指定した範囲を毎秒画像として保存しました。その画像処理の方法について紹介します。

事前準備

OpenCVのライブラリをインストールします。コマンドプロンプトから下記コマンドを実行します。

pip install opencv-python

動画の再生時間確認

OpenCVで動画を開いて動画の再生時間を計ってみます。

フレームカウントをフレームレートで割ると再生時間が算出できます。

フレームレート:1秒間に表示する画像の枚数

フレームカウント:動画全体のフレーム数

import cv2
 
# 動画のパス
VIDEO_FILE = “1.mp4”
# 動画の読み込み
cap = cv2.VideoCapture(VIDEO_FILE)
 
# 動画が開けない場合は終了
if not cap.isOpened():
    cap.release()
    exit
 
# フレームレート
fps = cap.get(cv2.CAP_PROP_FPS)
# フレームカウント
frame_count = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
 
print(f”fps:{fps}”)
print(f”frame_count:{frame_count}”)
print(f”再生時間:{frame_count/fps}秒”)

実行結果

fps:25.0
frame_count:3064
再生時間:122.56秒

計算結果は2分02秒56で、メディアプレーヤーの表示が2:02なので一致しました。

動画からフレームを切り出して保存

次に動画を開いて指定した範囲を1秒毎に画像として保存してみましょう。

直下にpictureフォルダを作成し、そのフォルダに画像ファイルを保存します。

import cv2
import os
import shutil
 
VIDEO_FILE = “1.mp4”
PICTURE_DIR = “./picture”
 
# PICTURE_DIRが存在していたら削除
if os.path.isdir(PICTURE_DIR):
    shutil.rmtree(PICTURE_DIR)
 
# PICTURE_DIRを作成
os.mkdir(PICTURE_DIR)
 
# 動画の読み込み
cap = cv2.VideoCapture(VIDEO_FILE)
 
# 動画が開けない場合は終了
if not cap.isOpened():
    cap.release()
    exit
 
# フレームレート
fps = cap.get(cv2.CAP_PROP_FPS)
# フレームカウント
frame_count = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
 
# 出力ファイルのカウント
file_count = 1
# フレームカウント分ループ
for count in range(frame_count):
    # 次のフレームを取得
    ret = cap.grab()
    if not ret:
        break
    # fps毎(1秒)に処理
    if count % fps != 0:
        continue
    # 動画読み込み
    ret, frame = cap.read()
 
    # フレーム保存
    output_path = os.path.join(“./picture”, f”{file_count}.jpg”)
    cv2.imwrite(output_path, frame)
 
    # 出力ファイルのカウントアップ
    file_count += 1
 
cap.release()

以下の通り、画像が保存されました。

動画の指定範囲を切り出して保存

最後に動画の切り出したい範囲をマウスでドラッグし、切り出して保存します。

表示された画像をマウスでドラッグすると赤枠が表示されます。ドラッグ後にEnterボタン押下で、指定した範囲を1秒毎に切り出して保存します。

import copy
import cv2
import os
 
 
class MakePicture():
 
    def __init__(self):
        self.rectangles = ()
        self.start_point = None
        self.end_point = None
        self.drawing = False
        self.img = None
 
    def run(self):
        video_file = “1.mp4”
 
        # 動画の読み込み
        cap = cv2.VideoCapture(video_file)
 
        # 動画が開けない場合は終了
        if not cap.isOpened():
            cap.release()
            exit
 
        # マウスで座標を指定して、座標を保存する
        x0, y0, x1, y1 = self.get_coordinate(cap)
 
# 動画の再読み込み
        cap.release()
        cap = cv2.VideoCapture(video_file)
 
        # フレームレート
        fps = cap.get(cv2.CAP_PROP_FPS)
        # フレームカウント
        frame_count = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
 
        # 出力ファイルのカウント
        file_count = 1
        # フレームカウント分ループ
        for count in range(frame_count):
            # 次のフレームを取得
            ret = cap.grab()
            if not ret:
                break
            # fps毎(1秒)に処理
            if count % fps != 0:
                continue
            # 動画読み込み
            ret, frame = cap.read()
 
            # フレーム切り取り
            cropped_frame = frame[y0:y1, x0:x1]
 
            # フレーム保存
            output_path = os.path.join(“./picture”, f”{file_count}.jpg”)
            cv2.imwrite(output_path, cropped_frame)
 
            # 出力ファイルのカウントアップ
            file_count += 1
 
        cap.release()
 
    # 動画内のxy座標を取得する
    def get_coordinate(self, cap) -> tuple:
 
        # 戻り値
        result = ()
 
        # 動画から画像を取得
        ret, self.img = cap.read()
 
        # エラーの場合は終了
        if not ret:
            print(“動画の読み込みに失敗しました”)
            return result
 
        # 表示ウィンドウの設定
        cv2.namedWindow(“image”)
        # マウスのコールバック設定
        cv2.setMouseCallback(“image”, self.__draw_rectangle)
 
        # 最初のイメージを保存
        self.save_img = copy.deepcopy(self.img)
 
        while True:
            # 画像を表示
            cv2.imshow(“image”, self.img)
 
            # 押下されたキーを取得
            key = cv2.waitKey(1) & 0xFF
 
            # Escキー押下で処理中断
            if key == 27:
                break
 
            # Enterキー押下で確定
            elif key == 13:
                # マウスで範囲指定していたら座標取得
                if self.rectangles:
                    # 座標の小さい値をx0,y0に、大きい値をx1,y1にセット
                    x0 = min(self.rectangles[0][0], self.rectangles[1][0])
                    y0 = min(self.rectangles[0][1], self.rectangles[1][1])
                    x1 = max(self.rectangles[0][0], self.rectangles[1][0])
                    y1 = max(self.rectangles[0][1], self.rectangles[1][1])
                    result = (x0, y0, x1, y1)
                break
 
        cap.release()
        cv2.destroyAllWindows()
        return result
 
    # マウスで矩形を描画する
    def __draw_rectangle(self, event, x, y, flags, param):
 
        # マウスの左ボタン押下で範囲指定開始
        if event == cv2.EVENT_LBUTTONDOWN:
            # 範囲指定の開始位置取得
            self.start_point = (x, y)
            # 範囲指定開始フラグTrue
            self.drawing = True
 
        # 範囲指定開始した後にマウスを動かしたら赤枠を表示
        elif event == cv2.EVENT_MOUSEMOVE:
            if self.drawing:
                # 最初のイメージをディープコピーして取得
                self.img = copy.deepcopy(self.save_img)
                # 範囲指定された部分を赤枠で表示
                cv2.rectangle(
                    self.img, self.start_point, (x, y), (0, 0, 255), 2)
                # 画像を表示
                cv2.imshow(“image”, self.img)
 
        # マウスの左ボタンを話したら範囲指定終了
        elif event == cv2.EVENT_LBUTTONUP:
            # 範囲指定開始フラグFalse
            self.drawing = False
            # 範囲指定の終了位置取得
            self.end_point = (x, y)
            # 範囲指定の開始、終了をセット
            self.rectangles = (self.start_point, self.end_point)
 
 
mp = MakePicture()
mp.run()

以下のように赤枠で囲んでEnterボタンを押下します。

指定範囲の画像が出力されました。

まとめ

今回はOpenCVを利用して動画から画像を出力しました。

機械学習ではたくさんの学習データが必要です。OpenCVを利用すると効率的に学習データを用意できます。他にも色々な活用ができますので、是非利用してみてください。

参考

OpenCV

https://opencv.org

※当社は、琉球大学「琉大ハニー養蜂部」のオフィシャルスポンサーとして、デジタル技術を活用し、養蜂産業をサポートしています。

詳細 ▶ https://www.globalway.co.jp/news/notice/6617/

この記事が気に入ったら
いいね または フォローしてね!

  • URLをコピーしました!
  • URLをコピーしました!
目次