OdometryViso2.cpp
Go to the documentation of this file.
1 /*
2 Copyright (c) 2010-2016, Mathieu Labbe - IntRoLab - Universite de Sherbrooke
3 All rights reserved.
4 
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are met:
7  * Redistributions of source code must retain the above copyright
8  notice, this list of conditions and the following disclaimer.
9  * Redistributions in binary form must reproduce the above copyright
10  notice, this list of conditions and the following disclaimer in the
11  documentation and/or other materials provided with the distribution.
12  * Neither the name of the Universite de Sherbrooke nor the
13  names of its contributors may be used to endorse or promote products
14  derived from this software without specific prior written permission.
15 
16 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
20 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27 
30 #include "rtabmap/core/util2d.h"
32 #include "rtabmap/utilite/UTimer.h"
33 #include "rtabmap/utilite/UStl.h"
34 
35 #ifdef RTABMAP_VISO2
36 #include <viso_stereo.h>
37 
38 double computeFeatureFlow(const std::vector<Matcher::p_match>& matches)
39  {
40  double total_flow = 0.0;
41  for (size_t i = 0; i < matches.size(); ++i)
42  {
43  double x_diff = matches[i].u1c - matches[i].u1p;
44  double y_diff = matches[i].v1c - matches[i].v1p;
45  total_flow += sqrt(x_diff * x_diff + y_diff * y_diff);
46  }
47  return total_flow / matches.size();
48 }
49 #endif
50 
51 namespace rtabmap {
52 
54  Odometry(parameters),
55 #ifdef RTABMAP_VISO2
56  viso2_(0),
57  ref_frame_change_method_(0),
58  ref_frame_inlier_threshold_(Parameters::defaultOdomVisKeyFrameThr()),
59  ref_frame_motion_threshold_(5.0),
60  lost_(false),
61  keep_reference_frame_(false),
62 #endif
63  reference_motion_(Transform::getIdentity())
64 {
65 #ifdef RTABMAP_VISO2
66  Parameters::parse(parameters, Parameters::kOdomVisKeyFrameThr(), ref_frame_inlier_threshold_);
67 #endif
68  viso2Parameters_ = Parameters::filterParameters(parameters, "OdomViso2");
69 }
70 
72 {
73 #ifdef RTABMAP_VISO2
74  delete viso2_;
75 #endif
76 }
77 
78 void OdometryViso2::reset(const Transform & initialPose)
79 {
80  Odometry::reset(initialPose);
81 #ifdef RTABMAP_VISO2
82  if(viso2_)
83  {
84  delete viso2_;
85  viso2_ = 0;
86  }
87  lost_ = false;
90 #endif
91 }
92 
93 // return not null transform if odometry is correctly computed
95  SensorData & data,
96  const Transform & guess,
97  OdometryInfo * info)
98 {
99  Transform t;
100 #ifdef RTABMAP_VISO2
101  //based on https://github.com/srv/viso2/blob/indigo/viso2_ros/src/stereo_odometer.cpp
102 
103  UTimer timer;
104 
105  if(!data.depthRaw().empty())
106  {
107  UERROR("viso2 odometry doesn't support RGB-D data, only stereo. Aborting odometry update...");
108  return t;
109  }
110 
111  if(data.imageRaw().empty() ||
112  data.imageRaw().rows != data.rightRaw().rows ||
113  data.imageRaw().cols != data.rightRaw().cols)
114  {
115  UERROR("Not compatible left (%dx%d) or right (%dx%d) image.",
116  data.imageRaw().rows,
117  data.imageRaw().cols,
118  data.rightRaw().rows,
119  data.rightRaw().cols);
120  return t;
121  }
122 
123  if(!(data.stereoCameraModel().isValidForProjection() &&
126  {
127  UERROR("Invalid stereo camera model!");
128  return t;
129  }
130 
131  cv::Mat leftGray;
132  if(data.imageRaw().type() == CV_8UC3)
133  {
134  cv::cvtColor(data.imageRaw(), leftGray, CV_BGR2GRAY);
135  }
136  else if(data.imageRaw().type() == CV_8UC1)
137  {
138  leftGray = data.imageRaw();
139  }
140  else
141  {
142  UFATAL("Not supported color type!");
143  }
144  cv::Mat rightGray;
145  if(data.rightRaw().type() == CV_8UC3)
146  {
147  cv::cvtColor(data.rightRaw(), rightGray, CV_BGR2GRAY);
148  }
149  else if(data.rightRaw().type() == CV_8UC1)
150  {
151  rightGray = data.rightRaw();
152  }
153  else
154  {
155  UFATAL("Not supported color type!");
156  }
157 
158  int32_t dims[] = {leftGray.cols, leftGray.rows, leftGray.cols};
159  cv::Mat covariance;
160  if(viso2_ == 0)
161  {
162  VisualOdometryStereo::parameters params;
163  params.base = params.match.base = data.stereoCameraModel().baseline();
164  params.calib.cu = params.match.cu = data.stereoCameraModel().left().cx();
165  params.calib.cv = params.match.cv = data.stereoCameraModel().left().cy();
166  params.calib.f = params.match.f = data.stereoCameraModel().left().fx();
167 
168  Parameters::parse(viso2Parameters_, Parameters::kOdomViso2RansacIters(), params.ransac_iters);
169  Parameters::parse(viso2Parameters_, Parameters::kOdomViso2InlierThreshold(), params.inlier_threshold);
170  Parameters::parse(viso2Parameters_, Parameters::kOdomViso2Reweighting(), params.reweighting);
171 
172  Parameters::parse(viso2Parameters_, Parameters::kOdomViso2MatchNmsN(), params.match.nms_n);
173  Parameters::parse(viso2Parameters_, Parameters::kOdomViso2MatchNmsTau(), params.match.nms_tau);
174  Parameters::parse(viso2Parameters_, Parameters::kOdomViso2MatchBinsize(), params.match.match_binsize);
175  Parameters::parse(viso2Parameters_, Parameters::kOdomViso2MatchRadius(), params.match.match_radius);
176  Parameters::parse(viso2Parameters_, Parameters::kOdomViso2MatchDispTolerance(), params.match.match_disp_tolerance);
177  Parameters::parse(viso2Parameters_, Parameters::kOdomViso2MatchOutlierDispTolerance(), params.match.outlier_disp_tolerance);
178  Parameters::parse(viso2Parameters_, Parameters::kOdomViso2MatchOutlierFlowTolerance(), params.match.outlier_flow_tolerance);
179  bool multistage = Parameters::defaultOdomViso2MatchMultiStage();
180  bool halfResolution = Parameters::defaultOdomViso2MatchHalfResolution();
181  Parameters::parse(viso2Parameters_, Parameters::kOdomViso2MatchMultiStage(), multistage);
182  Parameters::parse(viso2Parameters_, Parameters::kOdomViso2MatchHalfResolution() , halfResolution);
183  params.match.multi_stage = multistage?1:0;
184  params.match.half_resolution = halfResolution?1:0;
185  Parameters::parse(viso2Parameters_, Parameters::kOdomViso2MatchRefinement(), params.match.refinement);
186 
187  Parameters::parse(viso2Parameters_, Parameters::kOdomViso2BucketMaxFeatures(), params.bucket.max_features);
188  Parameters::parse(viso2Parameters_, Parameters::kOdomViso2BucketWidth(), params.bucket.bucket_width);
189  Parameters::parse(viso2Parameters_, Parameters::kOdomViso2BucketHeight(), params.bucket.bucket_height);
190 
191  viso2_ = new VisualOdometryStereo(params);
192 
193  viso2_->process(leftGray.data, rightGray.data, dims);
194  t.setIdentity();
195  covariance = cv::Mat::eye(6,6, CV_64FC1)*9999.0;
196  }
197  else
198  {
199  bool success = viso2_->process(leftGray.data, rightGray.data, dims, lost_ || keep_reference_frame_);
200  if (success)
201  {
202  Matrix motionViso = Matrix::inv(viso2_->getMotion());
203  Transform motion(motionViso.val[0][0], motionViso.val[0][1], motionViso.val[0][2],motionViso.val[0][3],
204  motionViso.val[1][0], motionViso.val[1][1], motionViso.val[1][2],motionViso.val[1][3],
205  motionViso.val[2][0], motionViso.val[2][1], motionViso.val[2][2], motionViso.val[2][3]);
206  Transform camera_motion;
207 
208  if(lost_ || keep_reference_frame_)
209  {
210  camera_motion = reference_motion_.inverse() * motion;
211  }
212  else
213  {
214  camera_motion = motion;
215  }
216  reference_motion_ = motion; // store last motion as reference
217 
218  t=camera_motion;
219 
220  //based on values set in viso2_ros
221  covariance = cv::Mat::eye(6,6, CV_64FC1);
222  covariance.at<double>(0,0) = 0.002;
223  covariance.at<double>(1,1) = 0.002;
224  covariance.at<double>(2,2) = 0.05;
225  covariance.at<double>(3,3) = 0.09;
226  covariance.at<double>(4,4) = 0.09;
227  covariance.at<double>(5,5) = 0.09;
228 
229  lost_=false;
230  }
231  else
232  {
233  covariance = cv::Mat::eye(6,6, CV_64FC1)*9999.0;
234  lost_ = true;
235  }
236 
237  if(success)
238  {
239  // Proceed depending on the reference frame change method
240  if(ref_frame_change_method_==1)
241  {
242  // calculate current feature flow
243  double feature_flow = computeFeatureFlow(viso2_->getMatches());
244  keep_reference_frame_ = (feature_flow < ref_frame_motion_threshold_);
245  }
246  else
247  {
248  keep_reference_frame_ = ref_frame_inlier_threshold_==0 || viso2_->getNumberOfInliers() > ref_frame_inlier_threshold_;
249  }
250  }
251  else
252  {
253  keep_reference_frame_ = false;
254  }
255  }
256 
257  const Transform & localTransform = data.stereoCameraModel().localTransform();
258  if(!t.isNull() && !t.isIdentity() && !localTransform.isIdentity() && !localTransform.isNull())
259  {
260  // from camera frame to base frame
262  {
263  t = previousLocalTransform_ * t * localTransform.inverse();
264  }
265  else
266  {
267  t = localTransform * t * localTransform.inverse();
268  }
269  previousLocalTransform_ = localTransform;
270  }
271 
272  if(info)
273  {
274  info->type = (int)kTypeViso2;
275  info->keyFrameAdded = !keep_reference_frame_;
276  info->reg.matches = viso2_->getNumberOfMatches();
277  info->reg.inliers = viso2_->getNumberOfInliers();
278  if(covariance.cols == 6 && covariance.rows == 6 && covariance.type() == CV_64FC1)
279  {
280  info->reg.covariance = covariance;
281  }
282 
283  if(this->isInfoDataFilled())
284  {
285  std::vector<Matcher::p_match> matches = viso2_->getMatches();
286  info->refCorners.resize(matches.size());
287  info->newCorners.resize(matches.size());
288  info->cornerInliers.resize(matches.size());
289  for (size_t i = 0; i < matches.size(); ++i)
290  {
291  info->refCorners[i].x = matches[i].u1p;
292  info->refCorners[i].y = matches[i].v1p;
293  info->newCorners[i].x = matches[i].u1c;
294  info->newCorners[i].y = matches[i].v1c;
295  info->cornerInliers[i] = i;
296  }
297  }
298  }
299 
300  UINFO("Odom update time = %fs lost=%s", timer.elapsed(), lost_?"true":"false");
301 
302 #else
303  UERROR("RTAB-Map is not built with VISO2 support! Select another visual odometry approach.");
304 #endif
305  return t;
306 }
307 
308 } // namespace rtabmap
Transform previousLocalTransform_
Definition: OdometryViso2.h:59
static ParametersMap filterParameters(const ParametersMap &parameters, const std::string &group)
Definition: Parameters.cpp:209
static bool parse(const ParametersMap &parameters, const std::string &key, bool &value)
Definition: Parameters.cpp:446
std::vector< cv::Point2f > refCorners
Definition: OdometryInfo.h:120
Definition: UTimer.h:46
double elapsed()
Definition: UTimer.h:75
bool isInfoDataFilled() const
Definition: Odometry.h:72
virtual void reset(const Transform &initialPose=Transform::getIdentity())
Definition: Odometry.cpp:182
GLM_FUNC_DECL vecType< T, P > sqrt(vecType< T, P > const &x)
std::map< std::string, std::string > ParametersMap
Definition: Parameters.h:41
const cv::Mat & imageRaw() const
Definition: SensorData.h:161
#define UFATAL(...)
cv::Mat rightRaw() const
Definition: SensorData.h:173
bool isIdentity() const
Definition: Transform.cpp:136
virtual void reset(const Transform &initialPose=Transform::getIdentity())
Wrappers of STL for convenient functions.
const CameraModel & left() const
double cx() const
Definition: CameraModel.h:97
bool isNull() const
Definition: Transform.cpp:107
std::vector< int > cornerInliers
Definition: OdometryInfo.h:122
bool isValidForReprojection() const
Definition: CameraModel.h:81
double cy() const
Definition: CameraModel.h:98
#define false
Definition: ConvertUTF.c:56
detail::int32 int32_t
Definition: fwd.hpp:307
double fx() const
Definition: CameraModel.h:95
const CameraModel & right() const
ParametersMap viso2Parameters_
Definition: OdometryViso2.h:60
#define UERROR(...)
OdometryViso2(const rtabmap::ParametersMap &parameters=rtabmap::ParametersMap())
ULogger class and convenient macros.
const StereoCameraModel & stereoCameraModel() const
Definition: SensorData.h:194
std::vector< cv::Point2f > newCorners
Definition: OdometryInfo.h:121
RegistrationInfo reg
Definition: OdometryInfo.h:91
virtual Transform computeTransform(SensorData &image, const Transform &guess=Transform(), OdometryInfo *info=0)
Transform inverse() const
Definition: Transform.cpp:169
const Transform & localTransform() const
cv::Mat depthRaw() const
Definition: SensorData.h:172
#define UINFO(...)


rtabmap
Author(s): Mathieu Labbe
autogenerated on Wed Jun 5 2019 22:41:32