OpenCV-Python 演習

マウス入力を処理する

ポイント

  • ウィンドウ上で以下のようなマウス操作を行うと,イベント(割り込み)が発生し,予め登録しておいたコールバック関数が呼出される.
    • マウスポインタを移動する
    • マウスボタンを押す
  • コールバック関数の定義
    • マウス操作に関するイベントが発生したときに呼出されるコールバック関数を定義しておく.
      def onMouse(event, x, y, flags, param):
  • eventには,次の表のいずれかがセットされ,どのイベントが発生したかがわかる.
    イベント発生するタイミング
    cv2.EVENT_MOUSEMOVEマウスを移動したとき,またはボタンを離した直後
    cv2.EVENT_LBUTTONDOWN左ボタンを押下したとき
    cv2.EVENT_RBUTTONDOWN右ボタンを押下したとき
    cv2.EVENT_MBUTTONDOWN中ボタンを押下したとき
    cv2.EVENT_LBUTTONUP左ボタンを離したとき
    cv2.EVENT_RBUTTONUP右ボタンを離したとき
    cv2.EVENT_MBUTTONUP中ボタンを離したとき
    cv2.EVENT_LBUTTONDBLCLK左ボタンがダブルクリックされたとき
    cv2.EVENT_RBUTTONDBLCLK右ボタンがダブルクリックされたとき
    cv2.EVENT_MBUTTONDBLCLK中ボタンがダブルクリックされたとき
  • x, yにはイベントが発生したときのマウスポインタの(ウィンドウに表示している画像上の)座標が入る.
  • flagsには,次の表に示すフラグの論理和がセットされ,どのキーが同時に押されているかが分かる
    フラグ名フラグが立つ条件
    cv2.EVENT_FLAG_LBUTTONCTRL,SHIFT,ALTいずれも押さずに,左ボタンを押下したとき
    cv2.EVENT_FLAG_RBUTTONCTRL,SHIFT,ALTいずれも押さずに,右ボタンを押下したとき
    cv2.EVENT_FLAG_MBUTTONCTRL,SHIFT,ALTいずれも押さずに,中ボタンを押下したとき
    cv2.EVENT_FLAG_CTRLKEYCTRLを押して,ボタンを離したときと離した直後
    cv2.EVENT_FLAG_SHIFTKEYSHIFTを押して,ボタンを離したときと離した直後
    cv2.EVENT_FLAG_ALTKEYALTを押して,ボタンを離したときと離した直後
  • paramには,以下に説明するコールバック関数の登録時に設定した,値や構造体のポインタが入る.
  • コールバック関数の登録
    • コールバック関数は,定義しただけでは呼び出されない. cv2.setMouseCallback関数を用いてコールバック関数を登録することで,マウス操作イベントが発生した際に登録された関数が自動的に呼び出されるようにする.
    • "name"というウィンドウ上でマウス操作が行われたとき,function_nameというコールバック関数を呼び出すように設定.
    • paramは,コールバック関数に渡すパラメータである.
      cv2.setMouseCallback("name", function_name, param)
  • コールバック関数の第5引数(param)について
    • コールバック関数内で処理した結果を外部に持ち出したいときなどに使用する.
    • 辞書をコールバック関数の引数として渡すときの使用例
      • 辞書は参照渡しとなるため,コールバック関数内での変更は,呼び出し元の辞書に反映される.
      • コールバック関数の定義例
        def onMouse(event, x, y, flags, param):
            event_description = ""
        
            if event == cv2.EVENT_MOUSEMOVE:
                event_description += "MOUSE_MOVE"
            elif event == cv2.EVENT_LBUTTONDOWN:
                event_description += "LBUTTON_DOWN"
                print("centerX: " + str(param["centerX"]) +
                      ", centerY: " + str(param["centerY"]))
                param["centerX"] = -1
                param["centerY"] = -1
            else:
                pass
        
  • メイン関数内での使用例
     param = {"centerX": 10, "centerY": 20, "color": 0 }
    
     cv2.setMouseCallback('img', onMouse, param)
    
    
  • paramは,利用しないのであれば, cv2.setMouseCallback関数の第3引数で指定しなくてもよい.
    cv2.setMouseCallback("name", function_name)

