21 #include <eigen3/Eigen/Dense> 22 #include <eigen3/Eigen/SVD> 23 #include <eigen3/Eigen/Eigenvalues> 31 if (q.x == 0.0 && q.y == 0.0 && q.z == 0.0 && q.w == 0.0)
37 return 2.0*
atan2(q.z, q.w);
40 std::vector<geometry_msgs::Point>
41 transform(
const std::vector<geometry_msgs::Point>& points,
46 std::vector<geometry_msgs::Point> points_t;
48 double cos_th =
cos(theta);
49 double sin_th =
sin(theta);
51 for (
size_t i = 0; i < points.size(); i++)
53 geometry_msgs::Point pt = points[i];
54 geometry_msgs::Point pt_t;
57 pt_t.x = cos_th * pt.x - sin_th * pt.y + x;
58 pt_t.y = sin_th * pt.x + cos_th * pt.y + y;
60 points_t.push_back(pt_t);
66 geometry_msgs::Point
getCentroid(
const std::vector<geometry_msgs::Point> points)
68 geometry_msgs::Point pt;
69 for (
size_t i = 0; i < points.size(); i++)
74 pt.x /= points.size();
75 pt.y /= points.size();
83 const std::vector<geometry_msgs::Point>& target,
84 std::vector<geometry_msgs::Point>& correspondences)
86 correspondences.clear();
87 std::vector<size_t> c_num;
89 for (
size_t i = 0; i < source.size(); i++)
94 for (
size_t j = 0; j < target.size(); j++)
96 double dx = source[i].x - target[j].x;
97 double dy = source[i].y - target[j].y;
98 double dist = dx * dx + dy * dy;
111 correspondences.push_back(target[best]);
112 c_num.push_back(best);
119 bool alignPCA(
const std::vector<geometry_msgs::Point> source,
120 const std::vector<geometry_msgs::Point> target,
121 geometry_msgs::Transform& t)
127 std::vector<geometry_msgs::Point> source_t =
transform(source,
137 t.translation.x += ct.x - cs.x;
138 t.translation.y += ct.y - cs.y;
141 Eigen::MatrixXf Ps(2, source_t.size());
142 for (
size_t i = 0; i < source_t.size(); i++)
144 Ps(0, i) = source_t[i].x - cs.x;
145 Ps(1, i) = source_t[i].y - cs.y;
149 Eigen::MatrixXf Ms = Ps * Ps.transpose();
152 Eigen::EigenSolver<Eigen::MatrixXf> solver_s(Ms);
153 Eigen::MatrixXf
A = solver_s.eigenvectors().real();
154 Eigen::MatrixXf eig_of_Ms = solver_s.eigenvalues().real();
158 if (eig_of_Ms(0, 0) < eig_of_Ms(1, 0))
160 A.col(0).swap(A.col(1));
161 A.col(1) = -A.col(1);
164 Eigen::MatrixXf Pt(2, target.size());
165 for (
size_t i = 0; i < target.size(); i++)
167 Pt(0, i) = target[i].x - ct.x;
168 Pt(1, i) = target[i].y - ct.y;
172 Eigen::MatrixXf Mt = Pt * Pt.transpose();
175 Eigen::EigenSolver<Eigen::MatrixXf> solver_t(Mt);
176 Eigen::MatrixXf B = solver_t.eigenvectors().real();
177 Eigen::MatrixXf eig_of_Mt = solver_t.eigenvalues().real();
181 if (eig_of_Mt(0, 0) < eig_of_Mt(1, 0))
183 B.col(0).swap(B.col(1));
184 B.col(1) = -B.col(1);
188 Eigen::MatrixXf R = B * A.transpose();
191 theta +=
atan2(R(1, 0), R(0, 0));
192 t.rotation.z =
sin(theta / 2.0);
193 t.rotation.w =
cos(theta / 2.0);
197 bool alignSVD(
const std::vector<geometry_msgs::Point> source,
198 const std::vector<geometry_msgs::Point> target,
199 geometry_msgs::Transform& t)
204 std::vector<geometry_msgs::Point> source_t =
transform(source,
216 std::vector<geometry_msgs::Point> corr;
227 Eigen::MatrixXf P(2, corr.size());
228 for (
size_t i = 0; i < corr.size(); i++)
230 P(0, i) = corr[i].x - cs.x;
231 P(1, i) = corr[i].y - cs.y;
235 Eigen::MatrixXf Q(2, target.size());
236 for (
size_t i = 0; i < target.size(); i++)
238 Q(0, i) = target[i].x - ct.x;
239 Q(1, i) = target[i].y - ct.y;
243 Eigen::MatrixXf M = P * Q.transpose();
246 Eigen::JacobiSVD<Eigen::MatrixXf> svd(M, Eigen::ComputeThinU | Eigen::ComputeThinV);
249 Eigen::MatrixXf R = svd.matrixV() * svd.matrixU().transpose();
252 t.translation.x += (ct.x - cs.x);
253 t.translation.y += (ct.y - cs.y);
256 theta +=
atan2(R(1, 0), R(0, 0));
257 t.rotation.z =
sin(theta / 2.0);
258 t.rotation.w =
cos(theta / 2.0);
262 double getRMSD(
const std::vector<geometry_msgs::Point> source,
263 const std::vector<geometry_msgs::Point> target)
266 std::vector<geometry_msgs::Point> corr;
277 for (
size_t i = 0; i < source.size(); i++)
279 double dx = source[i].x - corr[i].x;
280 double dy = source[i].y - corr[i].y;
281 rmsd += dx * dx + dy * dy;
289 double alignICP(
const std::vector<geometry_msgs::Point> source,
290 const std::vector<geometry_msgs::Point> target,
291 geometry_msgs::Transform & t,
292 size_t max_iterations,
293 double min_delta_rmsd)
299 double prev_rmsd = -1.0;
302 for (
size_t iteration = 0; iteration < max_iterations; iteration++)
312 std::vector<geometry_msgs::Point>
320 double rmsd =
getRMSD(target, source_t);
325 if (fabs(prev_rmsd - rmsd) < min_delta_rmsd)
328 return getRMSD(source_t, target);
335 std::vector<geometry_msgs::Point>
342 return getRMSD(source_t, target);
std::vector< geometry_msgs::Point > transform(const std::vector< geometry_msgs::Point > &points, double x, double y, double theta)
Transform a vector of points in 2d.
double alignICP(const std::vector< geometry_msgs::Point > source, const std::vector< geometry_msgs::Point > target, geometry_msgs::Transform &transform, size_t max_iterations=10, double min_delta_rmsd=0.000001)
Perform Iterative Closest Point (ICP) algorithm to align two point clouds in a two dimensional plane...
double getRMSD(const std::vector< geometry_msgs::Point > source, const std::vector< geometry_msgs::Point > target)
double thetaFromQuaternion(const geometry_msgs::Quaternion &q)
Get the 2d rotation from a quaternion.
geometry_msgs::Point getCentroid(const std::vector< geometry_msgs::Point > points)
Get the centroid of a set of points.
INLINE Rall1d< T, V, S > sqrt(const Rall1d< T, V, S > &arg)
bool alignSVD(const std::vector< geometry_msgs::Point > source, const std::vector< geometry_msgs::Point > target, geometry_msgs::Transform &transform)
Perform SVD optimization to align two point clouds in a two dimensional plane.
bool computeCorrespondences(const std::vector< geometry_msgs::Point > &source, const std::vector< geometry_msgs::Point > &target, std::vector< geometry_msgs::Point > &correspondences)
bool alignPCA(const std::vector< geometry_msgs::Point > source, const std::vector< geometry_msgs::Point > target, geometry_msgs::Transform &transform)
Perform PCA algorithm to align two point clouds in a two dimensional plane.
INLINE Rall1d< T, V, S > atan2(const Rall1d< T, V, S > &y, const Rall1d< T, V, S > &x)
INLINE Rall1d< T, V, S > cos(const Rall1d< T, V, S > &arg)
INLINE Rall1d< T, V, S > sin(const Rall1d< T, V, S > &arg)