-
-
Notifications
You must be signed in to change notification settings - Fork 827
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
3D-3D Registration based on PCL #425
Closed
Closed
Changes from all commits
Commits
Show all changes
34 commits
Select commit
Hold shift + click to select a range
89cc834
[registration] rough import of the 3D3D registration code into AV (co…
Debize 30a1578
[registration] rough changes in CmakeList files to make it runnable
Debize 372506e
[registration] input arguments refactoring (alicevision type)
Debize bf6a742
[registration] refactoring of verbose (alicevision type)
Debize b12e975
[registration] implement the 'transformAndSaveCloud()' to export tran…
Debize ea13fac
[registration] add the 'showPipeline' option + renaming
Debize 252323c
[registration] bugfix: solve conflict between scale ratio & measurements
TwokBox 94bcc3b
[registration] manage .OBJ files
TwokBox 61f89ce
[registration] add an option to show the duration of each step
TwokBox 5245506
[registration] moveToOrigin uses centroid instead of center of boundi…
TwokBox 93c4cf9
[registration] transformAndSaveCloud manages .obj files
TwokBox 95d3f8d
[registration] bugfix: fix error with scaleRatio & measurements manag…
TwokBox b1bf7f9
[3dregistration] fix CMakeLists + build
yann-lty 9b4c7a8
[registration] fix crash on windows in moveToOrigin
fabiencastan 794ed30
[registration] add ICP and SICP based on sparceicp implementation
fabiencastan 019af5b
[registration] make point cloud preparation common to all methods
fabiencastan f6024b6
[registration] registration preparation: disable voxel simplification…
fabiencastan d12c826
[registration] minor code clean for scaleRatio
fabiencastan ced0582
[registration] some code fixes
fabiencastan 9305654
[cmake] some find_package changes for flann and pcl
fabiencastan e2158b9
[registration] pcl now uses std::shared_ptr
fabiencastan 1645474
[cmake] rename internal flann target
fabiencastan 8a7f7b6
[cmake] use alicevision_add_library
simogasp c0dbfe4
[registration] fix missing include
simogasp 2c8fd66
[registration] pcl_isfinite deprecated, use std::
simogasp 5fc17a9
[cmake] add flann::flann_cpp as alias
simogasp 1e95f88
[sw] useless include
simogasp 32cfb26
[sw] fix typos
simogasp e257c74
[sw] use LOG_INFO instead of warning
simogasp 36fb42f
[registration] using doxygen comment for members
simogasp 2ad56b7
[registration] use default
simogasp 143e9be
[registration] remove const for primitive params
simogasp 9a2c4e6
[registration] typos
simogasp c53b5e9
[registration] doxygen format for members
simogasp File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
# Headers | ||
set(registration_files_headers | ||
nanoflannKDTreeEigenAdaptor.hpp | ||
rigidMotionEstimator.hpp | ||
directSimilarityEstimator.hpp | ||
ICP.hpp | ||
SICP.hpp | ||
PointcloudRegistration.hpp | ||
) | ||
|
||
# Sources | ||
set(registration_files_sources | ||
PointcloudRegistration.cpp | ||
) | ||
|
||
alicevision_add_library(aliceVision_registration | ||
SOURCES ${registration_files_headers} ${registration_files_sources} | ||
PUBLIC_LINKS | ||
Boost::filesystem | ||
${PCL_LIBRARIES} | ||
nanoflann | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,215 @@ | ||
// This file is part of the AliceVision project. | ||
// Copyright (c) 2018 AliceVision contributors. | ||
// Copyright (C) 2013 LGG, EPFL | ||
// "Sparse Iterative Closest Point" by Sofien Bouaziz, Andrea Tagliasacchi, Mark Pauly | ||
// This Source Code Form is subject to the terms of the Mozilla Public License, | ||
// v. 2.0. If a copy of the MPL was not distributed with this file, | ||
// You can obtain one at https://mozilla.org/MPL/2.0/. | ||
#pragma once | ||
|
||
#include <Eigen/Dense> | ||
|
||
#include "nanoflannKDTreeEigenAdaptor.hpp" | ||
#include "rigidMotionEstimator.hpp" | ||
#include "directSimilarityEstimator.hpp" | ||
|
||
|
||
namespace aliceVision { | ||
namespace registration { | ||
|
||
/// ICP implementation using iterative reweighting | ||
namespace ICP { | ||
|
||
enum Function { | ||
PNORM, | ||
TUKEY, | ||
FAIR, | ||
LOGISTIC, | ||
TRIMMED, | ||
NONE | ||
}; | ||
struct Parameters { | ||
Function f = NONE; /// robust function type | ||
double p = 1.0; // 0.1; /// paramter of the robust function | ||
int max_icp = 100; /// max ICP iteration | ||
int max_outer = 100; /// max outer iteration | ||
double stop = 1e-5; /// stopping criteria | ||
bool useDirectSimilarity = false; /// use direct similarity instead of rigid motion | ||
}; | ||
/// Weight functions | ||
/// @param Residuals | ||
/// @param Parameter | ||
void uniform_weight(Eigen::VectorXd& r) { | ||
r = Eigen::VectorXd::Ones(r.rows()); | ||
} | ||
/// @param Residuals | ||
/// @param Parameter | ||
void pnorm_weight(Eigen::VectorXd& r, double p, double reg=1e-8) { | ||
for(int i=0; i<r.rows(); ++i) { | ||
r(i) = p/(std::pow(r(i),2-p) + reg); | ||
} | ||
} | ||
/// @param Residuals | ||
/// @param Parameter | ||
void tukey_weight(Eigen::VectorXd& r, double p) { | ||
for(int i=0; i<r.rows(); ++i) { | ||
if(r(i) > p) r(i) = 0.0; | ||
else r(i) = std::pow((1.0 - std::pow(r(i)/p,2.0)), 2.0); | ||
} | ||
} | ||
/// @param Residuals | ||
/// @param Parameter | ||
void fair_weight(Eigen::VectorXd& r, double p) { | ||
for(int i=0; i<r.rows(); ++i) { | ||
r(i) = 1.0/(1.0 + r(i)/p); | ||
} | ||
} | ||
/// @param Residuals | ||
/// @param Parameter | ||
void logistic_weight(Eigen::VectorXd& r, double p) { | ||
for(int i=0; i<r.rows(); ++i) { | ||
r(i) = (p/r(i))*std::tanh(r(i)/p); | ||
} | ||
} | ||
struct sort_pred { | ||
bool operator()(const std::pair<int,double> &left, | ||
const std::pair<int,double> &right) { | ||
return left.second < right.second; | ||
} | ||
}; | ||
/// @param Residuals | ||
/// @param Parameter | ||
void trimmed_weight(Eigen::VectorXd& r, double p) { | ||
std::vector<std::pair<int, double> > sortedDist(r.rows()); | ||
for(int i=0; i<r.rows(); ++i) { | ||
sortedDist[i] = std::pair<int, double>(i,r(i)); | ||
} | ||
std::sort(sortedDist.begin(), sortedDist.end(), sort_pred()); | ||
r.setZero(); | ||
int nbV = r.rows()*p; | ||
for(int i=0; i<nbV; ++i) { | ||
r(sortedDist[i].first) = 1.0; | ||
} | ||
} | ||
/// @param Function type | ||
/// @param Residuals | ||
/// @param Parameter | ||
void robust_weight(Function f, Eigen::VectorXd& r, double p) { | ||
switch(f) { | ||
case PNORM: pnorm_weight(r,p); break; | ||
case TUKEY: tukey_weight(r,p); break; | ||
case FAIR: fair_weight(r,p); break; | ||
case LOGISTIC: logistic_weight(r,p); break; | ||
case TRIMMED: trimmed_weight(r,p); break; | ||
case NONE: uniform_weight(r); break; | ||
default: uniform_weight(r); break; | ||
} | ||
} | ||
/// Reweighted ICP with point to point | ||
/// @param Source (one 3D point per column) | ||
/// @param Target (one 3D point per column) | ||
/// @param Parameters | ||
Eigen::Affine3d point_to_point(Eigen::Matrix3Xd& X, | ||
Eigen::Matrix3Xd& Y, | ||
Parameters par = Parameters()) { | ||
/// Build kd-tree | ||
nanoflann::KDTreeAdaptor<Eigen::Matrix3Xd, 3, nanoflann::metric_L2_Simple> kdtree(Y); | ||
/// Buffers | ||
Eigen::Matrix3Xd Q = Eigen::Matrix3Xd::Zero(3, X.cols()); | ||
Eigen::VectorXd W = Eigen::VectorXd::Zero(X.cols()); | ||
Eigen::Matrix3Xd Xo1 = X; | ||
Eigen::Matrix3Xd Xo2 = X; | ||
Eigen::Affine3d finalTransform = Eigen::Affine3d::Identity(); | ||
/// ICP | ||
for(int icp=0; icp<par.max_icp; ++icp) { | ||
/// Find closest point | ||
#pragma omp parallel for | ||
for(int i=0; i<X.cols(); ++i) { | ||
Q.col(i) = Y.col(kdtree.closest(X.col(i).data())); | ||
} | ||
/// Computer rotation and translation | ||
for(int outer=0; outer<par.max_outer; ++outer) { | ||
/// Compute weights | ||
W = (X-Q).colwise().norm(); | ||
robust_weight(par.f, W, par.p); | ||
/// Rotation and translation update | ||
Eigen::Affine3d transform; | ||
if(par.useDirectSimilarity) | ||
transform = directSimilarityEstimator::point_to_point(X, Q, W); | ||
else | ||
transform = rigidMotionEstimator::point_to_point(X, Q, W); | ||
std::cout << "Intermediate transform:\n" << transform.matrix() << std::endl; | ||
finalTransform = transform * finalTransform; | ||
/// Stopping criteria | ||
double stop1 = (X-Xo1).colwise().norm().maxCoeff(); | ||
Xo1 = X; | ||
if(stop1 < par.stop) | ||
{ | ||
std::cout << "stop1 < par.stop:\n" << stop1 << ", " << par.stop << std::endl; | ||
break; | ||
} | ||
} | ||
/// Stopping criteria | ||
double stop2 = (X-Xo2).colwise().norm().maxCoeff(); | ||
Xo2 = X; | ||
if(stop2 < par.stop) | ||
{ | ||
std::cout << "stop2 < par.stop:\n" << stop2 << ", " << par.stop << std::endl; | ||
std::cout << "icp iteration:\n" << icp << std::endl; | ||
break; | ||
} | ||
} | ||
return finalTransform; | ||
} | ||
/// Reweighted ICP with point to plane | ||
/// @param Source (one 3D point per column) | ||
/// @param Target (one 3D point per column) | ||
/// @param Target normals (one 3D normal per column) | ||
/// @param Parameters | ||
template <typename Derived1, typename Derived2, typename Derived3> | ||
Eigen::Affine3d point_to_plane(Eigen::MatrixBase<Derived1>& X, | ||
Eigen::MatrixBase<Derived2>& Y, | ||
Eigen::MatrixBase<Derived3>& N, | ||
Parameters par = Parameters()) { | ||
/// Build kd-tree | ||
nanoflann::KDTreeAdaptor<Eigen::MatrixBase<Derived2>, 3, nanoflann::metric_L2_Simple> kdtree(Y); | ||
/// Buffers | ||
Eigen::Matrix3Xd Qp = Eigen::Matrix3Xd::Zero(3, X.cols()); | ||
Eigen::Matrix3Xd Qn = Eigen::Matrix3Xd::Zero(3, X.cols()); | ||
Eigen::VectorXd W = Eigen::VectorXd::Zero(X.cols()); | ||
Eigen::Matrix3Xd Xo1 = X; | ||
Eigen::Matrix3Xd Xo2 = X; | ||
Eigen::Affine3d finalTransform = Eigen::Affine3d::Identity(); | ||
/// ICP | ||
for(int icp=0; icp<par.max_icp; ++icp) { | ||
/// Find closest point | ||
#pragma omp parallel for | ||
for(int i=0; i<X.cols(); ++i) { | ||
int id = kdtree.closest(X.col(i).data()); | ||
Qp.col(i) = Y.col(id); | ||
Qn.col(i) = N.col(id); | ||
} | ||
/// Computer rotation and translation | ||
for(int outer=0; outer<par.max_outer; ++outer) { | ||
/// Compute weights | ||
W = (Qn.array()*(X-Qp).array()).colwise().sum().abs().transpose(); | ||
robust_weight(par.f, W, par.p); | ||
/// Rotation and translation update | ||
Eigen::Affine3d transform = rigidMotionEstimator::point_to_plane(X, Qp, Qn, W); | ||
finalTransform = transform * finalTransform; | ||
/// Stopping criteria | ||
double stop1 = (X-Xo1).colwise().norm().maxCoeff(); | ||
Xo1 = X; | ||
if(stop1 < par.stop) break; | ||
} | ||
/// Stopping criteria | ||
double stop2 = (X-Xo2).colwise().norm().maxCoeff() ; | ||
Xo2 = X; | ||
if(stop2 < par.stop) break; | ||
} | ||
return finalTransform; | ||
} | ||
|
||
} | ||
} | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FLANN_INCLUDE_DIR_HINTS
is now set afterfind_package
.In order to find the internal one we should add another
find_package
after this line.