サンプルコード

'''
 tutorial_008.py
 ウィンドウ上のマウス入力を処理する
'''
import cv2
import numpy as np

img = np.zeros((480, 640, 3), np.uint8)  # y座標, x座標, チャンネル

def onMouse(event, x, y, flags, param):
    event_description = ""

    if event == cv2.EVENT_MOUSEMOVE:
        event_description += "MOUSE_MOVE"
    elif event == cv2.EVENT_LBUTTONDOWN:
        event_description += "LBUTTON_DOWN"
        print("centerX: " + str(param["centerX"]) +
              ", centerY: " + str(param["centerY"]))
        param["centerX"] = -1
        param["centerY"] = -1
    elif event == cv2.EVENT_RBUTTONDOWN:
        event_description += "LBUTTON_DOWN"
    elif event == cv2.EVENT_MBUTTONDOWN:
        event_description += "MBUTTON_DOWN"
    elif event == cv2.EVENT_LBUTTONUP:
        event_description += "LBUTTON_UP"
    elif event == cv2.EVENT_RBUTTONUP:
        event_description += "RBUTTON_UP"
    elif event == cv2.EVENT_MBUTTONUP:
        event_description += "MBUTTON_UP"
    elif event == cv2.EVENT_LBUTTONDBLCLK:
        event_description += "LBUTTON_DBLCLK"
        cv2.circle(img, (x, y), 100, (0, 0, 255), 3)
    elif event == cv2.EVENT_RBUTTONDBLCLK:
        event_description += "RBUTTON_DBLCLK"
    elif event == cv2.EVENT_MBUTTONDBLCLK:
        event_description += "MBUTTON_DBLCLK"
    else:
        event_description += ""

    if flags & cv2.EVENT_FLAG_LBUTTON:
        event_description += " + LBUTTON"

    if flags & cv2.EVENT_FLAG_RBUTTON:
        event_description += " + RBUTTON"

    if flags & cv2.EVENT_FLAG_MBUTTON:
        event_description += " + MBUTTON"

    if flags & cv2.EVENT_FLAG_CTRLKEY:
        event_description += " + CTRL"

    if flags & cv2.EVENT_FLAG_SHIFTKEY:
        event_description += " + SHIFT"

    if flags & cv2.EVENT_FLAG_ALTKEY:
        event_description += " + ALT"

    print(event_description)


def tutorial_008():

    # 画面全体を青色にする
    img[:, :] = [255, 0, 0]
    cv2.namedWindow("img", cv2.WINDOW_AUTOSIZE)
    cv2.moveWindow("img", 100, 100)

    param = {"centerX": 10, "centerY": 20, "color": 0}

    cv2.setMouseCallback('img', onMouse, param)

    while(True):
        cv2.imshow('img', img)
        key = cv2.waitKey(20) & 0xFF
        if key == 0x1b or key == ord("q"):
            break
        elif key == ord("1"):
            param["centerX"] = 100
            param["centerY"] = 200
        elif key == ord("0"):
            param["centerX"] = 10
            param["centerY"] = 20
        elif key == ord("p"):
            print("centerX: " + str(param["centerX"]) +
                  ", centerY: " + str(param["centerY"]))
        else:
            pass

    cv2.destroyAllWindows()


if __name__ == "__main__":
    tutorial_008()

課題1 (exercise_008_01.py)

  • 簡単なペイントソフトを作成しなさい.
    • 背景を黒とし,マウスの左キーを押しながらドラッグすることで,フリーハンドによる絵が描けるようにする.
    • ドラッグ中は,マウスポインタの位置に適当な半径,適当な色の円を描くようにすることで実現可能である.
    • マウスの左キーの状態(押されているか,押されていないか)を管理するグローバル変数(bool型など)を利用しなさい.

課題2 (exercise_008_02.py)

  • 簡単なドローロフトを作成しなさい.
    • 左クリックした場所を起点とし,左ボタンを押している間は現在のマウスポインタの位置を終点とする,描画候補となる直線を動的に描くようにし,左ボタンを離したときに,線が確定するものとする.

OpenCV-Python 演習


Last-modified: 2018-08-18 (土) 15:31:58