17 #include "pipelines/registration/Registration.h"
21 namespace registration {
28 std::map<int, int> corres_ij;
29 std::vector<int> corres_ji(dst_features.
data_.cols(), -1);
31 #pragma omp for nowait
32 for (
int j = 0; j < dst_features.
data_.cols(); j++) {
33 std::vector<int> corres_tmp(1);
34 std::vector<double> dist_tmp(1);
35 src_feature_tree.
SearchKNN(Eigen::VectorXd(dst_features.
data_.col(j)),
36 1, corres_tmp, dist_tmp);
37 int i = corres_tmp[0];
39 if (corres_ij.find(i) == corres_ij.end()) {
46 Eigen::VectorXd(src_features.
data_.col(i)), 1, corres_tmp,
48 corres_ij[i] = corres_tmp[0];
53 std::vector<std::pair<int, int>> corres_cross;
54 for (
const std::pair<const int, int>& ij : corres_ij) {
55 if (corres_ji[ij.second] == ij.first) corres_cross.push_back(ij);
64 const std::vector<std::pair<int, int>>& corres_cross,
67 int rand0, rand1, rand2, i, cnt = 0;
68 int idi0, idi1, idi2, idj0, idj1, idj2;
70 int ncorr =
static_cast<int>(corres_cross.size());
71 int number_of_trial = ncorr * 100;
75 "Not enough correspondences for tuple test. At least 3 needed, "
82 std::vector<std::pair<int, int>> corres_tuple;
83 for (i = 0; i < number_of_trial; i++) {
84 rand0 = rand_generator();
85 rand1 = rand_generator();
86 rand2 = rand_generator();
87 idi0 = corres_cross[rand0].first;
88 idj0 = corres_cross[rand0].second;
89 idi1 = corres_cross[rand1].first;
90 idj1 = corres_cross[rand1].second;
91 idi2 = corres_cross[rand2].first;
92 idj2 = corres_cross[rand2].second;
98 double li0 = (pti0 - pti1).norm();
99 double li1 = (pti1 - pti2).norm();
100 double li2 = (pti2 - pti0).norm();
106 double lj0 = (ptj0 - ptj1).norm();
107 double lj1 = (ptj1 - ptj2).norm();
108 double lj2 = (ptj2 - ptj0).norm();
111 if ((li0 * scale < lj0) && (lj0 < li0 / scale) && (li1 * scale < lj1) &&
112 (lj1 < li1 / scale) && (li2 * scale < lj2) && (lj2 < li2 / scale)) {
113 corres_tuple.push_back(std::pair<int, int>(idi0, idj0));
114 corres_tuple.push_back(std::pair<int, int>(idi1, idj1));
115 corres_tuple.push_back(std::pair<int, int>(idi2, idj2));
129 std::vector<ccPointCloud>& point_cloud_vec,
133 std::vector<Eigen::Vector3d> pcd_mean_vec;
134 double scale_global, scale_start;
136 for (
int i = 0; i < num; ++i) {
137 double max_scale = 0.0;
138 Eigen::Vector3d mean;
141 int npti =
static_cast<int>(point_cloud_vec[i].size());
142 for (
int ii = 0; ii < npti; ++ii)
144 point_cloud_vec[i].getEigenPoint(
static_cast<size_t>(ii));
146 pcd_mean_vec.push_back(mean);
149 mean(0), mean(1), mean(2));
150 for (
int ii = 0; ii < npti; ++ii)
151 *point_cloud_vec[i].getPointPtr(
static_cast<size_t>(ii)) -= mean;
153 for (
int ii = 0; ii < npti; ++ii) {
155 point_cloud_vec[i].getEigenPoint(
static_cast<size_t>(ii)));
156 double temp = p.norm();
157 if (temp > max_scale) max_scale = temp;
159 if (max_scale > scale) scale = max_scale;
166 scale_global = scale;
170 if (scale_global <= 0) {
175 for (
int i = 0; i < num; ++i) {
176 int npti =
static_cast<int>(point_cloud_vec[i].size());
177 for (
int ii = 0; ii < npti; ++ii) {
178 *point_cloud_vec[i].getPointPtr(
static_cast<size_t>(ii)) /=
179 static_cast<float>(scale_global);
182 return std::make_tuple(pcd_mean_vec, scale_global, scale_start);
186 const std::vector<ccPointCloud>& point_cloud_vec,
187 const std::vector<std::pair<int, int>>& corres,
191 double par = scale_start;
197 if (corres.size() < 10)
return Eigen::Matrix4d::Identity();
199 std::vector<double> s(corres.size(), 1.0);
200 Eigen::Matrix4d trans;
203 for (
int itr = 0; itr < numIter; itr++) {
204 const int nvariable = 6;
205 Eigen::MatrixXd JTJ(nvariable, nvariable);
206 Eigen::MatrixXd JTr(nvariable, 1);
207 Eigen::MatrixXd J(nvariable, 1);
210 double r = 0.0, r2 = 0.0;
212 for (
size_t c = 0; c < corres.size(); c++) {
213 int ii = corres[c].first;
214 int jj = corres[c].second;
215 Eigen::Vector3d p, q;
216 p = point_cloud_vec[i].getEigenPoint(
static_cast<size_t>(ii));
217 q = point_cloud_copy_j.
getEigenPoint(
static_cast<size_t>(jj));
218 Eigen::Vector3d rpq = p - q;
221 double temp = par / (rpq.dot(rpq) + par);
229 JTJ += J * J.transpose() * s[c2];
230 JTr += J * r * s[c2];
238 JTJ += J * J.transpose() * s[c2];
239 JTr += J * r * s[c2];
247 JTJ += J * J.transpose() * s[c2];
248 JTr += J * r * s[c2];
250 r2 += (par * (1.0 - sqrt(s[c2])) * (1.0 - sqrt(s[c2])));
256 trans = delta * trans;
272 const Eigen::Matrix4d& transformation,
273 const std::vector<Eigen::Vector3d>& pcd_mean_vec,
274 const double scale_global) {
275 Eigen::Matrix3d R = transformation.block<3, 3>(0, 0);
276 Eigen::Vector3d t = transformation.block<3, 1>(0, 3);
277 Eigen::Matrix4d transtemp = Eigen::Matrix4d::Zero();
278 transtemp.block<3, 3>(0, 0) = R;
279 transtemp.block<3, 1>(0, 3) =
280 -R * pcd_mean_vec[1] + t * scale_global + pcd_mean_vec[0];
294 std::vector<ccPointCloud> point_cloud_vec;
295 point_cloud_vec.push_back(source);
296 point_cloud_vec.push_back(target);
298 double scale_global, scale_start;
299 std::vector<Eigen::Vector3d> pcd_mean_vec;
300 std::tie(pcd_mean_vec, scale_global, scale_start) =
303 std::vector<std::pair<int, int>> corresvec;
304 corresvec.reserve(corres.size());
305 for (
size_t i = 0; i < corres.size(); ++i) {
306 corresvec.push_back({corres[i](0), corres[i](1)});
313 Eigen::Matrix4d transformation;
315 scale_global, option);
336 std::vector<ccPointCloud> point_cloud_vec;
337 point_cloud_vec.push_back(source);
338 point_cloud_vec.push_back(target);
340 double scale_global, scale_start;
341 std::vector<Eigen::Vector3d> pcd_mean_vec;
342 std::tie(pcd_mean_vec, scale_global, scale_start) =
345 std::vector<std::pair<int, int>> corres;
348 if (source.
size() >= target.
size()) {
356 for (
auto& p : corres)
std::swap(p.first, p.second);
362 Eigen::Matrix4d transformation;
364 scale_global, option);
A 3D cloud and its associated features (color, normals, scalar fields, etc.)
virtual ccPointCloud & Transform(const Eigen::Matrix4d &trans) override
Apply transformation (4x4 matrix) to the geometry coordinates.
unsigned size() const override
Eigen::Vector3d getEigenPoint(size_t index) const
KDTree with FLANN for nearest neighbor search.
int SearchKNN(const T &query, int knn, std::vector< int > &indices, std::vector< double > &distance2) const
Options for FastGlobalRegistration.
int maximum_tuple_count_
Maximum number of tuples..
int iteration_number_
Maximum number of iterations.
double tuple_scale_
Similarity measure used for tuples of feature points.
double division_factor_
Division factor used for graduated non-convexity.
double maximum_correspondence_distance_
Class to store featrues for registration.
Eigen::MatrixXd data_
Data buffer storing features.
Helper functions for the ml ops.
Eigen::Matrix4d OptimizePairwiseRegistration(const std::vector< ccPointCloud > &point_cloud_vec, const std::vector< std::pair< int, int >> &corres, double scale_start, const FastGlobalRegistrationOption &option)
Eigen::Matrix4d GetTransformationOriginalScale(const Eigen::Matrix4d &transformation, const std::vector< Eigen::Vector3d > &pcd_mean_vec, const double scale_global)
std::vector< Eigen::Vector2i > CorrespondenceSet
RegistrationResult FastGlobalRegistrationBasedOnFeatureMatching(const ccPointCloud &source, const ccPointCloud &target, const utility::Feature &source_feature, const utility::Feature &target_feature, const FastGlobalRegistrationOption &option)
Fast Global Registration based on a given set of FPFH features.
static std::vector< std::pair< int, int > > AdvancedMatching(const ccPointCloud &src_point_cloud, const ccPointCloud &dst_point_cloud, const std::vector< std::pair< int, int >> &corres_cross, const FastGlobalRegistrationOption &option)
std::tuple< std::vector< Eigen::Vector3d >, double, double > NormalizePointCloud(std::vector< ccPointCloud > &point_cloud_vec, const FastGlobalRegistrationOption &option)
static std::vector< std::pair< int, int > > InitialMatching(const utility::Feature &src_features, const utility::Feature &dst_features)
RegistrationResult FastGlobalRegistrationBasedOnCorrespondence(const ccPointCloud &source, const ccPointCloud &target, const CorrespondenceSet &corres, const FastGlobalRegistrationOption &option)
Fast Global Registration based on a given set of correspondences.
RegistrationResult EvaluateRegistration(const ccPointCloud &source, const ccPointCloud &target, double max_correspondence_distance, const Eigen::Matrix4d &transformation)
Function for evaluating registration between point clouds.
std::tuple< bool, Eigen::VectorXd > SolveLinearSystemPSD(const Eigen::MatrixXd &A, const Eigen::VectorXd &b, bool prefer_sparse=false, bool check_symmetric=false, bool check_det=false, bool check_psd=false)
Function to solve Ax=b.
Eigen::Matrix4d TransformVector6dToMatrix4d(const Eigen::Vector6d &input)
Generic file read and write utility for python interface.
void swap(cloudViewer::core::SmallVectorImpl< T > &LHS, cloudViewer::core::SmallVectorImpl< T > &RHS)
Implement std::swap in terms of SmallVector swap.