handeye_target_aruco.cpp
Go to the documentation of this file.
1 /*********************************************************************
2  * Software License Agreement (BSD License)
3  *
4  * Copyright (c) 2019, Intel Corporation.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * * Redistributions of source code must retain the above copyright
12  * notice, this list of conditions and the following disclaimer.
13  * * Redistributions in binary form must reproduce the above
14  * copyright notice, this list of conditions and the following
15  * disclaimer in the documentation and/or other materials provided
16  * with the distribution.
17  * * Neither the name of Intel nor the names of its
18  * contributors may be used to endorse or promote products derived
19  * from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  *********************************************************************/
34 
35 /* Author: Yu Yan */
36 
38 
40 {
41 const std::string LOGNAME = "handeye_aruco_target";
42 
43 // Predefined ARUCO dictionaries in OpenCV for creating ARUCO marker board
44 const std::map<std::string, cv::aruco::PREDEFINED_DICTIONARY_NAME> ARUCO_DICTIONARY = {
45  { "DICT_4X4_250", cv::aruco::DICT_4X4_250 },
46  { "DICT_5X5_250", cv::aruco::DICT_5X5_250 },
47  { "DICT_6X6_250", cv::aruco::DICT_6X6_250 },
48  { "DICT_7X7_250", cv::aruco::DICT_7X7_250 },
49  { "DICT_ARUCO_ORIGINAL", cv::aruco::DICT_ARUCO_ORIGINAL }
50 };
51 
53 {
54  parameters_.push_back(Parameter("markers, X", Parameter::ParameterType::Int, 3));
55  parameters_.push_back(Parameter("markers, Y", Parameter::ParameterType::Int, 4));
56  parameters_.push_back(Parameter("marker size (px)", Parameter::ParameterType::Int, 200));
57  parameters_.push_back(Parameter("marker separation (px)", Parameter::ParameterType::Int, 20));
58  parameters_.push_back(Parameter("marker border (bits)", Parameter::ParameterType::Int, 1));
59  std::vector<std::string> dictionaries;
60  for (const auto& kv : ARUCO_DICTIONARY)
61  {
62  dictionaries.push_back(kv.first);
63  }
64  parameters_.push_back(Parameter("ArUco dictionary", Parameter::ParameterType::Enum, dictionaries, 1));
65  parameters_.push_back(Parameter("measured marker size (m)", Parameter::ParameterType::Float, 0.2));
66  parameters_.push_back(Parameter("measured separation (m)", Parameter::ParameterType::Float, 0.02));
67 }
68 
70 {
72 
73  int markers_x;
74  int markers_y;
75  int marker_size;
76  int separation;
77  int border_bits;
78  std::string dictionary_id;
79  float marker_measured_size;
80  float marker_measured_separation;
81 
83  getParameter("markers, X", markers_x) && getParameter("markers, Y", markers_y) &&
84  getParameter("marker size (px)", marker_size) && getParameter("marker separation (px)", separation) &&
85  getParameter("marker border (bits)", border_bits) && getParameter("ArUco dictionary", dictionary_id) &&
86  getParameter("measured marker size (m)", marker_measured_size) &&
87  getParameter("measured separation (m)", marker_measured_separation) &&
88  setTargetIntrinsicParams(markers_x, markers_y, marker_size, separation, border_bits, dictionary_id) &&
89  setTargetDimension(marker_measured_size, marker_measured_separation);
90 
91  return target_params_ready_;
92 }
93 
94 bool HandEyeArucoTarget::setTargetIntrinsicParams(int markers_x, int markers_y, int marker_size, int separation,
95  int border_bits, const std::string& dictionary_id)
96 {
97  if (markers_x <= 0 || markers_y <= 0 || marker_size <= 0 || separation <= 0 || border_bits <= 0 ||
98  marker_dictionaries_.find(dictionary_id) == marker_dictionaries_.end())
99  {
101  "Invalid target intrinsic params.\n"
102  << "markers_x_ " << std::to_string(markers_x) << "\n"
103  << "markers_y_ " << std::to_string(markers_y) << "\n"
104  << "marker_size " << std::to_string(marker_size) << "\n"
105  << "separation " << std::to_string(separation) << "\n"
106  << "border_bits " << std::to_string(border_bits) << "\n"
107  << "dictionary_id " << dictionary_id << "\n");
108  return false;
109  }
110 
111  std::lock_guard<std::mutex> aruco_lock(aruco_mutex_);
112  markers_x_ = markers_x;
113  markers_y_ = markers_y;
114  marker_size_ = marker_size;
115  separation_ = separation;
116  border_bits_ = border_bits;
117 
118  const auto& it = marker_dictionaries_.find(dictionary_id);
119  dictionary_id_ = it->second;
120 
121  return true;
122 }
123 
124 bool HandEyeArucoTarget::setTargetDimension(double marker_measured_size, double marker_measured_separation)
125 {
126  if (marker_measured_size <= 0 || marker_measured_separation <= 0)
127  {
128  ROS_ERROR_THROTTLE_NAMED(2., LOGNAME, "Invalid target measured dimensions: marker_size %f, marker_seperation %f",
129  marker_measured_size, marker_measured_separation);
130  return false;
131  }
132 
133  std::lock_guard<std::mutex> aruco_lock(aruco_mutex_);
134  marker_size_real_ = marker_measured_size;
135  marker_separation_real_ = marker_measured_separation;
137  "Set target real dimensions: \n"
138  << "marker_measured_size " << std::to_string(marker_measured_size) << "\n"
139  << "marker_measured_separation " << std::to_string(marker_measured_separation)
140  << "\n");
141  return true;
142 }
143 
144 bool HandEyeArucoTarget::createTargetImage(cv::Mat& image) const
145 {
146  cv::Size image_size;
147  image_size.width = markers_x_ * (marker_size_ + separation_) - separation_ + 2 * separation_;
148  image_size.height = markers_y_ * (marker_size_ + separation_) - separation_ + 2 * separation_;
149 
150  try
151  {
152  // Create target
153  cv::Ptr<cv::aruco::Dictionary> dictionary = cv::aruco::getPredefinedDictionary(dictionary_id_);
154  cv::Ptr<cv::aruco::GridBoard> board =
155  cv::aruco::GridBoard::create(markers_x_, markers_y_, float(marker_size_), float(separation_), dictionary);
156 
157  // Create target image
158  board->draw(image_size, image, separation_, border_bits_);
159  }
160  catch (const cv::Exception& e)
161  {
162  ROS_ERROR_STREAM_NAMED(LOGNAME, "Aruco target image creation exception: " << e.what());
163  return false;
164  }
165 
166  return true;
167 }
168 
169 bool HandEyeArucoTarget::detectTargetPose(cv::Mat& image)
170 {
171  std::lock_guard<std::mutex> base_lock(base_mutex_);
172  try
173  {
174  // Detect aruco board
175  aruco_mutex_.lock();
176  cv::Ptr<cv::aruco::Dictionary> dictionary = cv::aruco::getPredefinedDictionary(dictionary_id_);
177  cv::Ptr<cv::aruco::GridBoard> board =
178  cv::aruco::GridBoard::create(markers_x_, markers_y_, marker_size_real_, marker_separation_real_, dictionary);
179  aruco_mutex_.unlock();
180  cv::Ptr<cv::aruco::DetectorParameters> params_ptr(new cv::aruco::DetectorParameters());
181 #if CV_MAJOR_VERSION == 3 && CV_MINOR_VERSION == 2
182  params_ptr->doCornerRefinement = true;
183 #else
184  params_ptr->cornerRefinementMethod = cv::aruco::CORNER_REFINE_NONE;
185 #endif
186 
187  std::vector<int> marker_ids;
188  std::vector<std::vector<cv::Point2f>> marker_corners;
189  cv::aruco::detectMarkers(image, dictionary, marker_corners, marker_ids, params_ptr);
190  if (marker_ids.empty())
191  {
192  ROS_DEBUG_STREAM_THROTTLE_NAMED(1., LOGNAME, "No aruco marker detected.");
193  return false;
194  }
195 
196  // Refine markers borders
197  std::vector<std::vector<cv::Point2f>> rejected_corners;
198  cv::aruco::refineDetectedMarkers(image, board, marker_corners, marker_ids, rejected_corners, camera_matrix_,
200 
201  // Estimate aruco board pose
202  int valid = cv::aruco::estimatePoseBoard(marker_corners, marker_ids, board, camera_matrix_, distortion_coeffs_,
204 
205  // Draw the markers and frame axis if at least one marker is detected
206  if (valid == 0)
207  {
208  ROS_WARN_STREAM_THROTTLE_NAMED(1., LOGNAME, "Cannot estimate aruco board pose.");
209  return false;
210  }
211 
212  if (std::log10(std::fabs(rotation_vect_[0])) > 10 || std::log10(std::fabs(rotation_vect_[1])) > 10 ||
213  std::log10(std::fabs(rotation_vect_[2])) > 10 || std::log10(std::fabs(translation_vect_[0])) > 10 ||
214  std::log10(std::fabs(translation_vect_[1])) > 10 || std::log10(std::fabs(translation_vect_[2])) > 10)
215  {
216  ROS_WARN_STREAM_THROTTLE_NAMED(1., LOGNAME, "Invalid target pose, please check CameraInfo msg.");
217  return false;
218  }
219 
220  cv::Mat image_rgb;
221  cv::cvtColor(image, image_rgb, cv::COLOR_GRAY2RGB);
222  cv::aruco::drawDetectedMarkers(image_rgb, marker_corners);
224  image = image_rgb;
225  }
226  catch (const cv::Exception& e)
227  {
228  ROS_ERROR_STREAM_THROTTLE_NAMED(1., LOGNAME, "Aruco target detection exception: " << e.what());
229  return false;
230  }
231 
232  return true;
233 }
234 
235 } // namespace moveit_handeye_calibration
moveit_handeye_calibration::HandEyeArucoTarget::separation_
int separation_
Definition: handeye_target_aruco.h:137
ROS_WARN_STREAM_THROTTLE_NAMED
#define ROS_WARN_STREAM_THROTTLE_NAMED(period, name, args)
moveit_handeye_calibration::HandEyeTargetBase::distortion_coeffs_
cv::Mat distortion_coeffs_
Definition: handeye_target_base.h:467
ROS_ERROR_THROTTLE_NAMED
#define ROS_ERROR_THROTTLE_NAMED(period, name,...)
moveit_handeye_calibration::HandEyeArucoTarget::createTargetImage
virtual bool createTargetImage(cv::Mat &image) const override
Create an target image, so that the target can be viewed and printed.
Definition: handeye_target_aruco.cpp:176
moveit_handeye_calibration::HandEyeArucoTarget::setTargetDimension
virtual bool setTargetDimension(double marker_measured_size, double marker_measured_separation)
Definition: handeye_target_aruco.cpp:156
moveit_handeye_calibration::HandEyeTargetBase::base_mutex_
std::mutex base_mutex_
Definition: handeye_target_base.h:479
moveit_handeye_calibration::HandEyeArucoTarget::aruco_mutex_
std::mutex aruco_mutex_
Definition: handeye_target_aruco.h:145
moveit_handeye_calibration::HandEyeArucoTarget::border_bits_
int border_bits_
Definition: handeye_target_aruco.h:138
moveit_handeye_calibration::HandEyeArucoTarget::markers_x_
int markers_x_
Definition: handeye_target_aruco.h:134
moveit_handeye_calibration::HandEyeArucoTarget::setTargetIntrinsicParams
virtual bool setTargetIntrinsicParams(int markers_x, int markers_y, int marker_size, int separation, int border_bits, const std::string &dictionary_id)
Definition: handeye_target_aruco.cpp:126
moveit_handeye_calibration::HandEyeArucoTarget::dictionary_id_
cv::aruco::PREDEFINED_DICTIONARY_NAME dictionary_id_
Definition: handeye_target_aruco.h:139
moveit_handeye_calibration::ARUCO_DICTIONARY
const std::map< std::string, cv::aruco::PREDEFINED_DICTIONARY_NAME > ARUCO_DICTIONARY
Definition: handeye_target_aruco.cpp:76
moveit_handeye_calibration::HandEyeArucoTarget::markers_y_
int markers_y_
Definition: handeye_target_aruco.h:135
ROS_DEBUG_STREAM_THROTTLE_NAMED
#define ROS_DEBUG_STREAM_THROTTLE_NAMED(period, name, args)
moveit_handeye_calibration::HandEyeTargetBase::target_params_ready_
bool target_params_ready_
Definition: handeye_target_base.h:470
moveit_handeye_calibration::HandEyeTargetBase::parameters_
std::vector< Parameter > parameters_
Definition: handeye_target_base.h:473
moveit_handeye_calibration::HandEyeTargetBase::getParameter
virtual bool getParameter(std::string name, int &value) const
Get target parameter integer value.
Definition: handeye_target_base.h:394
ROS_INFO_STREAM_THROTTLE_NAMED
#define ROS_INFO_STREAM_THROTTLE_NAMED(period, name, args)
moveit_handeye_calibration::HandEyeArucoTarget::marker_size_real_
double marker_size_real_
Definition: handeye_target_aruco.h:142
moveit_handeye_calibration::HandEyeTargetBase::camera_matrix_
cv::Mat camera_matrix_
Definition: handeye_target_base.h:463
ROS_ERROR_STREAM_NAMED
#define ROS_ERROR_STREAM_NAMED(name, args)
moveit_handeye_calibration::HandEyeArucoTarget::HandEyeArucoTarget
HandEyeArucoTarget()
Definition: handeye_target_aruco.cpp:84
moveit_handeye_calibration::HandEyeArucoTarget::marker_size_
int marker_size_
Definition: handeye_target_aruco.h:136
handeye_target_aruco.h
moveit_handeye_calibration::HandEyeArucoTarget::marker_separation_real_
double marker_separation_real_
Definition: handeye_target_aruco.h:143
ROS_ERROR_STREAM_THROTTLE_NAMED
#define ROS_ERROR_STREAM_THROTTLE_NAMED(period, name, args)
moveit_handeye_calibration::HandEyeTargetBase::translation_vect_
cv::Vec3d translation_vect_
Definition: handeye_target_base.h:476
moveit_handeye_calibration::HandEyeArucoTarget::marker_dictionaries_
std::map< std::string, cv::aruco::PREDEFINED_DICTIONARY_NAME > marker_dictionaries_
Definition: handeye_target_aruco.h:131
moveit_handeye_calibration
Definition: handeye_solver_base.h:42
moveit_handeye_calibration::HandEyeTargetBase::LOGNAME
const std::string LOGNAME
Definition: handeye_target_base.h:144
moveit_handeye_calibration::HandEyeTargetBase::rotation_vect_
cv::Vec3d rotation_vect_
Definition: handeye_target_base.h:477
moveit_handeye_calibration::HandEyeArucoTarget::detectTargetPose
virtual bool detectTargetPose(cv::Mat &image) override
Given an image containing a target captured from a camera view point, get the target pose with respec...
Definition: handeye_target_aruco.cpp:201
moveit_handeye_calibration::LOGNAME
const std::string LOGNAME
Definition: handeye_solver_default.cpp:78
moveit_handeye_calibration::HandEyeTargetBase::drawAxis
void drawAxis(cv::InputOutputArray _image, cv::InputArray _cameraMatrix, cv::InputArray _distCoeffs, cv::InputArray _rvec, cv::InputArray _tvec, float length) const
Definition: handeye_target_base.h:221
moveit_handeye_calibration::HandEyeArucoTarget::initialize
virtual bool initialize() override
Initialize handeye target. Call after setting the parameters.
Definition: handeye_target_aruco.cpp:101


moveit_calibration_plugins
Author(s): Yu Yan
autogenerated on Fri Oct 18 2024 02:14:08