Skip to content

Commit 67b735e

Browse files
committed
Improves symmetric ICP registration stability
Refactors Jacobian calculation for clarity and efficiency. Adds checks for valid correspondences to prevent errors when no valid pairs are available.
1 parent c45b03a commit 67b735e

File tree

2 files changed

+46
-50
lines changed

2 files changed

+46
-50
lines changed

cpp/open3d/t/pipelines/kernel/RegistrationCPU.cpp

Lines changed: 29 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -149,58 +149,37 @@ static void ComputePoseSymmetricKernelCPU(const scalar_t *source_points_ptr,
149149
#pragma omp parallel for reduction(+ : A_reduction[:29]) schedule(static) num_threads(utility::EstimateMaxThreads())
150150
for (int workload_idx = 0; workload_idx < n; ++workload_idx) {
151151
#endif
152-
if (correspondence_indices[workload_idx] == -1) continue;
153-
int target_idx = 3 * correspondence_indices[workload_idx];
154-
int source_idx = 3 * workload_idx;
155-
156-
scalar_t sx = source_points_ptr[source_idx];
157-
scalar_t sy = source_points_ptr[source_idx + 1];
158-
scalar_t sz = source_points_ptr[source_idx + 2];
159-
scalar_t tx = target_points_ptr[target_idx];
160-
scalar_t ty = target_points_ptr[target_idx + 1];
161-
scalar_t tz = target_points_ptr[target_idx + 2];
162-
scalar_t nsx = source_normals_ptr[source_idx];
163-
scalar_t nsy = source_normals_ptr[source_idx + 1];
164-
scalar_t nsz = source_normals_ptr[source_idx + 2];
165-
scalar_t ntx = target_normals_ptr[target_idx];
166-
scalar_t nty = target_normals_ptr[target_idx + 1];
167-
scalar_t ntz = target_normals_ptr[target_idx + 2];
168-
169-
scalar_t dx = sx - tx;
170-
scalar_t dy = sy - ty;
171-
scalar_t dz = sz - tz;
172-
173-
scalar_t r1 = dx * ntx + dy * nty + dz * ntz;
174-
scalar_t r2 = dx * nsx + dy * nsy + dz * nsz;
175-
176-
scalar_t J1[6] = {-sz * nty + sy * ntz,
177-
sz * ntx - sx * ntz,
178-
-sy * ntx + sx * nty,
179-
ntx,
180-
nty,
181-
ntz};
182-
scalar_t J2[6] = {-sz * nsy + sy * nsz,
183-
sz * nsx - sx * nsz,
184-
-sy * nsx + sx * nsy,
185-
nsx,
186-
nsy,
187-
nsz};
188-
189-
scalar_t w1 = GetWeightFromRobustKernel(r1);
190-
scalar_t w2 = GetWeightFromRobustKernel(r2);
191-
192-
int i = 0;
193-
for (int j = 0; j < 6; ++j) {
194-
for (int k = 0; k <= j; ++k) {
195-
A_reduction[i] +=
196-
J1[j] * w1 * J1[k] + J2[j] * w2 * J2[k];
197-
++i;
152+
scalar_t J_ij[12] = {0};
153+
scalar_t r1 = 0, r2 = 0;
154+
const bool valid = GetJacobianSymmetric<scalar_t>(
155+
workload_idx, source_points_ptr, target_points_ptr,
156+
source_normals_ptr, target_normals_ptr,
157+
correspondence_indices, J_ij, r1, r2);
158+
159+
if (valid) {
160+
const scalar_t w1 = GetWeightFromRobustKernel(r1);
161+
const scalar_t w2 = GetWeightFromRobustKernel(r2);
162+
163+
// Accumulate JtJ and Jtr for both terms
164+
int i = 0;
165+
for (int j = 0; j < 6; ++j) {
166+
for (int k = 0; k <= j; ++k) {
167+
// Contribution from first term (source to
168+
// target)
169+
A_reduction[i] += J_ij[j] * w1 * J_ij[k];
170+
// Contribution from second term (target to
171+
// source)
172+
A_reduction[i] +=
173+
J_ij[j + 6] * w2 * J_ij[k + 6];
174+
++i;
175+
}
176+
// Jtr contributions
177+
A_reduction[21 + j] +=
178+
J_ij[j] * w1 * r1 + J_ij[j + 6] * w2 * r2;
198179
}
199-
A_reduction[21 + j] +=
200-
J1[j] * w1 * r1 + J2[j] * w2 * r2;
180+
A_reduction[27] += r1 * r1 + r2 * r2;
181+
A_reduction[28] += 1;
201182
}
202-
A_reduction[27] += r1 * r1 + r2 * r2;
203-
A_reduction[28] += 1;
204183
}
205184
#ifdef _WIN32
206185
return A_reduction;

cpp/open3d/t/pipelines/registration/TransformationEstimation.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,12 @@ double TransformationEstimationSymmetric::ComputeRMSE(
187187
core::Tensor valid = correspondences.Ne(-1).Reshape({-1});
188188
core::Tensor neighbour_indices =
189189
correspondences.IndexGet({valid}).Reshape({-1});
190+
191+
// Check if there are any valid correspondences
192+
if (neighbour_indices.GetLength() == 0) {
193+
return 0.0;
194+
}
195+
190196
core::Tensor source_points_indexed =
191197
source.GetPointPositions().IndexGet({valid});
192198
core::Tensor target_points_indexed =
@@ -223,6 +229,10 @@ core::Tensor TransformationEstimationSymmetric::ComputeTransformation(
223229
"normals.");
224230
}
225231

232+
const core::Device device = source.GetPointPositions().GetDevice();
233+
core::AssertTensorDevice(target.GetPointPositions(), device);
234+
235+
const core::Dtype dtype = source.GetPointPositions().GetDtype();
226236
core::AssertTensorDtypes(source.GetPointPositions(),
227237
{core::Float64, core::Float32});
228238
core::AssertTensorDtype(target.GetPointPositions(),
@@ -235,6 +245,13 @@ core::Tensor TransformationEstimationSymmetric::ComputeTransformation(
235245

236246
AssertValidCorrespondences(correspondences, source.GetPointPositions());
237247

248+
// Check if there are any valid correspondences
249+
core::Tensor valid = correspondences.Ne(-1);
250+
if (valid.Any().Item<bool>() == false) {
251+
// Return identity transformation if no valid correspondences
252+
return core::Tensor::Eye(4, dtype, device);
253+
}
254+
238255
// Get pose {6} of type Float64.
239256
core::Tensor pose = pipelines::kernel::ComputePoseSymmetric(
240257
source.GetPointPositions(), target.GetPointPositions(),

0 commit comments

Comments
 (0)