EnsekiTT Blog

EnsekiTTが書くブログです。

OpenCV+ArUco+Webカメラでマーカ検出をやった話

こんにちは、えんせきです。
4月は展示会だらけで忙しいのとRubyいじってばっかりだったので今日は息抜きに画像処理をやりました。

つまりなにしたの?

OpenCVOpenCV contribに含まれるArUcoにWebカメラの画像を放り込んで、マーカ検出をして表示する。
f:id:ensekitt:20180414202156g:plain

ArUcoとは?

ArUcoマーカはマーカを検出してカメラとかカメラから見たマーカの位置・姿勢を推定するのに使える。
白と黒のバイナリ形式で正方形、見栄えはどう見てもマーカだけどロバストな検出と簡単に使えて計算が早いのが利点。
ロボットとかでもよく使われている。
C++の例が多いので今日はPythonOpenCVでやってみた。
OpenCV: ArUco marker detection (aruco module)

どんな実装?

  • OpenCVWebカメラの画像を取り込む
  • 取り込んだフレームに大してマーカの検出処理をする
  • 処理結果をフレームに追記する
  • 処理済のデータを表示する

OpenCVOpenCV Contribをインストール(MacOS+python3.6.x+pip)

OpenCVをインストールする

pip install opencv-python

OpenCV Contribをインストールする

pip install opencv-contrib-python

実行確認

>>> import cv2
>>> cv2.__version__
'3.4.0'
>>> dir(cv2.aruco)
['Board_create', 'CORNER_REFINE_CONTOUR', 'CORNER_REFINE_NONE', 'CORNER_REFINE_SUBPIX', 'CharucoBoard_create', 'DICT_4X4_100', 'DICT_4X4_1000', 'DICT_4X4_250', 'DICT_4X4_50', 'DICT_5X5_100', 'DICT_5X5_1000', 'DICT_5X5_250', 'DICT_5X5_50', 'DICT_6X6_100', 'DICT_6X6_1000', 'DICT_6X6_250', 'DICT_6X6_50', 'DICT_7X7_100', 'DICT_7X7_1000', 'DICT_7X7_250', 'DICT_7X7_50', 'DICT_ARUCO_ORIGINAL', 'DetectorParameters_create', 'Dictionary_create', 'Dictionary_create_from', 'Dictionary_get', 'GridBoard_create', '__doc__', '__loader__', '__name__', '__package__', '__spec__', 'calibrateCameraAruco', 'calibrateCameraArucoExtended', 'calibrateCameraCharuco', 'calibrateCameraCharucoExtended', 'custom_dictionary', 'custom_dictionary_from', 'detectCharucoDiamond', 'detectMarkers', 'drawAxis', 'drawDetectedCornersCharuco', 'drawDetectedDiamonds', 'drawDetectedMarkers', 'drawMarker', 'drawPlanarBoard', 'estimatePoseBoard', 'estimatePoseCharucoBoard', 'estimatePoseSingleMarkers', 'getBoardObjectAndImagePoints', 'getPredefinedDictionary', 'interpolateCornersCharuco', 'refineDetectedMarkers']

コード

import cv2

cap = cv2.VideoCapture(0)

dictionary_name = cv2.aruco.DICT_6X6_250
dictionary = cv2.aruco.getPredefinedDictionary(dictionary_name)

while True:
    ret, frame = cap.read()

    # スクリーンショットを撮りたい関係で1/3サイズに縮小
    frame = cv2.resize(frame, (int(frame.shape[1]/3), int(frame.shape[0]/3)))

    # ArUcoの処理
    corners, ids, rejectedImgPoints = cv2.aruco.detectMarkers(frame, dictionary)
    frame = cv2.aruco.drawDetectedMarkers(frame, corners, ids)

    # 加工済の画像を表示する
    cv2.imshow('Edited Frame', frame)

    # キー入力を1ms待って、k が27(ESC)だったらBreakする
    k = cv2.waitKey(1)
    if k == 27:
        break

cap.release()
cv2.destroyAllWindows()

ここで、マーカ辞書は6x6の250にした。本来であれば辞書から画像を作成して印刷して壁に貼ったりするけど、
今回はディスプレイに表示するだけにした。
0から順番に並べると以下のようになる。
f:id:ensekitt:20180414203929p:plain

結果

f:id:ensekitt:20180414204125p:plain
いい感じに検出できた様子