Skip to content
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

Improve symmetric ICP #126

Merged
merged 1 commit into from
Dec 10, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 48 additions & 12 deletions src/cupoch/registration/transformation_estimation.cu
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,9 @@ struct pt2pl_jacobian_residual_functor
}
};

struct pl2pl_jacobian_residual_functor
struct symmetric_jacobian_residual_functor
: public utility::jacobian_residual_functor<Eigen::Vector6f> {
pl2pl_jacobian_residual_functor(const Eigen::Vector3f *source,
symmetric_jacobian_residual_functor(const Eigen::Vector3f *source,
const Eigen::Vector3f *source_normals,
const Eigen::Vector3f *target_points,
const Eigen::Vector3f *target_normals,
Expand Down Expand Up @@ -95,10 +95,13 @@ __device__ float ComputeErrorUsingNormals(
const Eigen::Vector3f &source_normal,
const Eigen::Vector3f &target_point,
const Eigen::Vector3f &target_normal) {
// Implement the error calculation logic here
// This is just a placeholder logic
return (source_point - target_point).dot(target_normal) +
(source_point - target_point).dot(source_normal);
// Symmetric treatment of normals
Eigen::Vector3f combined_normal = source_normal + target_normal;

// Compute the symmetric point-to-plane error
float error = (source_point - target_point).dot(combined_normal);

return error * error; // Return squared error for consistency
}

} // namespace
Expand Down Expand Up @@ -287,28 +290,61 @@ Eigen::Matrix4f TransformationEstimationSymmetricMethod::ComputeTransformation(
const geometry::PointCloud &source,
const geometry::PointCloud &target,
const CorrespondenceSet &corres) const {
if (corres.empty() || !target.HasNormals())
if (corres.empty() || !source.HasNormals() || !target.HasNormals())
return Eigen::Matrix4f::Identity();

Eigen::Matrix6f JTJ;
Eigen::Vector6f JTr;
float r2;
pl2pl_jacobian_residual_functor func(
symmetric_jacobian_residual_functor func(
thrust::raw_pointer_cast(source.points_.data()),
thrust::raw_pointer_cast(source.normals_.data()),
thrust::raw_pointer_cast(target.points_.data()),
thrust::raw_pointer_cast(target.normals_.data()),
thrust::raw_pointer_cast(corres.data()));
thrust::tie(JTJ, JTr, r2) =
utility::ComputeJTJandJTr<Eigen::Matrix6f, Eigen::Vector6f,
pl2pl_jacobian_residual_functor>(
symmetric_jacobian_residual_functor>(
func, (int)corres.size());

bool is_success;
Eigen::Matrix4f extrinsic;
thrust::tie(is_success, extrinsic) =
Eigen::Matrix4f transformation_matrix;
thrust::tie(is_success, transformation_matrix) =
utility::SolveJacobianSystemAndObtainExtrinsicMatrix(JTJ, JTr,
det_thresh_);
if (is_success) {
// Extract the rotation matrix (3x3 upper-left block) from the 4x4
// transformation matrix. This matrix represents the rotation component
// of the transformation.
Eigen::Matrix3f rotation_matrix_3f =
transformation_matrix.template block<3, 3>(0, 0);

return is_success ? extrinsic : Eigen::Matrix4f::Identity();
// Convert the rotation matrix to double precision for higher accuracy.
// This step is essential to maintain accuracy in the subsequent
// squaring operation.
Eigen::Matrix3d rotation_matrix_3d = rotation_matrix_3f.cast<double>();

// Square the rotation matrix as described in the original Symmetric ICP
// paper. This approach, part of the rotated-normals version of the
// symmetric objective, optimizes for half of the rotation angle,
// reducing linearization error and enabling exact correspondences in
// certain cases.
Eigen::Matrix3d R = rotation_matrix_3d * rotation_matrix_3d;

// Construct the final transformation matrix using the squared rotation
// matrix (R) and the translation vector. The translation component is
// extracted directly from the original 4x4 transformation matrix.
Eigen::Matrix4f extrinsic = Eigen::Matrix4f::Identity();
extrinsic.template block<3, 3>(0, 0) =
R.cast<float>(); // Set the rotation part with the squared
// rotation matrix.
extrinsic.template block<3, 1>(0, 3) =
transformation_matrix.template block<3, 1>(
0, 3); // Set the translation part from the original
// transformation matrix.

return extrinsic;
}

return Eigen::Matrix4f::Identity();
}