NASA Astrobee Robot Software  0.19.1
Flight software for the Astrobee robots operating inside the International Space Station.
transformation_estimation_symmetric_point_to_plane_lls_impl.h
Go to the documentation of this file.
1 /*
2  * Software License Agreement (BSD License)
3  *
4  * Point Cloud Library (PCL) - www.pointclouds.org
5  * Copyright (c) 2019-, Open Perception, Inc.
6  *
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  *
13  * * Redistributions of source code must retain the above copyright
14  * notice, this list of conditions and the following disclaimer.
15  * * Redistributions in binary form must reproduce the above
16  * copyright notice, this list of conditions and the following
17  * disclaimer in the documentation and/or other materials provided
18  * with the distribution.
19  * * Neither the name of the copyright holder(s) nor the names of its
20  * contributors may be used to endorse or promote products derived
21  * from this software without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
26  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
27  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
28  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
29  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
31  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
33  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34  * POSSIBILITY OF SUCH DAMAGE.
35  *
36  */
37 
38 // TODO(rsoussan): Remove this file from repo when PCL updated to version >= 1.10
39 #ifndef POINT_CLOUD_COMMON_TRANSFORMATION_ESTIMATION_SYMMETRIC_POINT_TO_PLANE_LLS_IMPL_H_
40 #define POINT_CLOUD_COMMON_TRANSFORMATION_ESTIMATION_SYMMETRIC_POINT_TO_PLANE_LLS_IMPL_H_
41 
42 #include <pcl/cloud_iterator.h>
43 
44 #include <vector>
45 
46 namespace pcl {
47 
48 namespace registration {
49 
50 template <typename PointSource, typename PointTarget, typename Scalar>
51 inline void
53  const pcl::PointCloud<PointSource>& cloud_src, const pcl::PointCloud<PointTarget>& cloud_tgt,
54  Matrix4& transformation_matrix) const {
55  const auto nr_points = cloud_src.size();
56  if (cloud_tgt.size() != nr_points) {
57  PCL_ERROR(
58  "[pcl::TransformationEstimationSymmetricPointToPlaneLLS::"
59  "estimateRigidTransformation] Number or points in source (%zu) differs "
60  "from target (%zu)!\n",
61  static_cast<std::size_t>(nr_points), static_cast<std::size_t>(cloud_tgt.size()));
62  return;
63  }
64 
65  ConstCloudIterator<PointSource> source_it(cloud_src);
66  ConstCloudIterator<PointTarget> target_it(cloud_tgt);
67  estimateRigidTransformation(source_it, target_it, transformation_matrix);
68 }
69 
70 template <typename PointSource, typename PointTarget, typename Scalar>
72  const pcl::PointCloud<PointSource>& cloud_src, const std::vector<int>& indices_src,
73  const pcl::PointCloud<PointTarget>& cloud_tgt, Matrix4& transformation_matrix) const {
74  const auto nr_points = indices_src.size();
75  if (cloud_tgt.size() != nr_points) {
76  PCL_ERROR(
77  "[pcl::TransformationEstimationSymmetricPointToPlaneLLS::"
78  "estimateRigidTransformation] Number or points in source (%zu) differs "
79  "than target (%zu)!\n",
80  indices_src.size(), static_cast<std::size_t>(cloud_tgt.size()));
81  return;
82  }
83 
84  ConstCloudIterator<PointSource> source_it(cloud_src, indices_src);
85  ConstCloudIterator<PointTarget> target_it(cloud_tgt);
86  estimateRigidTransformation(source_it, target_it, transformation_matrix);
87 }
88 
89 template <typename PointSource, typename PointTarget, typename Scalar>
90 inline void
92  const pcl::PointCloud<PointSource>& cloud_src, const std::vector<int>& indices_src,
93  const pcl::PointCloud<PointTarget>& cloud_tgt, const std::vector<int>& indices_tgt,
94  Matrix4& transformation_matrix) const {
95  const auto nr_points = indices_src.size();
96  if (indices_tgt.size() != nr_points) {
97  PCL_ERROR(
98  "[pcl::TransformationEstimationSymmetricPointToPlaneLLS::"
99  "estimateRigidTransformation] Number or points in source (%zu) differs "
100  "than target (%zu)!\n",
101  indices_src.size(), indices_tgt.size());
102  return;
103  }
104 
105  ConstCloudIterator<PointSource> source_it(cloud_src, indices_src);
106  ConstCloudIterator<PointTarget> target_it(cloud_tgt, indices_tgt);
107  estimateRigidTransformation(source_it, target_it, transformation_matrix);
108 }
109 
110 template <typename PointSource, typename PointTarget, typename Scalar>
111 inline void
113  const pcl::PointCloud<PointSource>& cloud_src, const pcl::PointCloud<PointTarget>& cloud_tgt,
114  const pcl::Correspondences& correspondences, Matrix4& transformation_matrix) const {
115  ConstCloudIterator<PointSource> source_it(cloud_src, correspondences, true);
116  ConstCloudIterator<PointTarget> target_it(cloud_tgt, correspondences, false);
117  estimateRigidTransformation(source_it, target_it, transformation_matrix);
118 }
119 
120 template <typename PointSource, typename PointTarget, typename Scalar>
121 inline void
123  const Vector6& parameters, Matrix4& transformation_matrix) const {
124  // Construct the transformation matrix from rotation and translation
125  const Eigen::AngleAxis<Scalar> rotation_z(parameters(2), Eigen::Matrix<Scalar, 3, 1>::UnitZ());
126  const Eigen::AngleAxis<Scalar> rotation_y(parameters(1), Eigen::Matrix<Scalar, 3, 1>::UnitY());
127  const Eigen::AngleAxis<Scalar> rotation_x(parameters(0), Eigen::Matrix<Scalar, 3, 1>::UnitX());
128  const Eigen::Translation<Scalar, 3> translation(parameters(3), parameters(4), parameters(5));
129  const Eigen::Transform<Scalar, 3, Eigen::Affine> transform =
130  rotation_z * rotation_y * rotation_x * translation * rotation_z * rotation_y * rotation_x;
131  transformation_matrix = transform.matrix();
132 }
133 
134 template <typename PointSource, typename PointTarget, typename Scalar>
135 inline void
137  ConstCloudIterator<PointSource>& source_it, ConstCloudIterator<PointTarget>& target_it,
138  Matrix4& transformation_matrix) const {
139  using Matrix6 = Eigen::Matrix<Scalar, 6, 6>;
140  using Vector3 = Eigen::Matrix<Scalar, 3, 1>;
141 
142  Matrix6 ATA;
143  Vector6 ATb;
144  ATA.setZero();
145  ATb.setZero();
146  auto M = ATA.template selfadjointView<Eigen::Upper>();
147 
148  // Approximate as a linear least squares problem
149  source_it.reset();
150  target_it.reset();
151  for (; source_it.isValid() && target_it.isValid(); ++source_it, ++target_it) {
152  const Vector3 p(source_it->x, source_it->y, source_it->z);
153  const Vector3 q(target_it->x, target_it->y, target_it->z);
154  const Vector3 n1(source_it->getNormalVector3fMap().template cast<Scalar>());
155  const Vector3 n2(target_it->getNormalVector3fMap().template cast<Scalar>());
156  Vector3 n;
157  if (enforce_same_direction_normals_) {
158  if (n1.dot(n2) >= 0.)
159  n = n1 + n2;
160  else
161  n = n1 - n2;
162  } else {
163  n = n1 + n2;
164  }
165 
166  if (!p.array().isFinite().all() || !q.array().isFinite().all() || !n.array().isFinite().all()) {
167  continue;
168  }
169 
170  Vector6 v;
171  v << (p + q).cross(n), n;
172  M.rankUpdate(v);
173 
174  ATb += v * (q - p).dot(n);
175  }
176 
177  // Solve A*x = b
178  const Vector6 x = M.ldlt().solve(ATb);
179 
180  // Construct the transformation matrix from x
181  constructTransformationMatrix(x, transformation_matrix);
182 }
183 
184 template <typename PointSource, typename PointTarget, typename Scalar>
185 inline void
187  bool enforce_same_direction_normals) {
188  enforce_same_direction_normals_ = enforce_same_direction_normals;
189 }
190 
191 template <typename PointSource, typename PointTarget, typename Scalar>
192 inline bool
194  return enforce_same_direction_normals_;
195 }
196 
197 } // namespace registration
198 } // namespace pcl
199 #endif // POINT_CLOUD_COMMON_TRANSFORMATION_ESTIMATION_SYMMETRIC_POINT_TO_PLANE_LLS_IMPL_H_
pcl
Definition: correspondence_rejection_surface_normal2.h:45
pcl::registration::TransformationEstimationSymmetricPointToPlaneLLS2::Vector6
Eigen::Matrix< Scalar, 6, 1 > Vector6
Definition: transformation_estimation_symmetric_point_to_plane_lls.h:71
pcl::registration::TransformationEstimationSymmetricPointToPlaneLLS2::Matrix4
typename TransformationEstimation< PointSource, PointTarget, Scalar >::Matrix4 Matrix4
Definition: transformation_estimation_symmetric_point_to_plane_lls.h:70
pcl::registration::TransformationEstimationSymmetricPointToPlaneLLS2::setEnforceSameDirectionNormals
void setEnforceSameDirectionNormals(bool enforce_same_direction_normals)
Set whether or not to negate source or target normals on a per-point basis such that they point in th...
Definition: transformation_estimation_symmetric_point_to_plane_lls_impl.h:186
pcl::registration::TransformationEstimationSymmetricPointToPlaneLLS2::constructTransformationMatrix
void constructTransformationMatrix(const Vector6 &parameters, Matrix4 &transformation_matrix) const
Construct a 4 by 4 transformation matrix from the provided rotation and translation.
Definition: transformation_estimation_symmetric_point_to_plane_lls_impl.h:122
pcl::registration::TransformationEstimationSymmetricPointToPlaneLLS2::getEnforceSameDirectionNormals
bool getEnforceSameDirectionNormals()
Obtain whether source or target normals are negated on a per-point basis such that they point in the ...
Definition: transformation_estimation_symmetric_point_to_plane_lls_impl.h:193
pcl::registration::TransformationEstimationSymmetricPointToPlaneLLS2::estimateRigidTransformation
void estimateRigidTransformation(const pcl::PointCloud< PointSource > &cloud_src, const pcl::PointCloud< PointTarget > &cloud_tgt, Matrix4 &transformation_matrix) const override
Estimate a rigid rotation transformation between a source and a target point cloud using SVD.
Definition: transformation_estimation_symmetric_point_to_plane_lls_impl.h:52