Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
iperov
GitHub Repository: iperov/deepfacelab
Path: blob/master/core/mathlib/umeyama.py
628 views
1
import numpy as np
2
3
def umeyama(src, dst, estimate_scale):
4
"""Estimate N-D similarity transformation with or without scaling.
5
Parameters
6
----------
7
src : (M, N) array
8
Source coordinates.
9
dst : (M, N) array
10
Destination coordinates.
11
estimate_scale : bool
12
Whether to estimate scaling factor.
13
Returns
14
-------
15
T : (N + 1, N + 1)
16
The homogeneous similarity transformation matrix. The matrix contains
17
NaN values only if the problem is not well-conditioned.
18
References
19
----------
20
.. [1] "Least-squares estimation of transformation parameters between two
21
point patterns", Shinji Umeyama, PAMI 1991, DOI: 10.1109/34.88573
22
"""
23
24
num = src.shape[0]
25
dim = src.shape[1]
26
27
# Compute mean of src and dst.
28
src_mean = src.mean(axis=0)
29
dst_mean = dst.mean(axis=0)
30
31
# Subtract mean from src and dst.
32
src_demean = src - src_mean
33
dst_demean = dst - dst_mean
34
35
# Eq. (38).
36
A = np.dot(dst_demean.T, src_demean) / num
37
38
# Eq. (39).
39
d = np.ones((dim,), dtype=np.double)
40
if np.linalg.det(A) < 0:
41
d[dim - 1] = -1
42
43
T = np.eye(dim + 1, dtype=np.double)
44
45
U, S, V = np.linalg.svd(A)
46
47
# Eq. (40) and (43).
48
rank = np.linalg.matrix_rank(A)
49
if rank == 0:
50
return np.nan * T
51
elif rank == dim - 1:
52
if np.linalg.det(U) * np.linalg.det(V) > 0:
53
T[:dim, :dim] = np.dot(U, V)
54
else:
55
s = d[dim - 1]
56
d[dim - 1] = -1
57
T[:dim, :dim] = np.dot(U, np.dot(np.diag(d), V))
58
d[dim - 1] = s
59
else:
60
T[:dim, :dim] = np.dot(U, np.dot(np.diag(d), V))
61
62
if estimate_scale:
63
# Eq. (41) and (42).
64
scale = 1.0 / src_demean.var(axis=0).sum() * np.dot(S, d)
65
else:
66
scale = 1.0
67
68
T[:dim, dim] = dst_mean - scale * np.dot(T[:dim, :dim], src_mean.T)
69
T[:dim, :dim] *= scale
70
71
return T
72
73