35 #include "common/homography.h" 36 #include "tagStandard52h13.h" 37 #include "tagStandard41h12.h" 41 #include "tagCustom48h12.h" 42 #include "tagCircle21h7.h" 43 #include "tagCircle49h12.h" 60 if(!pnh.
getParam(
"standalone_tags", standalone_tag_descriptions))
82 if(!pnh.
getParam(
"tag_bundles", tag_bundle_descriptions))
84 ROS_WARN(
"No tag bundles specified");
103 ROS_WARN(
"remove_duplicates parameter not provided. Defaulting to true");
109 if (
family_ ==
"tagStandard52h13")
111 tf_ = tagStandard52h13_create();
113 else if (
family_ ==
"tagStandard41h12")
115 tf_ = tagStandard41h12_create();
117 else if (
family_ ==
"tag36h11")
119 tf_ = tag36h11_create();
123 tf_ = tag25h9_create();
127 tf_ = tag16h5_create();
129 else if (
family_ ==
"tagCustom48h12")
131 tf_ = tagCustom48h12_create();
133 else if (
family_ ==
"tagCircle21h7")
135 tf_ = tagCircle21h7_create();
137 else if (
family_ ==
"tagCircle49h12")
139 tf_ = tagCircle49h12_create();
143 ROS_WARN(
"Invalid tag family specified! Aborting");
148 td_ = apriltag_detector_create();
149 apriltag_detector_add_family(
td_,
tf_);
169 apriltag_detector_destroy(
td_);
175 if (
family_ ==
"tagStandard52h13")
177 tagStandard52h13_destroy(
tf_);
179 else if (
family_ ==
"tagStandard41h12")
181 tagStandard41h12_destroy(
tf_);
183 else if (
family_ ==
"tag36h11")
185 tag36h11_destroy(
tf_);
189 tag25h9_destroy(
tf_);
193 tag16h5_destroy(
tf_);
195 else if (
family_ ==
"tagCustom48h12")
197 tagCustom48h12_destroy(
tf_);
199 else if (
family_ ==
"tagCircle21h7")
201 tagCircle21h7_destroy(
tf_);
203 else if (
family_ ==
"tagCircle49h12")
205 tagCircle49h12_destroy(
tf_);
211 const sensor_msgs::CameraInfoConstPtr& camera_info) {
214 if (image->image.channels() == 1)
216 gray_image = image->image;
220 cv::cvtColor(image->image, gray_image, CV_BGR2GRAY);
222 image_u8_t apriltag_image = { .width = gray_image.cols,
223 .height = gray_image.rows,
224 .stride = gray_image.cols,
225 .buf = gray_image.data
232 double fx = camera_model.
fx();
233 double fy = camera_model.
fy();
234 double cx = camera_model.
cx();
235 double cy = camera_model.
cy();
256 AprilTagDetectionArray tag_detection_array;
257 std::vector<std::string > detection_names;
258 tag_detection_array.header = image->header;
259 std::map<std::string, std::vector<cv::Point3d > > bundleObjectPoints;
260 std::map<std::string, std::vector<cv::Point2d > > bundleImagePoints;
264 apriltag_detection_t *detection;
272 int tagID = detection->id;
273 bool is_part_of_bundle =
false;
283 is_part_of_bundle =
true;
284 std::string bundleName = bundle.
name();
289 bundleObjectPoints[bundleName]);
311 double tag_size = standaloneDescription->
size();
331 std::vector<cv::Point3d > standaloneTagObjectPoints;
332 std::vector<cv::Point2d > standaloneTagImagePoints;
333 addObjectPoints(tag_size/2, cv::Matx44d::eye(), standaloneTagObjectPoints);
336 standaloneTagImagePoints,
338 Eigen::Matrix3d rot = transform.block(0, 0, 3, 3);
339 Eigen::Quaternion<double> rot_quaternion(rot);
341 geometry_msgs::PoseWithCovarianceStamped tag_pose =
342 makeTagPose(transform, rot_quaternion, image->header);
345 AprilTagDetection tag_detection;
346 tag_detection.pose = tag_pose;
347 tag_detection.id.push_back(detection->id);
348 tag_detection.size.push_back(tag_size);
349 tag_detection_array.detections.push_back(tag_detection);
350 detection_names.push_back(standaloneDescription->
frame_name());
362 std::map<std::string,
363 std::vector<cv::Point3d> >::iterator it =
364 bundleObjectPoints.find(bundleName);
365 if (it != bundleObjectPoints.end())
371 Eigen::Matrix4d transform =
373 bundleImagePoints[bundleName], fx, fy, cx, cy);
374 Eigen::Matrix3d rot = transform.block(0, 0, 3, 3);
375 Eigen::Quaternion<double> rot_quaternion(rot);
377 geometry_msgs::PoseWithCovarianceStamped bundle_pose =
378 makeTagPose(transform, rot_quaternion, image->header);
381 AprilTagDetection tag_detection;
382 tag_detection.pose = bundle_pose;
385 tag_detection_array.detections.push_back(tag_detection);
386 detection_names.push_back(bundle.
name());
392 for (
unsigned int i=0; i<tag_detection_array.detections.size(); i++) {
393 geometry_msgs::PoseStamped pose;
394 pose.pose = tag_detection_array.detections[i].pose.pose.pose;
395 pose.header = tag_detection_array.detections[i].pose.header;
401 detection_names[i]));
405 return tag_detection_array;
410 int id1 = ((apriltag_detection_t*) first)->id;
411 int id2 = ((apriltag_detection_t*) second)->id;
412 return (id1 < id2) ? -1 : ((id1 == id2) ? 0 : 1);
419 bool duplicate_detected =
false;
427 apriltag_detection_t *detection;
429 int id_current = detection->id;
436 id_next = detection->id;
438 if (id_current == id_next || (id_current != id_next && duplicate_detected))
440 duplicate_detected =
true;
444 if (id_current != id_next)
447 "appears more than once in the image.");
448 duplicate_detected =
false;
460 double s, cv::Matx44d T_oi, std::vector<cv::Point3d >& objectPoints)
const 464 objectPoints.push_back(T_oi.get_minor<3, 4>(0, 0)*cv::Vec4d(-s,-s, 0, 1));
465 objectPoints.push_back(T_oi.get_minor<3, 4>(0, 0)*cv::Vec4d( s,-s, 0, 1));
466 objectPoints.push_back(T_oi.get_minor<3, 4>(0, 0)*cv::Vec4d( s, s, 0, 1));
467 objectPoints.push_back(T_oi.get_minor<3, 4>(0, 0)*cv::Vec4d(-s, s, 0, 1));
471 apriltag_detection_t *detection,
472 std::vector<cv::Point2d >& imagePoints)
const 476 double tag_x[4] = {-1,1,1,-1};
477 double tag_y[4] = {1,1,-1,-1};
481 for (
int i=0; i<4; i++)
485 homography_project(detection->H, tag_x[i], tag_y[i], &im_x, &im_y);
486 imagePoints.push_back(cv::Point2d(im_x, im_y));
491 std::vector<cv::Point3d > objectPoints,
492 std::vector<cv::Point2d > imagePoints,
493 double fx,
double fy,
double cx,
double cy)
const 498 cv::Matx33d cameraMatrix(fx, 0, cx,
501 cv::Vec4f distCoeffs(0,0,0,0);
505 cv::solvePnP(objectPoints, imagePoints, cameraMatrix, distCoeffs, rvec, tvec);
507 cv::Rodrigues(rvec, R);
509 wRo << R(0,0), R(0,1), R(0,2), R(1,0), R(1,1), R(1,2), R(2,0), R(2,1), R(2,2);
512 T.topLeftCorner(3, 3) = wRo;
514 tvec.at<
double>(0), tvec.at<
double>(1), tvec.at<
double>(2);
520 const Eigen::Matrix4d& transform,
521 const Eigen::Quaternion<double> rot_quaternion,
522 const std_msgs::Header& header)
524 geometry_msgs::PoseWithCovarianceStamped pose;
525 pose.header = header;
527 pose.pose.pose.position.x = transform(0, 3);
528 pose.pose.pose.position.y = transform(1, 3);
529 pose.pose.pose.position.z = transform(2, 3);
530 pose.pose.pose.orientation.x = rot_quaternion.x();
531 pose.pose.pose.orientation.y = rot_quaternion.y();
532 pose.pose.pose.orientation.z = rot_quaternion.z();
533 pose.pose.pose.orientation.w = rot_quaternion.w();
541 apriltag_detection_t *det;
547 bool is_part_of_bundle =
false;
553 is_part_of_bundle =
true;
559 if (!is_part_of_bundle &&
571 line(image->image, cv::Point((
int)det->p[0][0], (
int)det->p[0][1]),
572 cv::Point((
int)det->p[1][0], (
int)det->p[1][1]),
573 cv::Scalar(0, 0xff, 0));
574 line(image->image, cv::Point((
int)det->p[0][0], (
int)det->p[0][1]),
575 cv::Point((
int)det->p[3][0], (
int)det->p[3][1]),
576 cv::Scalar(0, 0, 0xff));
577 line(image->image, cv::Point((
int)det->p[1][0], (
int)det->p[1][1]),
578 cv::Point((
int)det->p[2][0], (
int)det->p[2][1]),
579 cv::Scalar(0xff, 0, 0));
580 line(image->image, cv::Point((
int)det->p[2][0], (
int)det->p[2][1]),
581 cv::Point((
int)det->p[3][0], (
int)det->p[3][1]),
582 cv::Scalar(0xff, 0, 0));
585 std::stringstream ss;
587 cv::String text = ss.str();
588 int fontface = cv::FONT_HERSHEY_SCRIPT_SIMPLEX;
589 double fontscale = 0.5;
591 cv::Size textsize = cv::getTextSize(text, fontface,
592 fontscale, 2, &baseline);
593 cv::putText(image->image, text,
594 cv::Point((
int)(det->c[0]-textsize.width/2),
595 (
int)(det->c[1]+textsize.height/2)),
596 fontface, fontscale, cv::Scalar(0xff, 0x99, 0), 2);
605 std::map<int, StandaloneTagDescription> descriptions;
609 for (int32_t i = 0; i < standalone_tags.
size(); i++)
622 ROS_ASSERT(tag_description[
"size"].getType() ==
625 int id = (int)tag_description[
"id"];
627 double size = (double)tag_description[
"size"];
630 std::string frame_name;
634 ROS_ASSERT(tag_description[
"name"].getType() ==
636 frame_name = (std::string)tag_description[
"name"];
640 std::stringstream frame_name_stream;
641 frame_name_stream <<
"tag_" << id;
642 frame_name = frame_name_stream.str();
647 size <<
", frame_name: " << frame_name.c_str());
649 descriptions.insert(std::make_pair(
id, description));
659 std::vector<TagBundleDescription > descriptions;
663 for (int32_t i=0; i<tag_bundles.
size(); i++)
669 std::string bundleName;
670 if (bundle_description.
hasMember(
"name"))
672 ROS_ASSERT(bundle_description[
"name"].getType() ==
674 bundleName = (std::string)bundle_description[
"name"];
678 std::stringstream bundle_name_stream;
679 bundle_name_stream <<
"bundle_" << i;
680 bundleName = bundle_name_stream.str();
683 ROS_INFO(
"Loading tag bundle '%s'",bundle_i.
name().c_str());
685 ROS_ASSERT(bundle_description[
"layout"].getType() ==
690 for (int32_t j=0; j<member_tags.
size(); j++)
699 double size = tag[
"size"];
706 ROS_ASSERT(size == standaloneDescription->
size());
717 Eigen::Quaterniond q_tag(qw, qx, qy, qz);
719 Eigen::Matrix3d R_oi = q_tag.toRotationMatrix();
722 cv::Matx44d T_mj(R_oi(0,0), R_oi(0,1), R_oi(0,2), x,
723 R_oi(1,0), R_oi(1,1), R_oi(1,2), y,
724 R_oi(2,0), R_oi(2,1), R_oi(2,2), z,
729 ROS_INFO_STREAM(
" " << j <<
") id: " <<
id <<
", size: " << size <<
", " 730 <<
"p = [" << x <<
"," << y <<
"," << z <<
"], " 731 <<
"q = [" << qw <<
"," << qx <<
"," << qy <<
"," 734 descriptions.push_back(bundle_i);
740 std::string field)
const 746 int tmp = xmlValue[field];
751 return xmlValue[field];
757 double defaultValue)
const 765 int tmp = xmlValue[field];
770 return xmlValue[field];
782 std::map<int, StandaloneTagDescription>::iterator description_itr =
789 " but no description was found...",
id);
793 descriptionContainer = &(description_itr->second);
cv::Matx44d memberT_oi(int tagID)
static int idComparison(const void *first, const void *second)
const std::string & getMessage() const
void addImagePoints(apriltag_detection_t *detection, std::vector< cv::Point2d > &imagePoints) const
#define ROS_WARN_THROTTLE(rate,...)
std::map< int, StandaloneTagDescription > parseStandaloneTags(XmlRpc::XmlRpcValue &standalone_tag_descriptions)
bool findStandaloneTagDescription(int id, StandaloneTagDescription *&descriptionContainer, bool printWarning=true)
void addMemberTag(int id, double size, cv::Matx44d T_oi)
void addObjectPoints(double s, cv::Matx44d T_oi, std::vector< cv::Point3d > &objectPoints) const
std::map< int, StandaloneTagDescription > standalone_tag_descriptions_
TagDetector(ros::NodeHandle pnh)
T getAprilTagOption(ros::NodeHandle &pnh, const std::string ¶m_name, const T &default_val)
Type const & getType() const
TFSIMD_FORCE_INLINE const tfScalar & y() const
tf::TransformBroadcaster tf_pub_
AprilTagDetectionArray detectTags(const cv_bridge::CvImagePtr &image, const sensor_msgs::CameraInfoConstPtr &camera_info)
geometry_msgs::PoseWithCovarianceStamped makeTagPose(const Eigen::Matrix4d &transform, const Eigen::Quaternion< double > rot_quaternion, const std_msgs::Header &header)
void drawDetections(cv_bridge::CvImagePtr image)
double xmlRpcGetDouble(XmlRpc::XmlRpcValue &xmlValue, std::string field) const
std::vector< int > bundleIds()
std::string camera_tf_frame_
apriltag_detector_t * td_
bool fromCameraInfo(const sensor_msgs::CameraInfo &msg)
double xmlRpcGetDoubleWithDefault(XmlRpc::XmlRpcValue &xmlValue, std::string field, double defaultValue) const
TFSIMD_FORCE_INLINE const tfScalar & x() const
#define ROS_WARN_STREAM(args)
std::vector< double > bundleSizes()
TFSIMD_FORCE_INLINE const tfScalar & z() const
bool hasMember(const std::string &name) const
Eigen::Matrix4d getRelativeTransform(std::vector< cv::Point3d > objectPoints, std::vector< cv::Point2d > imagePoints, double fx, double fy, double cx, double cy) const
#define ROS_INFO_STREAM(args)
bool getParam(const std::string &key, std::string &s) const
std::vector< TagBundleDescription > tag_bundle_descriptions_
static void poseStampedMsgToTF(const geometry_msgs::PoseStamped &msg, Stamped< Pose > &bt)
#define ROS_ERROR_STREAM(args)
std::string & frame_name()
double memberSize(int tagID)
std::vector< TagBundleDescription > parseTagBundles(XmlRpc::XmlRpcValue &tag_bundles)
std::map< int, int > id2idx_