handeye_target_base.h
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 
37 #pragma once
38 
39 #include <mutex>
40 #include <algorithm>
41 #include <ros/ros.h>
42 #include <opencv2/opencv.hpp>
43 #include <sensor_msgs/CameraInfo.h>
46 #include <tf2_eigen/tf2_eigen.h>
47 #include <geometry_msgs/TransformStamped.h>
48 #include <opencv2/core/eigen.hpp>
49 
51 {
58 class HandEyeTargetBase
59 {
60 public:
61  class Parameter
62  {
63  public:
64  const enum ParameterType { Int, Float, Enum } parameter_type_;
65  const std::string name_;
66  union Value
67  {
68  int i;
69  float f;
70  std::size_t e;
71  } value_;
72  const std::vector<std::string> enum_values_;
73 
74  Parameter(std::string name, ParameterType parameter_type, int default_value = 0)
75  : name_(name), parameter_type_(parameter_type)
76  {
77  if (parameter_type_ == ParameterType::Int)
79  else
80  ROS_ERROR("Integer default value specified for non-integer parameter %s", name.c_str());
81  }
82 
83  Parameter(std::string name, ParameterType parameter_type, float default_value = 0.)
84  : name_(name), parameter_type_(parameter_type)
85  {
86  if (parameter_type_ == ParameterType::Float)
88  else
89  ROS_ERROR("Float default value specified for non-float parameter %s", name.c_str());
90  }
91 
92  Parameter(std::string name, ParameterType parameter_type, double default_value = 0.)
93  : name_(name), parameter_type_(parameter_type)
94  {
95  if (parameter_type_ == ParameterType::Float)
97  else
98  ROS_ERROR("Float default value specified for non-float parameter %s", name.c_str());
99  }
100 
101  Parameter(std::string name, ParameterType parameter_type, std::vector<std::string> enum_values,
102  size_t default_option = 0)
103  : name_(name), parameter_type_(parameter_type), enum_values_(enum_values)
104  {
105  if (default_option < enum_values_.size())
106  value_.e = default_option;
107  else
108  ROS_ERROR("Invalid default option for enum parameter %s", name.c_str());
109  }
110  };
111 
112  const std::string LOGNAME = "handeye_target_base";
113  const std::size_t CAMERA_MATRIX_VECTOR_DIMENSION = 9; // 3x3 camera intrinsic matrix
114  const std::size_t CAMERA_MATRIX_WIDTH = 3;
115  const std::size_t CAMERA_MATRIX_HEIGHT = 3;
116  const std::map<std::string, std::size_t> CAMERA_DISTORTION_MODELS_VECTOR_DIMENSIONS = { { "none", 0 },
117  { "plumb_bob", 5 },
118  { "rational_polynomial", 8 } };
119 
120  virtual ~HandEyeTargetBase() = default;
122  {
123  camera_matrix_ = cv::Mat::eye(3, 3, CV_64F);
124  distortion_coeffs_ = cv::Mat::zeros(5, 1, CV_64F);
125  }
126 
131  virtual bool initialize() = 0;
132 
138  virtual bool createTargetImage(cv::Mat& image) const = 0;
139 
147  virtual bool detectTargetPose(cv::Mat& image) = 0;
148 
154  virtual geometry_msgs::TransformStamped getTransformStamped(const std::string& frame_id) const
155  {
156  geometry_msgs::TransformStamped transform_stamped;
157  transform_stamped.header.stamp = ros::Time::now();
158  transform_stamped.header.frame_id = frame_id;
159  transform_stamped.child_frame_id = "handeye_target";
160 
161  transform_stamped.transform.rotation = convertToQuaternionROSMsg(rotation_vect_);
162  transform_stamped.transform.translation = convertToVectorROSMsg(translation_vect_);
163 
164  return transform_stamped;
165  }
166 
167  // Convert cv::Vec3d rotation vector to geometry_msgs::Quaternion
168  geometry_msgs::Quaternion convertToQuaternionROSMsg(const cv::Vec3d& input_rvect) const
169  {
170  cv::Mat cv_rotation_matrix;
171  cv::Rodrigues(input_rvect, cv_rotation_matrix);
172 
173  Eigen::Matrix3d eigen_rotation_matrix;
174  cv::cv2eigen(cv_rotation_matrix, eigen_rotation_matrix);
175  return tf2::toMsg(Eigen::Quaterniond(eigen_rotation_matrix));
176  }
177 
178  // Convert cv::Vec3d translation vector to geometry_msgs::Vector3
179  geometry_msgs::Vector3 convertToVectorROSMsg(const cv::Vec3d& input_tvect) const
180  {
181  Eigen::Vector3d eigen_tvect;
182  cv::cv2eigen(input_tvect, eigen_tvect);
183  geometry_msgs::Vector3 msg_tvect;
184  tf2::toMsg(eigen_tvect, msg_tvect);
185  return msg_tvect;
186  }
187 
188  // Replace OpenCV drawAxis func with custom one, drawing (x, y, z) -axes in red, green, blue color
189  void drawAxis(cv::InputOutputArray _image, cv::InputArray _cameraMatrix, cv::InputArray _distCoeffs,
190  cv::InputArray _rvec, cv::InputArray _tvec, float length) const
191  {
192  CV_Assert(_image.getMat().total() != 0 && (_image.getMat().channels() == 1 || _image.getMat().channels() == 3));
193  CV_Assert(length > 0);
194 
195  // project axis points
196  std::vector<cv::Point3f> axis_points;
197  axis_points.push_back(cv::Point3f(0, 0, 0));
198  axis_points.push_back(cv::Point3f(length, 0, 0));
199  axis_points.push_back(cv::Point3f(0, length, 0));
200  axis_points.push_back(cv::Point3f(0, 0, length));
201  std::vector<cv::Point2f> image_points;
202  cv::projectPoints(axis_points, _rvec, _tvec, _cameraMatrix, _distCoeffs, image_points);
203 
204  // draw axis lines
205  cv::line(_image, image_points[0], image_points[1], cv::Scalar(255, 0, 0), 3);
206  cv::line(_image, image_points[0], image_points[2], cv::Scalar(0, 255, 0), 3);
207  cv::line(_image, image_points[0], image_points[3], cv::Scalar(0, 0, 255), 3);
208  }
209 
215  virtual bool setCameraIntrinsicParams(const sensor_msgs::CameraInfoConstPtr& msg)
216  {
217  if (!msg)
218  {
219  ROS_ERROR_NAMED(LOGNAME, "CameraInfo msg is NULL.");
220  return false;
221  }
222 
223  if (msg->K.size() != CAMERA_MATRIX_VECTOR_DIMENSION)
224  {
225  ROS_ERROR_NAMED(LOGNAME, "Invalid camera matrix dimension, current is %ld, required is %zu.", msg->K.size(),
227  return false;
228  }
229 
230  if (0 == CAMERA_DISTORTION_MODELS_VECTOR_DIMENSIONS.count(msg->distortion_model))
231  {
232  ROS_ERROR_NAMED(LOGNAME, "Invalid camera distortion model, '%s'.", msg->distortion_model.c_str());
233  return false;
234  }
235 
236  const size_t camera_distortion_vector_dimension =
237  CAMERA_DISTORTION_MODELS_VECTOR_DIMENSIONS.at(msg->distortion_model);
238 
239  if (msg->D.size() != camera_distortion_vector_dimension)
240  {
241  ROS_ERROR_NAMED(LOGNAME, "Invalid distortion parameters dimension, current is %ld, required is %zu.",
242  msg->D.size(), camera_distortion_vector_dimension);
243  return false;
244  }
245 
246  std::lock_guard<std::mutex> base_lock(base_mutex_);
247 
248  // Store camera matrix info
249  for (size_t i = 0; i < CAMERA_MATRIX_WIDTH; i++)
250  {
251  for (size_t j = 0; j < CAMERA_MATRIX_HEIGHT; j++)
252  {
253  camera_matrix_.at<double>(i, j) = msg->K[i * CAMERA_MATRIX_WIDTH + j];
254  }
255  }
256 
257  // Store camera distortion info
258  distortion_coeffs_ = cv::Mat::zeros(camera_distortion_vector_dimension, 1, CV_64F);
259  for (size_t i = 0; i < camera_distortion_vector_dimension; i++)
260  {
261  distortion_coeffs_.at<double>(i, 0) = msg->D[i];
262  }
263 
264  ROS_DEBUG_STREAM_NAMED(LOGNAME, "Set camera intrinsic parameter to: " << *msg);
265  return true;
266  }
267 
272  virtual bool areIntrinsicsReasonable()
273  {
274  return cv::norm(camera_matrix_) != 0. && cv::norm(camera_matrix_, cv::Mat::eye(3, 3, CV_64F)) != 0.;
275  }
276 
281  virtual std::vector<Parameter> getParameters()
282  {
283  return parameters_;
284  }
285 
290  virtual bool setParameter(std::string name, int value)
291  {
292  for (auto& param : parameters_)
293  {
294  if (param.name_ == name && param.parameter_type_ == Parameter::Int)
295  {
296  param.value_.i = value;
297  return true;
298  }
299  }
300  return false;
301  }
302 
307  virtual bool setParameter(std::string name, float value)
308  {
309  for (auto& param : parameters_)
310  {
311  if (param.name_ == name && param.parameter_type_ == Parameter::Float)
312  {
313  param.value_.f = value;
314  return true;
315  }
316  }
317  return false;
318  }
319 
324  virtual bool setParameter(std::string name, double value)
325  {
326  for (auto& param : parameters_)
327  {
328  if (param.name_ == name && param.parameter_type_ == Parameter::Float)
329  {
330  param.value_.f = value;
331  return true;
332  }
333  }
334  return false;
335  }
336 
341  virtual bool setParameter(std::string name, std::string value)
342  {
343  for (auto& param : parameters_)
344  {
345  if (param.name_ == name && param.parameter_type_ == Parameter::Enum)
346  {
347  auto it = std::find(param.enum_values_.begin(), param.enum_values_.end(), value);
348  if (it != param.enum_values_.end())
349  {
350  param.value_.e = std::distance(param.enum_values_.begin(), it);
351  return true;
352  }
353  }
354  }
355  return false;
356  }
357 
362  virtual bool getParameter(std::string name, int& value) const
363  {
364  for (auto& param : parameters_)
365  {
366  if (param.name_ == name && param.parameter_type_ == Parameter::Int)
367  {
368  value = param.value_.i;
369  return true;
370  }
371  }
372  return false;
373  }
374 
379  virtual bool getParameter(std::string name, float& value) const
380  {
381  for (auto& param : parameters_)
382  {
383  if (param.name_ == name && param.parameter_type_ == Parameter::Float)
384  {
385  value = param.value_.f;
386  return true;
387  }
388  }
389  return false;
390  }
391 
396  virtual bool getParameter(std::string name, double& value) const
397  {
398  for (auto& param : parameters_)
399  {
400  if (param.name_ == name && param.parameter_type_ == Parameter::Float)
401  {
402  value = param.value_.f;
403  return true;
404  }
405  }
406  return false;
407  }
408 
413  virtual bool getParameter(std::string name, std::string& value) const
414  {
415  for (auto& param : parameters_)
416  {
417  if (param.name_ == name && param.parameter_type_ == Parameter::Enum)
418  {
419  value = param.enum_values_[param.value_.e];
420  return true;
421  }
422  }
423  return false;
424  }
425 
426 protected:
427  // 3x3 floating-point camera matrix
428  // [fx 0 cx]
429  // K = [ 0 fy cy]
430  // [ 0 0 1]
431  cv::Mat camera_matrix_;
432 
433  // Vector of distortion coefficients (k1, k2, t1, t2, k3)
434  // Assume `plumb_bob` model
435  cv::Mat distortion_coeffs_;
436 
437  // flag to indicate if target parameter values are correctly defined
439 
440  // List of parameters for this target type
441  std::vector<Parameter> parameters_;
442 
443  // Rotation and translation of the board w.r.t the camera frame
444  cv::Vec3d translation_vect_;
445  cv::Vec3d rotation_vect_;
446 
447  std::mutex base_mutex_;
448 };
449 } // namespace moveit_handeye_calibration
moveit_handeye_calibration::HandEyeTargetBase::distortion_coeffs_
cv::Mat distortion_coeffs_
Definition: handeye_target_base.h:467
moveit_handeye_calibration::HandEyeTargetBase::base_mutex_
std::mutex base_mutex_
Definition: handeye_target_base.h:479
tf2_eigen.h
ROS_DEBUG_STREAM_NAMED
#define ROS_DEBUG_STREAM_NAMED(name, args)
ros.h
moveit_handeye_calibration::HandEyeTargetBase::Parameter::Int
@ Int
Definition: handeye_target_base.h:96
moveit_handeye_calibration::HandEyeTargetBase::CAMERA_MATRIX_VECTOR_DIMENSION
const std::size_t CAMERA_MATRIX_VECTOR_DIMENSION
Definition: handeye_target_base.h:145
moveit_handeye_calibration::HandEyeTargetBase::createTargetImage
virtual bool createTargetImage(cv::Mat &image) const =0
Create an target image, so that the target can be viewed and printed.
moveit_handeye_calibration::HandEyeTargetBase::Parameter::Value::i
int i
Definition: handeye_target_base.h:100
moveit_handeye_calibration::HandEyeTargetBase::setParameter
virtual bool setParameter(std::string name, int value)
Set target parameter to integer value.
Definition: handeye_target_base.h:322
moveit_handeye_calibration::HandEyeTargetBase::convertToVectorROSMsg
geometry_msgs::Vector3 convertToVectorROSMsg(const cv::Vec3d &input_tvect) const
Definition: handeye_target_base.h:211
ROS_ERROR_NAMED
#define ROS_ERROR_NAMED(name,...)
moveit_handeye_calibration::HandEyeTargetBase::detectTargetPose
virtual bool detectTargetPose(cv::Mat &image)=0
Given an image containing a target captured from a camera view point, get the target pose with respec...
moveit_handeye_calibration::HandEyeTargetBase::target_params_ready_
bool target_params_ready_
Definition: handeye_target_base.h:470
moveit_handeye_calibration::HandEyeTargetBase::Parameter::parameter_type_
enum moveit_handeye_calibration::HandEyeTargetBase::Parameter::ParameterType parameter_type_
moveit_handeye_calibration::HandEyeTargetBase::parameters_
std::vector< Parameter > parameters_
Definition: handeye_target_base.h:473
moveit_handeye_calibration::HandEyeTargetBase::areIntrinsicsReasonable
virtual bool areIntrinsicsReasonable()
Check that camera intrinsic parameters are reasonable.
Definition: handeye_target_base.h:304
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
moveit_handeye_calibration::HandEyeTargetBase::Parameter::Float
@ Float
Definition: handeye_target_base.h:96
moveit_handeye_calibration::HandEyeTargetBase::~HandEyeTargetBase
virtual ~HandEyeTargetBase()=default
moveit_handeye_calibration::HandEyeTargetBase::getParameters
virtual std::vector< Parameter > getParameters()
Get parameters relevant to this target.
Definition: handeye_target_base.h:313
moveit_handeye_calibration::HandEyeTargetBase::getTransformStamped
virtual geometry_msgs::TransformStamped getTransformStamped(const std::string &frame_id) const
Get TransformStamped message from the target detection result, use for TF publish.
Definition: handeye_target_base.h:186
name
std::string name
moveit_handeye_calibration::HandEyeTargetBase::setCameraIntrinsicParams
virtual bool setCameraIntrinsicParams(const sensor_msgs::CameraInfoConstPtr &msg)
Set camera intrinsic parameters, e.g. camera intrinsic matrix and distortion coefficients.
Definition: handeye_target_base.h:247
moveit_handeye_calibration::HandEyeTargetBase::camera_matrix_
cv::Mat camera_matrix_
Definition: handeye_target_base.h:463
Quaternion.h
ROS_ERROR
#define ROS_ERROR(...)
moveit_handeye_calibration::HandEyeTargetBase::Parameter::Value::e
std::size_t e
Definition: handeye_target_base.h:102
moveit_handeye_calibration::HandEyeTargetBase::CAMERA_MATRIX_WIDTH
const std::size_t CAMERA_MATRIX_WIDTH
Definition: handeye_target_base.h:146
moveit_handeye_calibration::HandEyeTargetBase::Parameter::name_
const std::string name_
Definition: handeye_target_base.h:97
moveit_handeye_calibration::HandEyeTargetBase::Parameter::Parameter
Parameter(std::string name, ParameterType parameter_type, int default_value=0)
Definition: handeye_target_base.h:106
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::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::HandEyeTargetBase::Parameter::enum_values_
const std::vector< std::string > enum_values_
Definition: handeye_target_base.h:104
default_value
def default_value(type_)
moveit_handeye_calibration::HandEyeTargetBase::CAMERA_DISTORTION_MODELS_VECTOR_DIMENSIONS
const std::map< std::string, std::size_t > CAMERA_DISTORTION_MODELS_VECTOR_DIMENSIONS
Definition: handeye_target_base.h:148
moveit_handeye_calibration::HandEyeTargetBase::HandEyeTargetBase
HandEyeTargetBase()
Definition: handeye_target_base.h:153
tf2::toMsg
B toMsg(const A &a)
param
T param(const std::string &param_name, const T &default_val)
length
TF2SIMD_FORCE_INLINE tf2Scalar length(const Quaternion &q)
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::HandEyeTargetBase::Parameter::value_
union moveit_handeye_calibration::HandEyeTargetBase::Parameter::Value value_
moveit_handeye_calibration::HandEyeTargetBase::Parameter::Value::f
float f
Definition: handeye_target_base.h:101
Matrix3x3.h
moveit_handeye_calibration::HandEyeTargetBase::Parameter::Enum
@ Enum
Definition: handeye_target_base.h:96
moveit_handeye_calibration::HandEyeTargetBase::Parameter::ParameterType
ParameterType
Definition: handeye_target_base.h:96
moveit_handeye_calibration::HandEyeTargetBase::convertToQuaternionROSMsg
geometry_msgs::Quaternion convertToQuaternionROSMsg(const cv::Vec3d &input_rvect) const
Definition: handeye_target_base.h:200
moveit_handeye_calibration::HandEyeTargetBase::CAMERA_MATRIX_HEIGHT
const std::size_t CAMERA_MATRIX_HEIGHT
Definition: handeye_target_base.h:147
moveit_handeye_calibration::HandEyeTargetBase::initialize
virtual bool initialize()=0
Initialize handeye target. Call after setting the parameters.
ros::Time::now
static Time now()


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