Macでマウスを使って矩形領域を指定して画面キャプチャする(2021.7.7)

Summary

Macで指定したデバイスから画面キャプチャするのはできるようになったので、さらに、キャプチャ画面上でマウスを使って矩形領域を指定して、その領域だけをキャプチャするようにしたい。
前回と同様にデバイスが複数ある場合には最初に選択する。

cv2.setMouseCallback()でマウスイベントを取得して描画

マウスイベントの取得

call back関数を定義し、その関数でevent, x, y, flags, paramを引数として受け取るようにする。

cv2.namedWindow('Type [q] to quit capturing')
cv2.setMouseCallback('Type [q] to quit capturing', draw_circle)

cv2.namedWindow()で設定した名前の文字列と同一文字列で対象のwindowを特定できるようにしてcall back関数を指定する。
この対応が誤っていると、

 (-27:Null pointer) NULL window handler in function 'cvSetMouseCallback'.

などとおこられます。

カメラキャプチャ画像へのインポーズ描画

whileループ中では毎回新しいフレーム画像が取得されるので、必要な図形をマイフレーム再描画する必要がある。
draw_circleの中では、クリックイベントが発生するごとにポジションをpt0に保存する。
一度マウスがクリックされたなら、画面内のどこか(最新のpt0の場所)に赤丸を書き続ける。

def draw_circle(event, x, y, flags, param):
    global circle_clicked, pt0
    print(x, y, event, flags, param, cv2.EVENT_LBUTTONDOWN, circle_clicked)
    if event == cv2.EVENT_LBUTTONDOWN:
        print("Draw!!! (%d, %d), %s" % (x, y, circle_clicked))
        # pt0 shall be updeted for every Left click
        pt0 = (x, y)
        if circle_clicked == False:
            circle_clicked = True
           
while True:
    # Capture frame-by-frame
    ret, frame = cap.read()

    if circle_clicked == True:
            cv2.circle(frame, center=pt0, radius=5, color=(0,0,255), thickness=-1)

マウスでクリックしたところに赤い丸を表示するプログラムはこんな感じ。

プログラムサンプル
import cv2

def draw_circle(event, x, y, flags, param):
    global circle_clicked, pt0
    print(x, y, event, flags, param, cv2.EVENT_LBUTTONDOWN, circle_clicked)
    if event == cv2.EVENT_LBUTTONDOWN:
        print("Draw!!! (%d, %d), %s" % (x, y, circle_clicked))
        # pt0 shall be updeted for every Left click
        pt0 = (x, y)
        if circle_clicked == False:
            circle_clicked = True

# init position values
pt0 = (0, 0)
circle_clicked = False

cap = cv2.VideoCapture(0)

cv2.namedWindow('Type [q] to quit capturing')
cv2.setMouseCallback('Type [q] to quit capturing', draw_circle)

while True:
    # Capture frame-by-frame
    ret, frame = cap.read()

    if circle_clicked == True:
            cv2.circle(frame, center=pt0, radius=5, color=(0,0,255), thickness=-1)

    # show the frame
    cv2.imshow('Type [q] to quit capturing', frame)

    key = cv2.waitKey(1) & 0xFF
    if key == ord('q'):
        break

# terminate resources
cap.release()
cv2.destroyAllWindows()

マウスクリックで矩形領域を指定する

マウスで左上と右下の座標を取得し長方形をインポーズ描画する

カメラ画像の取得したい矩形領域の左上と右下の2点でマウス左クリックすると、領域を選択できる。その状態でsキーを押すと領域を切り出して画像として保存する。
選択された領域と切り出された画像が一致していないのは、キーを押す操作をしているあいだに手持ちの被写体がずれているからです。