forked from koide3/ndt_omp
-
Notifications
You must be signed in to change notification settings - Fork 36
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: score based covariance estimation (#45)
* Added score_array Signed-off-by: Shintaro Sakoda <[email protected]> * Added covariance_estimation Signed-off-by: Shintaro Sakoda <[email protected]> * Fixed to shared_ptr Signed-off-by: Shintaro Sakoda <[email protected]> * Added score Signed-off-by: Shintaro Sakoda <[email protected]> * Added default Signed-off-by: Shintaro Sakoda <[email protected]> * Fixed fill and aspect Signed-off-by: Shintaro Sakoda <[email protected]> * Fixed scale Signed-off-by: Shintaro Sakoda <[email protected]> * Fixed struct Signed-off-by: Shintaro Sakoda <[email protected]> * Fixed color Signed-off-by: Shintaro Sakoda <[email protected]> * Applied formatter Signed-off-by: Shintaro Sakoda <[email protected]> * Added calculate_weighted_mean_and_cov Signed-off-by: Shintaro Sakoda <[email protected]> * Applied formatter Signed-off-by: Shintaro Sakoda <[email protected]> * Refactored score Signed-off-by: Shintaro Sakoda <[email protected]> * Fixed temperature Signed-off-by: Shintaro Sakoda <[email protected]> * Added temperature arg Signed-off-by: Shintaro Sakoda <[email protected]> * Fixed signature Signed-off-by: Shintaro Sakoda <[email protected]> * Added time Signed-off-by: Shintaro Sakoda <[email protected]> * Fixed to use propose_search_points Signed-off-by: Shintaro Sakoda <[email protected]> * Fixed plot Signed-off-by: Shintaro Sakoda <[email protected]> * Fixed plot Signed-off-by: Shintaro Sakoda <[email protected]> * Renamed function Signed-off-by: Shintaro Sakoda <[email protected]> * Added make_flat_pcd.py Signed-off-by: Shintaro Sakoda <[email protected]> * Added awsim_nishishinjuku_flat Signed-off-by: Shintaro Sakoda <[email protected]> * Organized codes Signed-off-by: Shintaro Sakoda <[email protected]> * Fixed return type Signed-off-by: Shintaro Sakoda <[email protected]> * Fixed result Signed-off-by: Shintaro Sakoda <[email protected]> * Fixed calc unbiased covariance Signed-off-by: Shintaro Sakoda <[email protected]> * Refactored Signed-off-by: Shintaro Sakoda <[email protected]> * Fixed bug Signed-off-by: Shintaro Sakoda <[email protected]> * Fixed args Signed-off-by: Shintaro Sakoda <[email protected]> * Fixed propose_poses_to_search Signed-off-by: Shintaro Sakoda <[email protected]> * Removed output_pose_score_weight Signed-off-by: Shintaro Sakoda <[email protected]> * Refactored Signed-off-by: Shintaro Sakoda <[email protected]> * Fixed execute script Signed-off-by: Shintaro Sakoda <[email protected]> * Fixed plot script Signed-off-by: Shintaro Sakoda <[email protected]> * Fixed plot script Signed-off-by: Shintaro Sakoda <[email protected]> * Fixed plot script Signed-off-by: Shintaro Sakoda <[email protected]> * Fixed rot Signed-off-by: Shintaro Sakoda <[email protected]> * Fix parameter Signed-off-by: Shintaro Sakoda <[email protected]> * Fixed rot Signed-off-by: Shintaro Sakoda <[email protected]> * Fixed to calculate only score Signed-off-by: Shintaro Sakoda <[email protected]> * Fixed plot script Signed-off-by: Shintaro Sakoda <[email protected]> * Fixed check_covariance.cpp Signed-off-by: Shintaro Sakoda <[email protected]> * Removed transform_probability_array and nearest_voxel_transformation_likelihood_array Signed-off-by: Shintaro Sakoda <[email protected]> * Added a line break Signed-off-by: Shintaro Sakoda <[email protected]> * Removed make_flat_pcd.py Signed-off-by: Shintaro Sakoda <[email protected]> * Fixed output csv Signed-off-by: Shintaro Sakoda <[email protected]> * Added rotate_covariance_to_base_link Signed-off-by: Shintaro Sakoda <[email protected]> * Fixed rotation Signed-off-by: Shintaro Sakoda <[email protected]> * Fixed execute_script Signed-off-by: Shintaro Sakoda <[email protected]> * Fixed regression_test.yml Signed-off-by: Shintaro Sakoda <[email protected]> * Fixed script name Signed-off-by: Shintaro Sakoda <[email protected]> * Added tqdm Signed-off-by: Shintaro Sakoda <[email protected]> * Added adjust_diagonal_covariance Signed-off-by: Shintaro Sakoda <[email protected]> --------- Signed-off-by: Shintaro Sakoda <[email protected]> Signed-off-by: Shintaro Sakoda <[email protected]>
- Loading branch information
1 parent
609d9f6
commit c803c10
Showing
8 changed files
with
655 additions
and
5 deletions.
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,174 @@ | ||
#include <iostream> | ||
#include <chrono> | ||
#include <pcl/io/pcd_io.h> | ||
#include <pcl/point_types.h> | ||
#include <pcl/point_cloud.h> | ||
#include <pcl/registration/ndt.h> | ||
#include <pcl/registration/gicp.h> | ||
#include <pcl/filters/voxel_grid.h> | ||
#include <pcl/visualization/pcl_visualizer.h> | ||
#include <omp.h> | ||
#include <glob.h> | ||
#include <filesystem> | ||
|
||
#include <pclomp/gicp_omp.h> | ||
#include <multigrid_pclomp/multigrid_ndt_omp.h> | ||
#include "estimate_covariance/estimate_covariance.hpp" | ||
|
||
#include "util.hpp" | ||
|
||
int main(int argc, char** argv) { | ||
if(argc != 3) { | ||
std::cout << "usage: ./regression_test <input_dir> <output_dir>" << std::endl; | ||
return 0; | ||
} | ||
|
||
const std::string input_dir = argv[1]; | ||
const std::string output_dir = argv[2]; | ||
|
||
// load target pcd | ||
const std::string target_pcd = input_dir + "/pointcloud_map.pcd"; | ||
const pcl::PointCloud<pcl::PointXYZ>::Ptr target_cloud = load_pcd(target_pcd); | ||
|
||
// prepare sensor_pcd | ||
const std::string source_pcd_dir = input_dir + "/sensor_pcd/"; | ||
const std::vector<std::string> source_pcd_list = glob(source_pcd_dir); | ||
|
||
// load kinematic_state.csv | ||
const std::vector<Eigen::Matrix4f> initial_pose_list = load_pose_list(input_dir + "/kinematic_state.csv"); | ||
|
||
if(initial_pose_list.size() != source_pcd_list.size()) { | ||
std::cerr << "initial_pose_list.size() != source_pcd_list.size()" << std::endl; | ||
return 1; | ||
} | ||
const int64_t n_data = initial_pose_list.size(); | ||
|
||
// prepare ndt | ||
std::shared_ptr<pclomp::MultiGridNormalDistributionsTransform<pcl::PointXYZ, pcl::PointXYZ>> mg_ndt_omp(new pclomp::MultiGridNormalDistributionsTransform<pcl::PointXYZ, pcl::PointXYZ>()); | ||
mg_ndt_omp->setInputTarget(target_cloud); | ||
mg_ndt_omp->setResolution(2.0); | ||
mg_ndt_omp->setNumThreads(4); | ||
mg_ndt_omp->setMaximumIterations(30); | ||
mg_ndt_omp->setTransformationEpsilon(0.01); | ||
mg_ndt_omp->setStepSize(0.1); | ||
mg_ndt_omp->createVoxelKdtree(); | ||
|
||
std::cout << std::fixed; | ||
|
||
const std::vector<double> offset_x = {0.0, 0.0, 0.5, -0.5, 1.0, -1.0, 0.0, 0.0, 2.0, -2.0}; | ||
const std::vector<double> offset_y = {0.5, -0.5, 0.0, 0.0, 0.0, 0.0, 1.0, -1.0, 0.0, 0.0}; | ||
|
||
// output result | ||
std::filesystem::create_directories(output_dir); | ||
std::ofstream ofs(output_dir + "/result.csv"); | ||
ofs << std::fixed; | ||
ofs << "index,score,"; | ||
ofs << "initial_x,initial_y,initial_yaw,"; | ||
ofs << "result_x,result_y,result_yaw,"; | ||
ofs << "elapsed_la,cov_by_la_00,cov_by_la_01,cov_by_la_10,cov_by_la_11,"; | ||
ofs << "elapsed_mndt,cov_by_mndt_00,cov_by_mndt_01,cov_by_mndt_10,cov_by_mndt_11,"; | ||
ofs << "elapsed_mndt_score,cov_by_mndt_score_00,cov_by_mndt_score_01,cov_by_mndt_score_10,cov_by_mndt_score_11,"; | ||
ofs << "cov_by_la_rotated_00,cov_by_la_rotated_01,cov_by_la_rotated_10,cov_by_la_rotated_11,"; | ||
ofs << "cov_by_mndt_rotated_00,cov_by_mndt_rotated_01,cov_by_mndt_rotated_10,cov_by_mndt_rotated_11,"; | ||
ofs << "cov_by_mndt_score_rotated_00,cov_by_mndt_score_rotated_01,cov_by_mndt_score_rotated_10,cov_by_mndt_score_rotated_11" << std::endl; | ||
|
||
const std::string multi_ndt_dir = output_dir + "/multi_ndt"; | ||
std::filesystem::create_directories(multi_ndt_dir); | ||
const std::string multi_ndt_score_dir = output_dir + "/multi_ndt_score"; | ||
std::filesystem::create_directories(multi_ndt_score_dir); | ||
|
||
auto t1 = std::chrono::system_clock::now(); | ||
auto t2 = std::chrono::system_clock::now(); | ||
|
||
// execute align | ||
for(int64_t i = 0; i < n_data; i++) { | ||
const Eigen::Matrix4f initial_pose = initial_pose_list[i]; | ||
const std::string& source_pcd = source_pcd_list[i]; | ||
pcl::PointCloud<pcl::PointXYZ>::Ptr source_cloud(new pcl::PointCloud<pcl::PointXYZ>()); | ||
if(pcl::io::loadPCDFile(source_pcd, *source_cloud)) { | ||
std::cerr << "failed to load " << source_pcd << std::endl; | ||
return 1; | ||
} | ||
mg_ndt_omp->setInputSource(source_cloud); | ||
pcl::PointCloud<pcl::PointXYZ>::Ptr aligned(new pcl::PointCloud<pcl::PointXYZ>()); | ||
mg_ndt_omp->align(*aligned, initial_pose); | ||
const pclomp::NdtResult ndt_result = mg_ndt_omp->getResult(); | ||
const double score = ndt_result.nearest_voxel_transformation_likelihood; | ||
std::cout << source_pcd << ", num=" << std::setw(4) << source_cloud->size() << " points, score=" << score << std::endl; | ||
|
||
const std::vector<Eigen::Matrix4f> poses_to_search = pclomp::propose_poses_to_search(ndt_result, offset_x, offset_y); | ||
|
||
// estimate covariance | ||
// (1) Laplace approximation | ||
t1 = std::chrono::system_clock::now(); | ||
const Eigen::Matrix2d cov_by_la = pclomp::estimate_xy_covariance_by_Laplace_approximation(ndt_result.hessian); | ||
t2 = std::chrono::system_clock::now(); | ||
const auto elapsed_la = std::chrono::duration_cast<std::chrono::microseconds>(t2 - t1).count() / 1000.0; | ||
|
||
// (2) Multi NDT | ||
t1 = std::chrono::system_clock::now(); | ||
const pclomp::ResultOfMultiNdtCovarianceEstimation result_of_mndt = pclomp::estimate_xy_covariance_by_multi_ndt(ndt_result, mg_ndt_omp, poses_to_search); | ||
const Eigen::Matrix2d cov_by_mndt = pclomp::adjust_diagonal_covariance(result_of_mndt.covariance, ndt_result.pose, 0.0225, 0.0225); | ||
t2 = std::chrono::system_clock::now(); | ||
const auto elapsed_mndt = std::chrono::duration_cast<std::chrono::microseconds>(t2 - t1).count() / 1000.0; | ||
|
||
// (3) Multi NDT with score | ||
const double temperature = 0.1; | ||
t1 = std::chrono::system_clock::now(); | ||
const pclomp::ResultOfMultiNdtCovarianceEstimation result_of_mndt_score = pclomp::estimate_xy_covariance_by_multi_ndt_score(ndt_result, mg_ndt_omp, poses_to_search, temperature); | ||
const Eigen::Matrix2d cov_by_mndt_score = pclomp::adjust_diagonal_covariance(result_of_mndt_score.covariance, ndt_result.pose, 0.0225, 0.0225); | ||
t2 = std::chrono::system_clock::now(); | ||
const auto elapsed_mndt_score = std::chrono::duration_cast<std::chrono::microseconds>(t2 - t1).count() / 1000.0; | ||
|
||
// output result | ||
const auto result_x = ndt_result.pose(0, 3); | ||
const auto result_y = ndt_result.pose(1, 3); | ||
const Eigen::Vector3f euler_initial = initial_pose.block<3, 3>(0, 0).eulerAngles(0, 1, 2); | ||
const Eigen::Vector3f euler_result = ndt_result.pose.block<3, 3>(0, 0).eulerAngles(0, 1, 2); | ||
const Eigen::Matrix2d cov_by_la_rotated = pclomp::rotate_covariance_to_base_link(cov_by_la, ndt_result.pose); | ||
const Eigen::Matrix2d cov_by_mndt_rotated = pclomp::rotate_covariance_to_base_link(cov_by_mndt, ndt_result.pose); | ||
const Eigen::Matrix2d cov_by_mndt_score_rotated = pclomp::rotate_covariance_to_base_link(cov_by_mndt_score, ndt_result.pose); | ||
ofs << i << "," << score << ","; | ||
ofs << initial_pose(0, 3) << "," << initial_pose(1, 3) << "," << euler_initial(2) << ","; | ||
ofs << result_x << "," << result_y << "," << euler_result(2) << ","; | ||
ofs << elapsed_la << "," << cov_by_la(0, 0) << "," << cov_by_la(0, 1) << "," << cov_by_la(1, 0) << "," << cov_by_la(1, 1) << ","; | ||
ofs << elapsed_mndt << "," << cov_by_mndt(0, 0) << "," << cov_by_mndt(0, 1) << "," << cov_by_mndt(1, 0) << "," << cov_by_mndt(1, 1) << ","; | ||
ofs << elapsed_mndt_score << "," << cov_by_mndt_score(0, 0) << "," << cov_by_mndt_score(0, 1) << "," << cov_by_mndt_score(1, 0) << "," << cov_by_mndt_score(1, 1) << ","; | ||
ofs << cov_by_la_rotated(0, 0) << "," << cov_by_la_rotated(0, 1) << "," << cov_by_la_rotated(1, 0) << "," << cov_by_la_rotated(1, 1) << ","; | ||
ofs << cov_by_mndt_rotated(0, 0) << "," << cov_by_mndt_rotated(0, 1) << "," << cov_by_mndt_rotated(1, 0) << "," << cov_by_mndt_rotated(1, 1) << ","; | ||
ofs << cov_by_mndt_score_rotated(0, 0) << "," << cov_by_mndt_score_rotated(0, 1) << "," << cov_by_mndt_score_rotated(1, 0) << "," << cov_by_mndt_score_rotated(1, 1) << std::endl; | ||
|
||
std::stringstream filename_ss; | ||
filename_ss << std::setw(8) << std::setfill('0') << i << ".csv"; | ||
|
||
// output multi ndt result | ||
std::ofstream ofs_mndt(multi_ndt_dir + "/" + filename_ss.str()); | ||
const int n_mndt = result_of_mndt.ndt_results.size(); | ||
ofs_mndt << "index,score,initial_x,initial_y,result_x,result_y" << std::endl; | ||
ofs_mndt << std::fixed; | ||
for(int j = 0; j < n_mndt; j++) { | ||
const pclomp::NdtResult& ndt_result = result_of_mndt.ndt_results[j]; | ||
const auto nvtl = ndt_result.nearest_voxel_transformation_likelihood; | ||
const auto initial_x = result_of_mndt.ndt_initial_poses[j](0, 3); | ||
const auto initial_y = result_of_mndt.ndt_initial_poses[j](1, 3); | ||
const auto result_x = ndt_result.pose(0, 3); | ||
const auto result_y = ndt_result.pose(1, 3); | ||
ofs_mndt << j << "," << nvtl << "," << initial_x << "," << initial_y << "," << result_x << "," << result_y << std::endl; | ||
} | ||
|
||
// output multi ndt score result | ||
std::ofstream ofs_mndt_score(multi_ndt_score_dir + "/" + filename_ss.str()); | ||
const int n_mndt_score = result_of_mndt_score.ndt_results.size(); | ||
ofs_mndt_score << "index,score,initial_x,initial_y,result_x,result_y" << std::endl; | ||
ofs_mndt_score << std::fixed; | ||
for(int j = 0; j < n_mndt_score; j++) { | ||
const pclomp::NdtResult& ndt_result = result_of_mndt_score.ndt_results[j]; | ||
const auto nvtl = ndt_result.nearest_voxel_transformation_likelihood; | ||
const auto initial_x = result_of_mndt_score.ndt_initial_poses[j](0, 3); | ||
const auto initial_y = result_of_mndt_score.ndt_initial_poses[j](1, 3); | ||
const auto result_x = ndt_result.pose(0, 3); | ||
const auto result_y = ndt_result.pose(1, 3); | ||
ofs_mndt_score << j << "," << nvtl << "," << initial_x << "," << initial_y << "," << result_x << "," << result_y << std::endl; | ||
} | ||
} | ||
} |
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,52 @@ | ||
#ifndef NDT_OMP__ESTIMATE_COVARIANCE_HPP_ | ||
#define NDT_OMP__ESTIMATE_COVARIANCE_HPP_ | ||
|
||
#include <Eigen/Core> | ||
#include "multigrid_pclomp/multigrid_ndt_omp.h" | ||
|
||
namespace pclomp { | ||
|
||
struct ResultOfMultiNdtCovarianceEstimation { | ||
Eigen::Vector2d mean; | ||
Eigen::Matrix2d covariance; | ||
std::vector<Eigen::Matrix4f> ndt_initial_poses; | ||
std::vector<NdtResult> ndt_results; | ||
}; | ||
|
||
/** \brief Estimate functions */ | ||
Eigen::Matrix2d estimate_xy_covariance_by_Laplace_approximation(const Eigen::Matrix<double, 6, 6>& hessian); | ||
ResultOfMultiNdtCovarianceEstimation estimate_xy_covariance_by_multi_ndt(const NdtResult& ndt_result, std::shared_ptr<pclomp::MultiGridNormalDistributionsTransform<pcl::PointXYZ, pcl::PointXYZ>> ndt_ptr, const std::vector<Eigen::Matrix4f>& poses_to_search); | ||
ResultOfMultiNdtCovarianceEstimation estimate_xy_covariance_by_multi_ndt_score(const NdtResult& ndt_result, std::shared_ptr<pclomp::MultiGridNormalDistributionsTransform<pcl::PointXYZ, pcl::PointXYZ>> ndt_ptr, const std::vector<Eigen::Matrix4f>& poses_to_search, const double temperature); | ||
|
||
/** \brief Find rotation matrix aligning covariance to principal axes | ||
* (1) Compute eigenvalues and eigenvectors | ||
* (2) Compute angle for first eigenvector | ||
* (3) Return rotation matrix | ||
*/ | ||
Eigen::Matrix2d find_rotation_matrix_aligning_covariance_to_principal_axes(const Eigen::Matrix2d& matrix); | ||
|
||
/** \brief Propose poses to search. | ||
* (1) Compute covariance by Laplace approximation | ||
* (2) Find rotation matrix aligning covariance to principal axes | ||
* (3) Propose search points by adding offset_x and offset_y to the center_pose | ||
*/ | ||
std::vector<Eigen::Matrix4f> propose_poses_to_search(const NdtResult& ndt_result, const std::vector<double>& offset_x, const std::vector<double>& offset_y); | ||
|
||
/** \brief Calculate weights by exponential */ | ||
std::vector<double> calc_weight_vec(const std::vector<double>& score_vec, double temperature); | ||
|
||
/** \brief Calculate weighted mean and covariance */ | ||
std::pair<Eigen::Vector2d, Eigen::Matrix2d> calculate_weighted_mean_and_cov(const std::vector<Eigen::Vector2d>& pose_2d_vec, const std::vector<double>& weight_vec); | ||
|
||
/** \brief Rotate covariance to base_link coordinate */ | ||
Eigen::Matrix2d rotate_covariance_to_base_link(const Eigen::Matrix2d& covariance, const Eigen::Matrix4f& pose); | ||
|
||
/** \brief Rotate covariance to map coordinate */ | ||
Eigen::Matrix2d rotate_covariance_to_map(const Eigen::Matrix2d& covariance, const Eigen::Matrix4f& pose); | ||
|
||
/** \brief Adjust diagonal covariance */ | ||
Eigen::Matrix2d adjust_diagonal_covariance(const Eigen::Matrix2d& covariance, const Eigen::Matrix4f& pose, const double fixed_cov00, const double fixed_cov11); | ||
|
||
} // namespace pclomp | ||
|
||
#endif // NDT_OMP__ESTIMATE_COVARIANCE_HPP_ |
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,13 @@ | ||
#!/bin/bash | ||
set -eux | ||
|
||
INPUT_DIR=$(readlink -f $1) | ||
OUTPUT_DIR=$(readlink -f $2) | ||
|
||
cd $(dirname $0)/../build | ||
|
||
make -j8 | ||
|
||
rm -rf ${OUTPUT_DIR} | ||
./check_covariance ${INPUT_DIR} ${OUTPUT_DIR} | ||
python3 ../script/plot_covariance.py ${OUTPUT_DIR}/result.csv |
Oops, something went wrong.