kiss_icp_ops_eigen/
lib.rs1use std::ops::MulAssign;
2
3use kiss_icp_ops_core::matrix::MatrixVectorOps;
4use nalgebra::{Matrix3xX, Matrix4, Vector3, SVD};
5
6pub fn umeyama(src: &Matrix3xX<f64>, dst: &Matrix3xX<f64>, with_scaling: bool) -> Matrix4<f64> {
7 let n = src.ncols(); let one_over_n = 1.0 / n as f64;
11
12 let src_mean = src.column_mean();
14 let dst_mean = dst.column_mean();
15
16 let src_demean = src.vector_sub(&src_mean);
18 let dst_demean = dst.vector_sub(&dst_mean);
19
20 let src_var = src_demean
22 .row_iter()
23 .map(|column| column.norm_squared())
24 .sum::<f64>()
25 * one_over_n;
26
27 let sigma = one_over_n * dst_demean * src_demean.transpose();
29
30 let SVD {
31 u,
32 v_t,
33 singular_values,
34 } = sigma.svd(true, true);
35 let u = u.unwrap();
36 let v_t = v_t.unwrap();
37
38 let mut rt = Matrix4::identity();
40
41 let mut s = Vector3::<f64>::from_element(1.0);
43
44 if u.determinant() * v_t.transpose().determinant() < 0.0 {
45 s[2] = -1.0;
46 }
47
48 let rot = u.vector_mul(&s) * v_t;
50 rt.fixed_view_mut::<3, 3>(0, 0).copy_from(&rot);
51
52 let mut block = rt.fixed_view_mut::<3, 1>(0, 3);
53 block.copy_from(&dst_mean);
54
55 if with_scaling {
56 let c = 1.0 / src_var * singular_values.dot(&s);
58
59 block -= c * rot * src_mean;
61 rt.fixed_view_mut::<3, 3>(0, 0).mul_assign(c);
62 } else {
63 block -= rot * src_mean;
64 }
65
66 rt
67}