handeye_target_charuco.cpp
Go to the documentation of this file.
1 /*********************************************************************
2  * Software License Agreement (BSD License)
3  *
4  * Copyright (c) 2020, PickNik, Inc.
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 PickNik, Inc., 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, John Stechschulte */
36 
38 
40 {
41 const std::string LOGNAME = "handeye_charuco_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("squares, X", Parameter::ParameterType::Int, 5));
55  parameters_.push_back(Parameter("squares, Y", Parameter::ParameterType::Int, 7));
56  parameters_.push_back(Parameter("marker size (px)", Parameter::ParameterType::Int, 50));
57  parameters_.push_back(Parameter("square size (px)", Parameter::ParameterType::Int, 80));
58  parameters_.push_back(Parameter("margin size (px)", Parameter::ParameterType::Int, 2));
59  parameters_.push_back(Parameter("marker border (bits)", Parameter::ParameterType::Int, 1));
60  std::vector<std::string> dictionaries;
61  for (const auto& kv : ARUCO_DICTIONARY)
62  {
63  dictionaries.push_back(kv.first);
64  }
65  parameters_.push_back(Parameter("ArUco dictionary", Parameter::ParameterType::Enum, dictionaries, 1));
66  parameters_.push_back(Parameter("longest board side (m)", Parameter::ParameterType::Float, 0.56));
67  parameters_.push_back(Parameter("measured marker size (m)", Parameter::ParameterType::Float, 0.06));
68 }
69 
71 {
73 
74  int squares_x;
75  int squares_y;
76  int marker_size_pixels;
77  int square_size_pixels;
78  int border_size_bits;
79  int margin_size_pixels;
80  std::string dictionary_id;
81  double board_size_meters;
82  double marker_size_meters;
83 
85  getParameter("squares, X", squares_x) && getParameter("squares, Y", squares_y) &&
86  getParameter("marker size (px)", marker_size_pixels) && getParameter("square size (px)", square_size_pixels) &&
87  getParameter("marker border (bits)", border_size_bits) && getParameter("margin size (px)", margin_size_pixels) &&
88  getParameter("ArUco dictionary", dictionary_id) && getParameter("longest board side (m)", board_size_meters) &&
89  getParameter("measured marker size (m)", marker_size_meters) &&
90  setTargetIntrinsicParams(squares_x, squares_y, marker_size_pixels, square_size_pixels, border_size_bits,
91  margin_size_pixels, dictionary_id) &&
92  setTargetDimension(board_size_meters, marker_size_meters);
93 
94  return target_params_ready_;
95 }
96 
97 bool HandEyeCharucoTarget::setTargetIntrinsicParams(int squares_x, int squares_y, int marker_size_pixels,
98  int square_size_pixels, int border_size_bits,
99  int margin_size_pixels, const std::string& dictionary_id)
100 {
101  if (squares_x <= 0 || squares_y <= 0 || marker_size_pixels <= 0 || square_size_pixels <= 0 ||
102  margin_size_pixels < 0 || border_size_bits <= 0 || square_size_pixels <= marker_size_pixels ||
103  0 == marker_dictionaries_.count(dictionary_id))
104  {
106  "Invalid target intrinsic params.\n"
107  << "squares_x " << std::to_string(squares_x) << "\n"
108  << "squares_y " << std::to_string(squares_y) << "\n"
109  << "marker_size_pixels " << std::to_string(marker_size_pixels) << "\n"
110  << "square_size_pixels " << std::to_string(square_size_pixels) << "\n"
111  << "border_size_bits " << std::to_string(border_size_bits) << "\n"
112  << "margin_size_pixels " << std::to_string(margin_size_pixels) << "\n"
113  << "dictionary_id " << dictionary_id << "\n");
114  return false;
115  }
116 
117  std::lock_guard<std::mutex> charuco_lock(charuco_mutex_);
118  squares_x_ = squares_x;
119  squares_y_ = squares_y;
120  marker_size_pixels_ = marker_size_pixels;
121  square_size_pixels_ = square_size_pixels;
122  border_size_bits_ = border_size_bits;
123  margin_size_pixels_ = margin_size_pixels;
124 
125  const auto& it = marker_dictionaries_.find(dictionary_id);
126  dictionary_id_ = it->second;
127 
128  return true;
129 }
130 
131 bool HandEyeCharucoTarget::setTargetDimension(double board_size_meters, double marker_size_meters)
132 {
133  // Check for positive sizes and valid aspect ratio
134  if (board_size_meters <= 0 || marker_size_meters <= 0 ||
135  board_size_meters < marker_size_meters * std::max(squares_x_, squares_y_))
136  {
138  "Invalid target measured dimensions. Longest board dimension: %f. Marker size: %f",
139  board_size_meters, marker_size_meters);
140  return false;
141  }
142 
143  std::lock_guard<std::mutex> charuco_lock(charuco_mutex_);
145  "Set target real dimensions: \n"
146  << "board_size_meters " << std::to_string(board_size_meters) << "\n"
147  << "marker_size_meters " << std::to_string(marker_size_meters) << "\n"
148  << "\n");
149  board_size_meters_ = board_size_meters;
150  marker_size_meters_ = marker_size_meters;
151  return true;
152 }
153 
154 bool HandEyeCharucoTarget::createTargetImage(cv::Mat& image) const
155 {
157  return false;
158  cv::Size image_size;
159  image_size.width = squares_x_ * square_size_pixels_ + 2 * margin_size_pixels_;
160  image_size.height = squares_y_ * square_size_pixels_ + 2 * margin_size_pixels_;
161 
162  try
163  {
164  // Create target
165  cv::Ptr<cv::aruco::Dictionary> dictionary = cv::aruco::getPredefinedDictionary(dictionary_id_);
166  cv::Ptr<cv::aruco::CharucoBoard> board = cv::aruco::CharucoBoard::create(
167  squares_x_, squares_y_, float(square_size_pixels_), float(marker_size_pixels_), dictionary);
168 
169  // Create target image
170  board->draw(image_size, image, margin_size_pixels_, border_size_bits_);
171  }
172  catch (const cv::Exception& e)
173  {
174  ROS_ERROR_STREAM_NAMED(LOGNAME, "ChArUco target image creation exception: " << e.what());
175  return false;
176  }
177 
178  return true;
179 }
180 
181 bool HandEyeCharucoTarget::detectTargetPose(cv::Mat& image)
182 {
184  return false;
185  std::lock_guard<std::mutex> base_lock(base_mutex_);
186  try
187  {
188  // Detect aruco board
189  charuco_mutex_.lock();
190  cv::Ptr<cv::aruco::Dictionary> dictionary = cv::aruco::getPredefinedDictionary(dictionary_id_);
191  float square_size_meters = board_size_meters_ / std::max(squares_x_, squares_y_);
192  cv::Ptr<cv::aruco::CharucoBoard> board =
193  cv::aruco::CharucoBoard::create(squares_x_, squares_y_, square_size_meters, marker_size_meters_, dictionary);
194  charuco_mutex_.unlock();
195  cv::Ptr<cv::aruco::DetectorParameters> params_ptr(new cv::aruco::DetectorParameters());
196 #if CV_MAJOR_VERSION == 3 && CV_MINOR_VERSION == 2
197  params_ptr->doCornerRefinement = true;
198 #else
199  params_ptr->cornerRefinementMethod = cv::aruco::CORNER_REFINE_NONE;
200 #endif
201 
202  std::vector<int> marker_ids;
203  std::vector<std::vector<cv::Point2f>> marker_corners;
204  cv::aruco::detectMarkers(image, dictionary, marker_corners, marker_ids, params_ptr);
205  if (marker_ids.empty())
206  {
207  ROS_DEBUG_STREAM_THROTTLE_NAMED(1., LOGNAME, "No aruco marker detected. Dictionary ID: " << dictionary_id_);
208  return false;
209  }
210 
211  // Find ChArUco corners
212  std::vector<cv::Point2f> charuco_corners;
213  std::vector<int> charuco_ids;
214  cv::aruco::interpolateCornersCharuco(marker_corners, marker_ids, image, board, charuco_corners, charuco_ids,
216 
217  // Estimate aruco board pose
218  bool valid = cv::aruco::estimatePoseCharucoBoard(charuco_corners, charuco_ids, board, camera_matrix_,
220 
221  // Draw the markers and frame axis if at least one marker is detected
222  if (!valid)
223  {
224  ROS_WARN_STREAM_THROTTLE_NAMED(1., LOGNAME, "Cannot estimate aruco board pose.");
225  return false;
226  }
227 
228  if (cv::norm(rotation_vect_) > 3.2 || std::log10(std::fabs(translation_vect_[0])) > 4 ||
229  std::log10(std::fabs(translation_vect_[1])) > 4 || std::log10(std::fabs(translation_vect_[2])) > 4)
230  {
231  ROS_WARN_STREAM_THROTTLE_NAMED(1., LOGNAME, "Invalid target pose, please check CameraInfo msg.");
232  return false;
233  }
234 
235  cv::Mat image_rgb;
236  cv::cvtColor(image, image_rgb, cv::COLOR_GRAY2RGB);
237  cv::aruco::drawDetectedMarkers(image_rgb, marker_corners);
239  image = image_rgb;
240  }
241  catch (const cv::Exception& e)
242  {
243  ROS_ERROR_STREAM_THROTTLE_NAMED(1., LOGNAME, "ChArUco target detection exception: " << e.what());
244  return false;
245  }
246 
247  return true;
248 }
249 
250 } // namespace moveit_handeye_calibration
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::HandEyeTargetBase::base_mutex_
std::mutex base_mutex_
Definition: handeye_target_base.h:479
handeye_target_charuco.h
moveit_handeye_calibration::HandEyeCharucoTarget::dictionary_id_
cv::aruco::PREDEFINED_DICTIONARY_NAME dictionary_id_
Definition: handeye_target_charuco.h:140
moveit_handeye_calibration::HandEyeCharucoTarget::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_charuco.cpp:186
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::HandEyeCharucoTarget::marker_dictionaries_
std::map< std::string, cv::aruco::PREDEFINED_DICTIONARY_NAME > marker_dictionaries_
Definition: handeye_target_charuco.h:131
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::HandEyeCharucoTarget::border_size_bits_
int border_size_bits_
Definition: handeye_target_charuco.h:138
moveit_handeye_calibration::HandEyeCharucoTarget::squares_x_
int squares_x_
Definition: handeye_target_charuco.h:134
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::HandEyeCharucoTarget::setTargetDimension
virtual bool setTargetDimension(double board_size_meters, double marker_size_meters)
Definition: handeye_target_charuco.cpp:163
moveit_handeye_calibration::HandEyeCharucoTarget::HandEyeCharucoTarget
HandEyeCharucoTarget()
Definition: handeye_target_charuco.cpp:84
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
Definition: handeye_solver_base.h:42
moveit_handeye_calibration::HandEyeCharucoTarget::margin_size_pixels_
int margin_size_pixels_
Definition: handeye_target_charuco.h:139
moveit_handeye_calibration::HandEyeTargetBase::LOGNAME
const std::string LOGNAME
Definition: handeye_target_base.h:144
moveit_handeye_calibration::HandEyeCharucoTarget::squares_y_
int squares_y_
Definition: handeye_target_charuco.h:135
moveit_handeye_calibration::HandEyeTargetBase::rotation_vect_
cv::Vec3d rotation_vect_
Definition: handeye_target_base.h:477
moveit_handeye_calibration::HandEyeCharucoTarget::setTargetIntrinsicParams
virtual bool setTargetIntrinsicParams(int markers_x, int markers_y, int marker_size_pixels, int square_size_pixels, int border_size_bits, int margin_size_pixels, const std::string &dictionary_id)
Definition: handeye_target_charuco.cpp:129
moveit_handeye_calibration::HandEyeCharucoTarget::marker_size_meters_
double marker_size_meters_
Definition: handeye_target_charuco.h:144
moveit_handeye_calibration::HandEyeCharucoTarget::square_size_pixels_
int square_size_pixels_
Definition: handeye_target_charuco.h:137
moveit_handeye_calibration::LOGNAME
const std::string LOGNAME
Definition: handeye_solver_default.cpp:78
moveit_handeye_calibration::HandEyeCharucoTarget::initialize
virtual bool initialize() override
Initialize handeye target. Call after setting the parameters.
Definition: handeye_target_charuco.cpp:102
moveit_handeye_calibration::HandEyeCharucoTarget::marker_size_pixels_
int marker_size_pixels_
Definition: handeye_target_charuco.h:136
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::HandEyeCharucoTarget::board_size_meters_
double board_size_meters_
Definition: handeye_target_charuco.h:143
moveit_handeye_calibration::HandEyeCharucoTarget::charuco_mutex_
std::mutex charuco_mutex_
Definition: handeye_target_charuco.h:146
moveit_handeye_calibration::HandEyeCharucoTarget::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_charuco.cpp:213


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