【OpenCV-Python】カメラからの画像取込を別スレッドにする

カメラからの画像取込を、なぜ、わざわざ別スレッドにしたいか?というと、よくある画像取込のプログラム

import cv2

# カメラを開く
cap = cv2.VideoCapture(0)

while True:
    # 画像をキャプチャする
    _, frame = cap.read()

    # 画像を表示する
    cv2.imshow("Image", frame)

    # キーを押すとループを終了する
    if cv2.waitKey(1) > 0:
        break

# カメラを閉じる
cap.release()
# すべてのウィンドウを閉じる
cv2.destroyAllWindows()

を実行し、画像が表示されたウィンドウのタイトルバーの部分をマウスでクリックすると、while文のループ内で、waitKey(1) の部分で処理が停止します。

 

処理が停止するということは、画像の表示(imshow())や画像の取込(read())も、つられて実行されなくなってしまいます。

 

画像の表示は、最悪、停止してもしょうがないとしても、画像の取込が停止するのは、画像の取込ながら画像処理する場合には、不都合です。

 

そこで、画像の取込部分を別スレッドにしたプログラムがこちら↓

import threading
import queue

import cv2

# カメラを開く
cap = cv2.VideoCapture(0)

# フレーム共用のキュー
q_frames = queue.Queue()

def frame_update():
    '''画像取込'''
    while True:
        # カメラ画像の取得
        _, frame = cap.read()
        # 取得した画像をキューに追加
        q_frames.put(frame)
        print(f"qsize:{q_frames.qsize()}")

# 画像取り込みスレッドの作成
thread = threading.Thread(target=frame_update, daemon=True)
# スレッドの開始
thread.start()

# 画像表示用スレッド
while True:
    frame = q_frames.get() # queueが空の場合、キューに何か入るまで、スレッドをブロックする。
    cv2.imshow("Image", frame)

    # キーを押すとループを終了する
    if cv2.waitKey(1) > 0:
        break

# カメラを閉じる
cap.release()
# すべてのウィンドウを閉じる
cv2.destroyAllWindows()

このようにすることで、画像を表示しているウィンドウのタイトルバーの部分をクリックしても、画像の取込(read())が停止する事は無くなります。

 

ただし、少々、厄介なのが、別スレッドからGUIの表示を行う事が出来ないので、queueを介して画像データをメインスレッド側で画像を表示するようにしています。

 

今回は、waitKeyの部分で処理が停止してしまうのを、スレッドで回避していますが、waitKeyの関数に限らず、処理が停止してしまう関数が他にもあるので、注意が必要です。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください