LoginSignup
4
10

More than 3 years have passed since last update.

python wxpython + openCVでシンプルな動画解析ツールを作成

Posted at

アジェンダ

  1. はじめに
  2. 出来上がったツールのデモ
  3. openCVで動画解析
  4. wxpythonでGUI作成
  5. pyinstallerでexe化

はじめに

動画中の「どの時間に」「どんな人物がでてくるか」を知りたいって思ったことがあって、
勉強していたwxpythonとopenCVでシンプルな動画解析ツールを作成してみました。
自分用のメモも兼ねて、ここで紹介させていただきます。

ダウンロードはこちらから
GitLab ChuntaMovieAnalyzer

出来上がったツールのデモ

まずはツールのデモ画面から。
動画を指定してhtmlのレポートを出力します。
動画の秒数ごとに人間の顔を抽出して表示しています。
GUIで秒数の間隔や抽出する最大人数を変更できます。

capture_1.jpg
capture_2.jpg

ダウンロードはこちらから
GitLab ChuntaMovieAnalyzer

openCVで動画解析

動画を解析する際に利用したライブラリはopenCVです。
今回は動画の1フレームを画像データにし、
画像データから顔を検出し、トリミングしています。
トリミングしたデータはhtml用の画像として出力しています。
ポイントと思われる部分のコードについて紹介します。

動画を読み込んで画像を出力

動画を読み込んで、動画の総フレーム数とfps(1秒あたりのフレーム数)を利用し、指定された秒数の間隔ごとに処理を行っています。

def get_sampling_data_list(self, movie_path, report_path, interval_time, max_human, is_advance):
    sampling_data_list = []

    cap = cv2.VideoCapture(movie_path)

    if not cap.isOpened():
        print('cannot open movie file.')
        return []

    # 総フレーム数を取得
    all_frame_cnt = cap.get(cv2.CAP_PROP_FRAME_COUNT)

    # フレームレートからサンプリングするフレーム数を算出
    fps = cap.get(cv2.CAP_PROP_FPS)
    sampling_frame_num = math.floor( fps * interval_time )

    frame_cnt = 1

    while True:
        cap.set(cv2.CAP_PROP_POS_FRAMES, frame_cnt)
        ret, frame = cap.read()

        if ret:
            sampling_data = self.get_sampling_data(frame, frame_cnt, fps, report_path, max_human, is_advance)
            sampling_data_list.append(sampling_data)

            frame_cnt = frame_cnt + sampling_frame_num
        else:
            break

    return sampling_data_list

1フレームごとの処理

1フレームを画像データ化 ⇒ 画像データから顔を検出 ⇒ トリミング ⇒ html用の画像として出力
の順で処理を行っています。

def get_sampling_data(self, frame, frame_cnt, fps, report_path, max_human, is_advance):
    data = sampling_data(frame_cnt, fps)

    face_cascade = cv2.CascadeClassifier(resourcePath('cascade/haarcascade_frontalface_default.xml'))
    src_gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
    faceInfoList = face_cascade.detectMultiScale(src_gray)

    human_cnt = 0

    for x, y, w, h in faceInfoList:
        # 最大人数を超えている場合はループを抜ける
        if human_cnt >= max_human:
            break

        # トリミング
        img_trim = frame[y:(y + h), x:(x + w)]

        data2 = None

        data2 = human_data()

        # 画像出力用フォルダを作成
        if False == os.path.exists(report_path + '/img'):
            os.mkdir(report_path + '/img')

        # 画像出力
        file_name = str(frame_cnt) + '_' + str(human_cnt) + '.jpg'
        cv2.imwrite(report_path + '/img/' + file_name, img_trim)
        data2.set_img_src(report_path, file_name)

        data.append_human_data(data2)

        human_cnt = human_cnt + 1

    return data

wxpythonでGUI作成

GUI部分のソースです。
ポイントと思われる部分のコードについて紹介します。

動画解析処理呼び出し処理

動画解析処理は時間がかかるため、非同期で呼び出さないとビジー状態になってしまいます。
これを回避するために、呼び出し部分は非同期にしています。

import threading
# 処理に時間がかかり画面がフリーズするのを防ぐためにスレッドキックする
analysis_thread = threading.Thread(target=exec_analyze, args=(self.analysis, self.btn, movie_path, interval_time, max_human, is_advance, token, report_path))
analysis_thread.start()
def exec_analyze(analysis, btn, movie_path, interval_time, max_human, is_advance, token, report_path):
    analysis.analyze(movie_path, int(interval_time), int(max_human), is_advance, token, report_path)

    wx.MessageBox('指定されたフォルダにhtmlファイルを出力しました。', '処理完了')

exe化

exe化する際はpyinstallerを利用しました。
外部リソースをexeに同封する際はひと工夫必要でした。
下記のサイトを参考に実施しました。

参考にしたURL
Pyinstaller でリソースを含めたexeを作成する

コマンドプロンプトで下記を実行

pyinstaller --onefile --icon=icon.ico -n chuntaMovieAnalyzer view_gui.py

作成されたspecファイルを編集し、再度コマンドプロンプトで下記を実行

pyinstaller chuntaMovieAnalyzer.spec

ダウンロードはこちらから
GitLab ChuntaMovieAnalyzer

4
10
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
4
10