solve-rigid-point-set-rt 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 GGN_2015
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,69 @@
1
+ Metadata-Version: 2.4
2
+ Name: solve-rigid-point-set-rt
3
+ Version: 0.1.0
4
+ Summary: Solve the transform vector and rotation matrix of a rigid point set.
5
+ License: MIT
6
+ License-File: LICENSE
7
+ Author: GGN_2015
8
+ Author-email: neko@jlulug.org
9
+ Requires-Python: >=3.10
10
+ Classifier: License :: OSI Approved :: MIT License
11
+ Classifier: Programming Language :: Python :: 3
12
+ Classifier: Programming Language :: Python :: 3.10
13
+ Classifier: Programming Language :: Python :: 3.11
14
+ Classifier: Programming Language :: Python :: 3.12
15
+ Classifier: Programming Language :: Python :: 3.13
16
+ Classifier: Programming Language :: Python :: 3.14
17
+ Requires-Dist: numpy
18
+ Description-Content-Type: text/markdown
19
+
20
+ # solve_rigid_point_set_rt
21
+ Solve the transform vector and rotation matrix of a rigid point set.
22
+
23
+ ## Installation
24
+
25
+ ```bash
26
+ pip install solve_rigid_point_set_rt
27
+ ```
28
+
29
+ ## Usage
30
+
31
+ ```python
32
+ from solve_rigid_point_set_rt import compute_best_rigid_transform
33
+ from solve_rigid_point_set_rt import apply_transform
34
+ from solve_rigid_point_set_rt import calculate_error
35
+ import numpy as np
36
+
37
+ P = np.array([
38
+ [ 20.606943, -0.005458, 0.040331],
39
+ [ -4.885081, -26.211561, -0.023027],
40
+ [ 12.012958, 20.049110, -0.035819],
41
+ [-27.734814, 6.167912, 0.018507]
42
+ ])
43
+
44
+ Q = np.array([
45
+ [-132.94031926182967, 137.4289669332182, 782.6069181107938],
46
+ [-164.12739196778332, 120.93405919807722, 791.4971644346351],
47
+ [-115.37230320753432, 126.89401508498568, 790.1637162115628],
48
+ [-137.8636773243661, 96.44871350623225, 808.1944560570211]
49
+ ])
50
+
51
+ # 2. Compute optimal rotation and translation
52
+ R_est, t_est = compute_best_rigid_transform(P, Q)
53
+
54
+ # 3. Apply transformation and calculate error
55
+ P_transformed = apply_transform(P, R_est, t_est)
56
+ rmse, mean_dist, _ = calculate_error(P_transformed, Q)
57
+
58
+ # 4. Print results
59
+ print("="*50)
60
+ print("Optimal Rotation Matrix R:")
61
+ print(R_est)
62
+ print("\nOptimal Translation Vector t:")
63
+ print(t_est)
64
+ print("\nRegistration Accuracy:")
65
+ print(f"Root Mean Square Error (RMSE): {rmse:.6f}")
66
+ print(f"Mean Euclidean Distance: {mean_dist:.6f}")
67
+ print("="*50)
68
+ ```
69
+
@@ -0,0 +1,49 @@
1
+ # solve_rigid_point_set_rt
2
+ Solve the transform vector and rotation matrix of a rigid point set.
3
+
4
+ ## Installation
5
+
6
+ ```bash
7
+ pip install solve_rigid_point_set_rt
8
+ ```
9
+
10
+ ## Usage
11
+
12
+ ```python
13
+ from solve_rigid_point_set_rt import compute_best_rigid_transform
14
+ from solve_rigid_point_set_rt import apply_transform
15
+ from solve_rigid_point_set_rt import calculate_error
16
+ import numpy as np
17
+
18
+ P = np.array([
19
+ [ 20.606943, -0.005458, 0.040331],
20
+ [ -4.885081, -26.211561, -0.023027],
21
+ [ 12.012958, 20.049110, -0.035819],
22
+ [-27.734814, 6.167912, 0.018507]
23
+ ])
24
+
25
+ Q = np.array([
26
+ [-132.94031926182967, 137.4289669332182, 782.6069181107938],
27
+ [-164.12739196778332, 120.93405919807722, 791.4971644346351],
28
+ [-115.37230320753432, 126.89401508498568, 790.1637162115628],
29
+ [-137.8636773243661, 96.44871350623225, 808.1944560570211]
30
+ ])
31
+
32
+ # 2. Compute optimal rotation and translation
33
+ R_est, t_est = compute_best_rigid_transform(P, Q)
34
+
35
+ # 3. Apply transformation and calculate error
36
+ P_transformed = apply_transform(P, R_est, t_est)
37
+ rmse, mean_dist, _ = calculate_error(P_transformed, Q)
38
+
39
+ # 4. Print results
40
+ print("="*50)
41
+ print("Optimal Rotation Matrix R:")
42
+ print(R_est)
43
+ print("\nOptimal Translation Vector t:")
44
+ print(t_est)
45
+ print("\nRegistration Accuracy:")
46
+ print(f"Root Mean Square Error (RMSE): {rmse:.6f}")
47
+ print(f"Mean Euclidean Distance: {mean_dist:.6f}")
48
+ print("="*50)
49
+ ```
@@ -0,0 +1,18 @@
1
+ [project]
2
+ name = "solve-rigid-point-set-rt"
3
+ version = "0.1.0"
4
+ description = "Solve the transform vector and rotation matrix of a rigid point set."
5
+ authors = [
6
+ {name = "GGN_2015",email = "neko@jlulug.org"}
7
+ ]
8
+ license = {text = "MIT"}
9
+ readme = "README.md"
10
+ requires-python = ">=3.10"
11
+ dependencies = [
12
+ "numpy"
13
+ ]
14
+
15
+
16
+ [build-system]
17
+ requires = ["poetry-core>=2.0.0,<3.0.0"]
18
+ build-backend = "poetry.core.masonry.api"
@@ -0,0 +1,9 @@
1
+ from .main import compute_best_rigid_transform
2
+ from .main import apply_transform
3
+ from .main import calculate_error
4
+
5
+ __all__ = [
6
+ "compute_best_rigid_transform",
7
+ "apply_transform",
8
+ "calculate_error"
9
+ ]
@@ -0,0 +1,55 @@
1
+ import numpy as np
2
+
3
+ def compute_best_rigid_transform(P: np.ndarray, Q: np.ndarray, assume_p_center_zero:bool=False):
4
+ """
5
+ Compute the optimal 3D rotation matrix R and translation vector t
6
+ that satisfies: Q = R @ P + t (minimum mean square error)
7
+ Parameters:
8
+ P: Source point set, shape (N, 3), N is the number of points
9
+ Q: Target point set, shape (N, 3), in one-to-one correspondence with P
10
+ Returns:
11
+ R: 3x3 optimal rotation matrix
12
+ t: 3x1 optimal translation vector
13
+ """
14
+ # 1. Validate input
15
+ assert P.shape == Q.shape, "The number and dimensions of the two point sets must be identical!"
16
+ assert P.shape[1] == 3, "Must be 3D point coordinates (x,y,z)"
17
+
18
+ # 2. Compute centroids of the two point sets
19
+ if assume_p_center_zero:
20
+ centroid_P = np.array([0, 0, 0])
21
+ else:
22
+ centroid_P = np.mean(P, axis=0)
23
+ centroid_Q = np.mean(Q, axis=0)
24
+
25
+ # 3. Center the points (subtract centroids to eliminate translation effect)
26
+ P_centered = P - centroid_P
27
+ Q_centered = Q - centroid_Q
28
+
29
+ # 4. Compute covariance matrix H (3x3)
30
+ H = P_centered.T @ Q_centered
31
+
32
+ # 5. Perform SVD to solve for optimal rotation
33
+ U, S, Vt = np.linalg.svd(H)
34
+ R = Vt.T @ U.T
35
+
36
+ # Correction: Ensure rotation matrix is right-handed (avoid reflection transformation)
37
+ if np.linalg.det(R) < 0:
38
+ Vt[-1, :] *= -1
39
+ R = Vt.T @ U.T
40
+
41
+ # 6. Compute optimal translation vector
42
+ t = centroid_Q - R @ centroid_P
43
+
44
+ return R, t
45
+
46
+ def apply_transform(P: np.ndarray, R: np.ndarray, t: np.ndarray):
47
+ """Apply rotation and translation to the source point set to get transformed points"""
48
+ return (R @ P.T).T + t
49
+
50
+ def calculate_error(transformed_P: np.ndarray, Q: np.ndarray):
51
+ """Calculate Root Mean Square Error (RMSE) and mean distance to evaluate registration accuracy"""
52
+ errors = np.linalg.norm(transformed_P - Q, axis=1) # Euclidean distance for each point
53
+ rmse = np.sqrt(np.mean(errors ** 2))
54
+ mean_dist = np.mean(errors)
55
+ return rmse, mean_dist, errors