ArUcoマーカーの認識練習
はじめに
本記事は、ロボットに化学実験をさせるための試行錯誤の記録です。
webに諸々の類似情報があるかもしれませんが、勉強のため、車輪の再発明をする覚悟で進めています。
本日は、ロボット分野で定番となっているarucoマーカーの練習をします。
web上に色々とサンプルコードがあったのですが、open cvの仕様がコロコロ変わるようで、2023/7/12時点で動くものがあまり見つかりませんでした。
ArUcoマーカーとは?
QRコードのようなものです。
QRコードよりも画素が低いのが特徴です。入れられる情報量は減りますが、webカメラのような低性能な認識デバイスでも扱いやすいのが特長のようです。
マーカーの生成
ライブラリのインストール (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')
マーカーの認識
詳細はソースコードを参照
マーカーの認識クラス
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は自動的に境界を描画してくれるようです。
マーカーの左上部分に、青い四角がつきます。回転した画像にも対応しているということです。
深度の計測
深度カメラを使って、マーカーの深度を計測してみます。
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)
この記事が気に入ったらサポートをしてみませんか?