Skip to content

Commit 7dd52da

Browse files
committed
Python版のaruco_detectionを追加
1 parent aed6727 commit 7dd52da

3 files changed

Lines changed: 109 additions & 1 deletion

File tree

sciurus17_examples_py/launch/camera_example.launch.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ def generate_launch_description():
2525
declare_example_name = DeclareLaunchArgument(
2626
'example',
2727
default_value='color_detection',
28-
description=('Set an example executable name: [color_detection]'),
28+
description=('Set an example executable name: [aruco_detection, color_detection]'),
2929
)
3030

3131
declare_use_sim_time = DeclareLaunchArgument(
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
# Copyright 2026 RT Corporation
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
import cv2
16+
from cv2 import aruco
17+
from cv_bridge import CvBridge
18+
from geometry_msgs.msg import TransformStamped
19+
import message_filters
20+
import numpy as np
21+
import rclpy
22+
from rclpy.node import Node
23+
from scipy.spatial.transform import Rotation
24+
from sensor_msgs.msg import CameraInfo, Image
25+
from tf2_ros import TransformBroadcaster
26+
27+
28+
class ImageSubscriber(Node):
29+
def __init__(self):
30+
super().__init__('aruco_detection')
31+
self.image_sub = message_filters.Subscriber(
32+
self, Image, '/head_camera/color/image_raw'
33+
)
34+
self.info_sub = message_filters.Subscriber(
35+
self, CameraInfo, '/head_camera/color/camera_info'
36+
)
37+
self.ts = message_filters.TimeSynchronizer([self.image_sub, self.info_sub], 10)
38+
self.ts.registerCallback(self.camera_callback)
39+
40+
# ArUcoマーカのデータセットを読み込む
41+
# DICT_6x6_50は6x6ビットのマーカが50個収録されたもの
42+
self.marker_dict = aruco.getPredefinedDictionary(aruco.DICT_6X6_50)
43+
44+
self.tf_broadcaster = TransformBroadcaster(self)
45+
self.bridge = CvBridge()
46+
47+
def camera_callback(self, img_msg, info_msg):
48+
# 画像データをROSのメッセージからOpenCVの配列に変換
49+
cv_img = self.bridge.imgmsg_to_cv2(img_msg, desired_encoding=img_msg.encoding)
50+
cv_img = cv2.cvtColor(cv_img, cv2.COLOR_RGB2BGR)
51+
52+
# 画像座標系上のマーカ頂点位置
53+
corners = []
54+
# マーカID
55+
ids = []
56+
# マーカの検出
57+
corners, ids, _ = aruco.detectMarkers(cv_img, self.marker_dict)
58+
59+
if ids is None:
60+
return
61+
# マーカの検出数
62+
n_markers = len(ids)
63+
64+
# カメラパラメータ
65+
CAMERA_MATRIX = np.array(info_msg.k).reshape(3, 3)
66+
DIST_COEFFS = np.array(info_msg.d).reshape(1, 5)
67+
68+
# マーカ一辺の長さ 0.04 [m]
69+
MARKER_LENGTH = 0.04
70+
71+
# 画像座標系上のマーカ位置を三次元のカメラ座標系に変換
72+
rvecs, tvecs, _ = cv2.aruco.estimatePoseSingleMarkers(
73+
corners, MARKER_LENGTH, CAMERA_MATRIX, DIST_COEFFS
74+
)
75+
76+
# マーカの位置姿勢をtfで配信
77+
for i in range(n_markers):
78+
t = TransformStamped()
79+
t.header = img_msg.header
80+
t.child_frame_id = 'target_' + str(ids[i][0])
81+
t.transform.translation.x = tvecs[i][0][0]
82+
t.transform.translation.y = tvecs[i][0][1]
83+
t.transform.translation.z = tvecs[i][0][2]
84+
85+
# 回転ベクトルをクォータニオンに変換
86+
marker_orientation_rot = Rotation.from_rotvec(rvecs[i][0])
87+
marker_orientation_quat = marker_orientation_rot.as_quat()
88+
t.transform.rotation.x = marker_orientation_quat[0]
89+
t.transform.rotation.y = marker_orientation_quat[1]
90+
t.transform.rotation.z = marker_orientation_quat[2]
91+
t.transform.rotation.w = marker_orientation_quat[3]
92+
93+
self.tf_broadcaster.sendTransform(t)
94+
95+
96+
def main(args=None):
97+
rclpy.init(args=args)
98+
99+
image_subscriber = ImageSubscriber()
100+
rclpy.spin(image_subscriber)
101+
102+
image_subscriber.destroy_node()
103+
rclpy.shutdown()
104+
105+
106+
if __name__ == '__main__':
107+
main()

sciurus17_examples_py/setup.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
sciurus17_examples_py.pick_and_place_right_arm_waist:main',
3535
'pick_and_place_left_arm = sciurus17_examples_py.pick_and_place_left_arm:main',
3636
'pick_and_place_tf = sciurus17_examples_py.pick_and_place_tf:main',
37+
'aruco_detection = sciurus17_examples_py.aruco_detection:main',
3738
'color_detection = sciurus17_examples_py.color_detection:main',
3839
],
3940
},

0 commit comments

Comments
 (0)