LoginSignup
5
7

More than 5 years have passed since last update.

opencv(python)のマウスイベントでカメラのライブ映像に線を描く

Last updated at Posted at 2019-03-16

はじめに

opencvのマウスイベントを使いこなしていなかったので、カメラのライブ映像にマウスで描画する実験をしたメモ。
記述言語はpython。

pythonプラグラム

参考文献

以下の情報を参考にして、プログラムを作成した。

オリジナルなのは、以下。

  • マウスでクリックした座標を辞書型変数に格納して、履歴を残せるようにした
  • 右クリックで直前の座標を削除できるようにした
  • 画像と座標を保存できるようにした

ライブラリ

opencvがインストールされている前提。anaconda環境なので、condaでインストールする。バージョンは3.4.2だった。

conda install opencv

プログラム

opencvとjsonをインポートして、変数を初期化する。座標はptに格納する。

import cv2
import json

#データの初期化
pt = {}
m = 0
n = 0
p = 0

マウスイベントに対するコールバック関数を記述する。今回はシンプルに、左クリックでマーカーと直線を描画していく。

#マウスの操作があるとき呼ばれる関数
def callback(event, x, y, flags, param):
    global pt, m, n, p

    #マウスの左ボタンがクリックされたとき
    if event == cv2.EVENT_LBUTTONDOWN:
        m = n
        pt[n] = (x, y)
        #print(n)
        #print(pt)
        n = n + 1
        p = p + 1

    #マウスの右ボタンがクリックされたとき
    if event == cv2.EVENT_RBUTTONDOWN and n > 0:
        #print(m, n)
        #print(pt[m])
        pt.pop(m)
        m = m - 1
        n = n - 1
        p = p + 1

カメラウィンドウやマウスのコールバック関数をセットする。

#カメラを設定
cap = cv2.VideoCapture(0)
#ウィンドウの名前を設定
cv2.namedWindow("img", cv2.WINDOW_NORMAL)
#コールバック関数の設定
cv2.setMouseCallback("img", callback)
#処理開始のプロンプト
print(">>> Start !!")

カメラのライブ画像を読み込んで描画する。画像ファイルの場合は ret, frame = cap.read() はコメントアウトして、 frame = cv2.imread("lena.jpg") を有効化する。

操作とキーコマンドは以下。

  • 左クリックするごとに、描画が進行
  • 右クリックすると、直前の描画を削除
  • sキーで画像と座標をファイルに保存(画像は連番ファイル)
  • cキーで座標履歴クリア(描画は辞書型変数ptに基づくので、描画もクリアされる)
  • ESCキーで終了
#処理ループ
while True:
    #カメラ画像を読み込む
    ret, frame = cap.read()
    #画像ファイルを読み込む
    #frame = cv2.imread("lena.jpg")

    if n >= 1:
        cv2.drawMarker(frame, pt[m], (0, 255, 255), markerType=cv2.MARKER_TILTED_CROSS, markerSize=15)
    if n >= 2:
        for i in range(1, n):
            cv2.line(frame, pt[i - 1], pt[i], (0, 255, 255), 1)

    cv2.imshow("img", frame)

    k = cv2.waitKey(1)
    #Escキーを押すと終了
    if k == 27:
        print(">>> Exit")
        break
    #cを押すと描画クリア(ptを初期化)
    elif k == ord("c"):
        print(">>> Clear Coordinates.")
        pt.clear()
        m = 0
        n = 0
    #sを押すと画像を保存
    elif k == ord("s"):
        print(">>> Save Image and Coordinates.")
        str = "painted{no:03}.png".format(no = p)
        cv2.imwrite(str, frame)
        with open("painted.json","w") as f:
            json.dump(pt, f, indent = 4)

cap.release()
cv2.destroyAllWindows()

プログラム全体

もう少しスマートにかけそうなところもあるが、やりたいことはできたのでこれで良しとする。

draw_by_mouse.py
import cv2
import json

#データの初期化
pt = {}
m = 0
n = 0
p = 0

#マウスの操作があるとき呼ばれる関数
def callback(event, x, y, flags, param):
    global pt, m, n, p

    #マウスの左ボタンがクリックされたとき
    if event == cv2.EVENT_LBUTTONDOWN:
        m = n
        pt[n] = (x, y)
        #print(n)
        #print(pt)
        n = n + 1
        p = p + 1

    #マウスの右ボタンがクリックされたとき
    if event == cv2.EVENT_RBUTTONDOWN and n > 0:
        #print(m, n)
        #print(pt[m])
        pt.pop(m)
        m = m - 1
        n = n - 1
        p = p + 1

#カメラを設定
cap = cv2.VideoCapture(0)
#ウィンドウの名前を設定
cv2.namedWindow("img", cv2.WINDOW_NORMAL)
#コールバック関数の設定
cv2.setMouseCallback("img", callback)
#処理開始のプロンプト
print(">>> Start !!")

#処理ループ
while True:
    #カメラ画像を読み込む
    ret, frame = cap.read()
    #画像ファイルを読み込む
    #frame = cv2.imread("lena.jpg")

    if n >= 1:
        cv2.drawMarker(frame, pt[m], (0, 255, 255), markerType=cv2.MARKER_TILTED_CROSS, markerSize=15)
    if n >= 2:
        for i in range(1, n):
            cv2.line(frame, pt[i - 1], pt[i], (0, 255, 255), 1)

    cv2.imshow("img", frame)

    k = cv2.waitKey(1)
    #Escキーを押すと終了
    if k == 27:
        print(">>> Exit")
        break
    #cを押すと描画クリア(ptを初期化)
    elif k == ord("c"):
        print(">>> Clear Coordinates.")
        pt.clear()
        m = 0
        n = 0
    #sを押すと画像を保存
    elif k == ord("s"):
        print(">>> Save Image and Coordinates.")
        str = "painted{no:03}.png".format(no = p)
        cv2.imwrite(str, frame)
        with open("painted.json","w") as f:
            json.dump(pt, f, indent = 4)

cap.release()
cv2.destroyAllWindows()

実行結果

思ったようにできた。これは画像を使った場合で、ffmpegで連番画像ファイルをgifアニメーションにした。

anim.gif

おまけ

gifアニメーションの生成コマンド

ffmpeg -i painted%03d.png -vf palettegen palette.png
ffmpeg -f image2 -r 1 -i painted%03d.png -i palette.png -filter_complex paletteuse anim.gif
5
7
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
5
7