I am trying to do a rigid-body transformation in Python to register a source point set to a target point set by only allowing the source point set to rotate around one point shared by both the source and the target, i.e., the 2nd point. I basically translate the source and target by subtracting that user-defined center of rotation rather than the centroids. I then applied np.linalg.svd
for getting a rotation_matrix
.
However, when I tried the source and target points with different precisions, they got completely different results.
The first set of source and targets are:
source_points = np.array([[29.930, 65.059, -692.872], [20.588, 38.868, -675.454], [18.266, 57.316, -682.061]])
target_points = np.array([[27.474, 61.970, -689.958], [20.588, 38.868, -675.454], [15.340, 60.875, -681.762]]) # Your target points
The script is https://github.com/chz31/surgical_plate_registration/blob/main/proper_svd.py
I got a neat rotation transformation matrix that yielded good alignment as
array([[ 0.99795083, -0.05814411, 0.02670959],
[ 0.05909811, 0.99758699, -0.03643628],
[-0.02452659, 0.0379401 , 0.99897898]])
The second set of source and targets have higher precisions but are essentially the same points:
source_points = np.array([[29.92973456, 65.05863408, -692.87207321], [20.58772087,38.86774826, -675.45440674],[18.2662661, 57.31554544, -682.06144071]])
target_points = np.array([[27.47413063, 61.97033691, -689.95812988], [20.58772087, 38.86774826, -675.45440674], [15.33987617, 60.87537766, -681.76153564]])
The script is: https://github.com/chz31/surgical_plate_registration/blob/main/svd_deform_error.py
I then got a completely different transformation:
array([[ 0.49127036, -0.40722086, -0.76995104],
[-0.2900711 , 0.75702601, -0.58546595],
[-0.82128691, -0.51096261, -0.25378144]])
So for the second set, the homogeneous transformation matrix I reconstructed essentially deformed the source. For rigid-body registration, it should not deform the source.
#translation
t = rotation_center.T - np.dot(rotation_matrix, rotation_center.T)
#homogeneous transform matrix
T = np.identity(4)
T[:3, :3] = rotation_matrix
T[:3, 3] = t
I assumed that the two scripts should yield very similar results since they are essentially the same points only differing by precisions. In particular, a rigid transformation should not deform the source. Can anyone give some suggestions of what I did wrong or why this happened?
All right, I forgot the case that the signs of the rotation matrix might be reflected.
Adding this piece solved the problem:
# special reflection case
m = translated_source_points.shape[1]
if np.linalg.det(rotation_matrix) < 0:
Vt[m - 1, :] *= -1 rotation_matrix = np.dot(Vt.T, U.T)