AprilTag识别
AprilTag 是一种基于图像的标识符系统,类似于二维码,但专为机器人视觉和增强现实(AR)应用设计。它由密歇根大学 APRIL 实验室开发,旨在通过摄像头快速、准确地检测和识别目标物体。
本节将介绍如何通过视觉识别AprilTag的内容。
示例运行
大家可以在套件的白色地图中看到三个AprilTag码,接下来不妨开启OriginMan电源,然后在MoboXterm或者Vscode中启动如下指令:
将OriginMan放置于地图上的Apriltag码前,运行后首先可以看到OriginMan将会把头部向下低下,开始观察视野内的Apriltag码
代码实现
代码放置于:originman_apriltag_detect/apriltag_detect.py
#!/usr/bin/env python3
# encoding:utf-8
import rclpy
from rclpy.node import Node
import cv2
from cv_bridge import CvBridge
from sensor_msgs.msg import Image
from std_msgs.msg import String
import apriltag
import numpy as np
class AprilTagDetectNode(Node):
def __init__(self):
super().__init__('image_publisher_node')
self.bridge = CvBridge()
# 创建发布者,发布 image_raw 话题
self.publisher_ = self.create_publisher(Image, 'image_raw', 10)
# 创建发布者,发布 AprilTag 识别信息
self.apriltag_info_pub = self.create_publisher(String, 'apriltag_info', 10)
# 打开摄像头,0 表示默认摄像头
self.cap = cv2.VideoCapture(0)
if not self.cap.isOpened():
self.get_logger().error("无法打开摄像头")
else:
# 创建定时器,定期发布图像
self.timer = self.create_timer(0.1, self.publish_image)
# 用于标记是否为首次发布图像
self.is_first_publish = True
# 初始化 AprilTag 检测器
self.detector = apriltag.Detector(searchpath=apriltag._get_demo_searchpath())
def publish_image(self):
ret, frame = self.cap.read()
if ret:
try:
# 进行 AprilTag 检测
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
detections = self.detector.detect(gray, return_image=False)
apriltag_info_msg = String()
if len(detections) != 0:
tag_info_list = []
for detection in detections:
corners = np.int0(detection.corners) # 获取四个角点
cv2.drawContours(frame, [np.array(corners, int)], -1, (0, 255, 255), 2)
tag_family = str(detection.tag_family, encoding='utf-8') # 获取 tag_family
tag_id = int(detection.tag_id) # 获取 tag_id
object_center_x, object_center_y = int(detection.center[0]), int(detection.center[1]) # 中心点
object_angle = int(np.degrees(np.arctan2(corners[0][1] - corners[1][1], corners[0][0] - corners[1][0]))) # 计算旋转角
self.get_logger().info(f"检测到 AprilTag - ID: {tag_id}, 家族: {tag_family}")
# 在图像上绘制标签信息
cv2.putText(frame, f"tag_id: {tag_id}", (10, frame.shape[0] - 30), cv2.FONT_HERSHEY_SIMPLEX, 0.65, [0, 255, 255], 2)
cv2.putText(frame, f"tag_family: {tag_family}", (10, frame.shape[0] - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.65, [0, 255, 255], 2)
tag_info_list.append(f"ID: {tag_id}, 家族: {tag_family}")
apriltag_info_msg.data = "; ".join(tag_info_list)
else:
cv2.putText(frame, "tag_id: None", (10, frame.shape[0] - 30), cv2.FONT_HERSHEY_SIMPLEX, 0.65, [0, 255, 255], 2)
cv2.putText(frame, "tag_family: None", (10, frame.shape[0] - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.65, [0, 255, 255], 2)
apriltag_info_msg.data = "未检测到 AprilTag"
# 发布 AprilTag 识别信息
self.apriltag_info_pub.publish(apriltag_info_msg)
# 将 OpenCV 图像转换为 ROS 图像消息
ros_image = self.bridge.cv2_to_imgmsg(frame, "bgr8")
# 发布图像消息
self.publisher_.publish(ros_image)
if self.is_first_publish:
self.get_logger().info('正在检测AprilTag信息')
self.is_first_publish = False
except Exception as e:
self.get_logger().error(f"Error converting image: {str(e)}")
else:
self.get_logger().error("无法读取图像帧")
def __del__(self):
# 释放摄像头资源
if self.cap.isOpened():
self.cap.release()
def main(args=None):
rclpy.init(args=args)
image_publisher_node = AprilTagDetectNode()
rclpy.spin(image_publisher_node)
image_publisher_node.destroy_node()
rclpy.shutdown()
if __name__ == '__main__':
main()