ArUcoマーカーの認識練習

はじめに

本記事は、ロボットに化学実験をさせるための試行錯誤の記録です。
webに諸々の類似情報があるかもしれませんが、勉強のため、車輪の再発明をする覚悟で進めています。

本日は、ロボット分野で定番となっているarucoマーカーの練習をします。
web上に色々とサンプルコードがあったのですが、open cvの仕様がコロコロ変わるようで、2023/7/12時点で動くものがあまり見つかりませんでした。

ArUcoマーカーとは?

QRコードのようなものです。

QRコードよりも画素が低いのが特徴です。入れられる情報量は減りますが、webカメラのような低性能な認識デバイスでも扱いやすいのが特長のようです。

arucoの例

マーカーの生成

ライブラリのインストール (open cvとバージョンをあわせる必要があるようです)

pip install opencv-contrib-python

今回は以下のバージョンを使用しました。
opencv-contrib-python 4.8.0.74
opencv-python 4.8.0.74

最低限のコードはこちら

from cv2 import aruco
import matplotlib.pyplot as plt


#aruco辞書の生成
dict_aruco=aruco.getPredefinedDictionary(aruco.DICT_4X4_50)

#IDを指定 (適当な整数)
marker_id=2

#マーカーサイズ
size_mark=100

#imgの作成
img=aruco.generateImageMarker(dict_aruco,marker_id,size_mark)

#表示
plt.imshow(img,cmap='gray')
こんなマーカーが生成されるはずです。markar_idを変えると値がかわります

マーカーの認識

詳細はソースコードを参照

マーカーの認識クラス

from cv2 import aruco

class ArucoDetect:
    def __init__(self) -> None:
        self.aruco_dict = aruco.getPredefinedDictionary(aruco.DICT_4X4_50)
        self.parameters = aruco.DetectorParameters()

    def detect(self, frame):
        corners, ids, rejectedImgPoints = aruco.detectMarkers(
            frame, self.aruco_dict, parameters=self.parameters)
        return corners, ids  # , rejectedImgPoints

カメラでの認識

通常のusbカメラ またはrealsenseの深度カメラを使います

#USBカメラ
from camera.USBCamera import USBCamera
camera=USBCamera(0)

#realsenseの深度カメラを使うとき
from camera.RealSense import RealSense
camera=RealSense()

認識
aruco_list[0]には座標、aruco_list[1]にはマーカーのidが入ります

dat=camera.get_frame()

#realsenseの時は、画像と深度の両方を返すので分ける
if len(dat)==2:
    frame,depth=dat

#arucoを認識して書き込み
aruco_list=aruco_detector.detect(frame)
annoted_frame=aruco.drawDetectedMarkers(frame,aruco_list[0],aruco_list[1])
plt.imshow(frame)

drawDetectedMarkersは自動的に境界を描画してくれるようです。
マーカーの左上部分に、青い四角がつきます。回転した画像にも対応しているということです。

これくらい雑な画像でもOKでした

深度の計測

深度カメラを使って、マーカーの深度を計測してみます。

import numpy as np
import cv2
from IPython.display import clear_output

while True:
    dat=camera.get_frame()
    frame,depth=dat

    #arucoを認識して書き込み
    aruco_list=aruco_detector.detect(frame)
    aruco.drawDetectedMarkers(frame,aruco_list[0],aruco_list[1])

    #マーカーの深度を計算
    for idx in range(len(aruco_list[0])):
        corners=aruco_list[0][idx]
        marker_id=aruco_list[1][idx]

        #cornersをintに変換
        corners=corners.astype(int)

        #四角で囲まれた領域内のdepthの平均値を取得
        mask = np.zeros(depth.shape, dtype=np.uint16)
        cv2.fillPoly(mask, corners.astype(np.int32), 255)
        masked_depth_image = cv2.bitwise_and(depth, mask)
        mean_depth = (np.median(masked_depth_image[mask > 0]))
        #mean_depth = stats.mode(masked_depth_image[mask > 0])[0]


        #mean_depthを書き込み
        cv2.putText(frame, str(mean_depth), (corners[0][0][0], corners[0][0][1]),
                    cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
        
    fig, axs = plt.subplots(nrows=1, ncols=2, figsize=(12,6))
    # Plot images
    axs[0].imshow(depth, cmap='plasma')
    axs[0].set_title('Depth image')
    
    axs[1].imshow(frame)
    axs[1].set_title('Color image')
    
    for ax in axs:
        ax.axis('off')
    #plt.imshow(frame)
    plt.show()
    clear_output(wait=True)


デバイスの問題?で、カメラを前後に動かすと、たまにおかしな値がでます。原因調査中


この記事が気に入ったらサポートをしてみませんか?