PythonでARマーカーを利用する(OpenCV、ArUco Markers)
はじめに
今回はPythonでARマーカーの生成やカメラでの検出について試してみました。
最近ロボットの自己位置推定にARマーカーを利用しているところを見ました。シミュレーションでもARマーカーを配置して、自己位置推定をできるようにしたいなと思っています。
▼以前の記事はこちら
関連情報
二次元コードについて調べていると、いろんな種類のものがありました。
▼QRコードとARマーカーの違いはこちら。QRコードの目的はWebへのリンクだそうです。
https://www.elecom.co.jp/pickup/column/ar_column/00001
▼Tello-pythonを利用した記事がありました。ARマーカーでドローンに命令するようになっています。
https://qiita.com/hsgucci/items/37becbb8bfe04330ce14
▼他の二次元コードについてもまとまった記事はこちら。
▼ROSでの利用についての記事もありました。自己位置推定に利用できるようです。
https://www.fsi.co.jp/blog/9214
ARマーカーを自己位置推定などに利用したいとChatGPTに聞くと、OpenCVにAruco機能というものがあるようでした。
▼ChatGPTにArucoマーカーについて聞くと、以下のような回答が返ってきました。


▼OpenCVのArUco Markersに関する説明はこちら
https://docs.opencv.org/4.x/d5/dae/tutorial_aruco_detection.html
▼macnicaのページにも説明がありました。
https://www.macnica.co.jp/business/semiconductor/articles/nvidia/136335
環境を構築する
▼PCは10万円ぐらいで購入したゲーミングノートPCを利用しています。Windows 11の環境です。
Pythonの仮想環境を作成しておきます。
py -3.10 -m venv pyenv-ar
cd .\pyenv-ar\
.\Scripts\activate
▼Pythonの仮想環境の作成については、以下の記事をご覧ください。
OpenCVをインストールします。
pip install opencv-python opencv-contrib-python
ARマーカーを生成する
マーカーを生成するためのコードを、ChatGPTに書いてもらいました。
import cv2
import cv2.aruco as aruco
# 使用する辞書を取得
aruco_dict = aruco.getPredefinedDictionary(aruco.DICT_4X4_50)
# マーカーIDとサイズの設定
marker_id = 0
marker_size = 200 # ピクセル単位
# マーカー画像の生成
marker_img = aruco.generateImageMarker(aruco_dict, marker_id, marker_size)
# 画像の保存
cv2.imwrite("aruco_marker_0.png", marker_img)
print("aruco_marker_0.png を保存しました。")
▼以下のマーカーが生成されました。

IDの種類について、ChatGPTに聞いてみました。
▼Dictionaryによって異なるようです。

IDごとに生成するのは面倒だったので、markerフォルダにすべてのIDのマーカーを保存するようにコードを変更してもらいました。
import cv2
import cv2.aruco as aruco
import os
# 保存先のディレクトリを作成
save_dir = "marker"
if not os.path.exists(save_dir):
os.makedirs(save_dir)
# 使用する辞書を取得
aruco_dict = aruco.getPredefinedDictionary(aruco.DICT_4X4_50)
# マーカーサイズの設定
marker_size = 200 # ピクセル単位
# 0から49までのマーカーIDを生成して保存
for marker_id in range(50):
# マーカー画像の生成
marker_img = aruco.generateImageMarker(aruco_dict, marker_id, marker_size)
# 画像の保存
filename = os.path.join(save_dir, f"aruco_marker_{marker_id}.png")
cv2.imwrite(filename, marker_img)
print(f"{filename} を保存しました。")
▼実行すると、フォルダにマーカーが保存されていました。

これですぐに使えそうです。
カメラの映像に対して検出する
USBカメラでマーカーの検出を試してみました。
以下のコードを実行しました。ノートPCの内蔵カメラではなくUSBカメラなので、番号は1にしています。
import cv2
import cv2.aruco as aruco
# カメラの読み込み
cap = cv2.VideoCapture(1)
# ArUco辞書の取得
aruco_dict = aruco.getPredefinedDictionary(aruco.DICT_4X4_50)
# ディテクターパラメータの設定
parameters = aruco.DetectorParameters()
while True:
ret, frame = cap.read()
if not ret:
break
# マーカーの検出
corners, ids, rejected_img_points = aruco.detectMarkers(frame, aruco_dict, parameters=parameters)
if ids is not None:
# マーカーに枠とIDを描画
aruco.drawDetectedMarkers(frame, corners, ids)
# 結果の表示
cv2.imshow("AR Marker Detection", frame)
# 'q'キーで終了
if cv2.waitKey(1) & 0xFF == ord("q"):
break
# リソースの解放
cap.release()
cv2.destroyAllWindows()
実際にカメラを動かしながら検出を試してみました。
▼検出できました!IDと領域、1つの頂点に赤い点が表示されています。

▼傾けると、赤い点も回転しました。

▼ちょっと途切れると検出できないようでした。

▼動画だとこんな感じです。
動画の最後の方で、キーボードの上矢印と17番を誤検出していました。
▼17番は以下の画像です。単純すぎて誤検出しそうな見た目ではあります。

最後に
マーカーの生成と検出ができるようになったので、ロボットの自己位置推定に利用していこうと思っています。
17番のIDのように単純すぎるものは避けた方が良いのかもしれません。現状でも50通りはありますし、辞書を変更すると増えるので、使いやすいものを選べばいいのかなと思います。
今回生成したARマーカーをUnreal Engineにも取り込もうと考えています。
▼最近Unreal Engineで3Dスキャンのようなものを試していたので、ARマーカーによる自己位置推定と併用したいところです。