iterative closest points
CEV ICP algorithm library
Loading...
Searching...
No Matches
vanilla.cpp
Go to the documentation of this file.
1
8#include <cassert>
9#include <cstddef>
10#include <cstdlib>
11#include <Eigen/Core>
12#include <Eigen/SVD>
13#include <Eigen/Dense>
14#include <vector>
15#include "icp/geo.h"
16
17#include "icp/impl/vanilla.h"
18
19/* #name Vanilla */
20/* #register vanilla */
21
22/* #desc The vanilla algorithm for ICP will match the point-cloud centers
23exactly and then iterate until an optimal rotation has been found. */
24
25namespace icp {
26 Vanilla::Vanilla([[maybe_unused]] const Config& config): ICP() {}
29
31 a_current.resize(a.size());
32
33 compute_matches();
34 }
35
37 const size_t n = a.size();
38
39 for (size_t i = 0; i < n; i++) {
40 a_current[i] = transform.apply_to(a[i]);
41 }
42
43 // can optimize by just transforming prev centroid if necessary
44 auto a_current_cm = get_centroid(a_current);
45
46 /*
47 #step
48 Matching Step: match closest points.
49
50 Sources:
51 https://ieeexplore.ieee.org/stamp/stamp.jsp?tp=&arnumber=4767965
52 https://arxiv.org/pdf/2206.06435.pdf
53 https://web.archive.org/web/20220615080318/https://www.cs.technion.ac.il/~cs236329/tutorials/ICP.pdf
54 https://en.wikipedia.org/wiki/Iterative_closest_point
55 https://courses.cs.duke.edu/spring07/cps296.2/scribe_notes/lecture24.pdf
56 -> use k-d tree
57 */
58 compute_matches();
59
60 icp::Vector corr_cm = icp::Vector::Zero();
61 for (size_t i = 0; i < matches.size(); i++) {
62 corr_cm += b[matches[i].pair];
63 }
64 corr_cm /= matches.size();
65
66 /*
67 #step
68 SVD
69
70 We compute the SVD of this magical matrix. A proof that this yields the optimal
71 transform R is in the source below.
72
73 Sources:
74 https://ieeexplore.ieee.org/stamp/stamp.jsp?tp=&arnumber=4767965
75 */
76 Matrix N = Matrix::Zero();
77 for (size_t i = 0; i < n; i++) {
78 N += (a_current[i] - a_current_cm) * (b[matches[i].pair] - corr_cm).transpose();
79 }
80 auto svd = N.jacobiSvd(Eigen::ComputeFullU | Eigen::ComputeFullV);
81 const Matrix U = svd.matrixU();
82 Matrix V = svd.matrixV();
83 Matrix R = V * U.transpose();
84
85 /*
86 #step
87 Reflection Handling
88
89 SVD may return a reflection instead of a rotation if it's equally good or better.
90 This is exceedingly rare with real data but may happen in very high noise
91 environment with sparse point cloud.
92
93 In the 2D case, we can always recover a reasonable rotation by negating the last
94 column of V. I do not know if this is the optimal rotation among rotations, but
95 we can probably get an answer to that question with more effort.
96
97 Sources:
98 https://ieeexplore.ieee.org/stamp/stamp.jsp?tp=&arnumber=4767965
99 */
100 if (R.determinant() < 0) {
101 V = V * Eigen::DiagonalMatrix<double, 2>(1, -1);
102 R = V * U.transpose();
103 }
104
105 /*
106 #step
107 Transformation Step: determine optimal transformation.
108
109 The translation vector is determined by the displacement between
110 the centroids of both point clouds. The rotation matrix is
111 calculated via singular value decomposition.
112
113 Sources:
114 https://ieeexplore.ieee.org/stamp/stamp.jsp?tp=&arnumber=4767965
115 https://courses.cs.duke.edu/spring07/cps296.2/scribe_notes/lecture24.pdf
116 */
117 RBTransform step(corr_cm - R * a_current_cm, R);
118
120 }
121}
122
123void icp::Vanilla::compute_matches() {
124 const size_t n = a.size();
125 const size_t m = b.size();
126
127 for (size_t i = 0; i < n; i++) {
128 matches[i].cost = std::numeric_limits<double>::infinity();
129 for (size_t j = 0; j < m; j++) {
130 // Point-to-point matching
131 double dist_ij = (b[j] - a_current[i]).squaredNorm();
132
133 if (dist_ij < matches[i].cost) {
134 matches[i].cost = dist_ij;
135 matches[i].pair = j;
136 }
137 }
138 }
139}
Configuration for ICP instances.
Definition icp.h:81
Interface for iterative closest points.
Definition icp.h:49
RBTransform transform
The current point cloud transformation that is being optimized.
Definition icp.h:59
std::vector< Vector > a
The source point cloud.
Definition icp.h:62
std::vector< Vector > b
The destination point cloud.
Definition icp.h:65
std::vector< Match > matches
The pairing of each point in a to its closest in b.
Definition icp.h:68
void iterate() override
Perform one iteration of ICP for the point clouds a and b provided with ICP::begin.
Definition vanilla.cpp:36
void setup() override
Per-method setup code.
Definition vanilla.cpp:30
Definition driver.h:12
Eigen::Vector2d Vector
Definition geo.h:15
Eigen::Matrix2d Matrix
Definition geo.h:16
Vector get_centroid(const std::vector< Vector > &points)
Definition geo.cpp:11
Rigid-body transformation.
Definition geo.h:19
RBTransform and_then(const RBTransform &next) const
Definition geo.h:36
Vector apply_to(Vector v) const
Definition geo.h:32