Unified 3D transform utilities supporting both NumPy and PyTorch backends
Project description
uni-transform
A high-performance Python library for 3D rigid body transformations, supporting both NumPy and PyTorch backends with full gradient support.
Features
- Dual Backend Support: Seamless switching between NumPy and PyTorch
- Full Gradient Support: All PyTorch operations are differentiable (ideal for deep learning)
- Arbitrary Batch Dimensions: Handle single transforms or batches of any shape
- Comprehensive Representations: Matrix, Quaternion (xyzw), Euler, Rotation Vector, 6D Rotation
- SE(3) Lie Group Operations: Logarithm and exponential maps for twist representations
- Interpolation: SLERP, NLERP, and transform sequence interpolation
- Numerically Stable: Robust implementations handling edge cases (gimbal lock, 180° rotations)
Installation
pip install uni-transform
From Source
git clone https://github.com/junhaotu/uni-transform.git
cd uni-transform
pip install -e .
Development Installation
pip install -e ".[dev]"
Quick Start
Basic Usage
import numpy as np
from uni_transform import Transform, convert_rotation
# Create a transform from position + euler angles
tf = Transform.from_rep(
np.array([1.0, 2.0, 3.0, 0.1, 0.2, 0.3]), # [x, y, z, roll, pitch, yaw]
from_rep="euler",
seq="ZYX"
)
# Convert to quaternion representation
quat_rep = tf.to_rep("quat") # [x, y, z, qx, qy, qz, qw]
# Get 4x4 homogeneous matrix
matrix_4x4 = tf.as_matrix()
# Transform composition
tf_composed = tf @ tf.inverse() # Should be identity
# Transform points
points = np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]])
transformed = tf.transform_point(points)
PyTorch with Gradients
import torch
from uni_transform import rotation_6d_to_matrix, geodesic_distance
# 6D rotation is ideal for neural networks (continuous, no singularities)
pred_rot6d = model(input) # Shape: (batch, 6)
# Convert to rotation matrix
pred_matrix = rotation_6d_to_matrix(pred_rot6d) # Shape: (batch, 3, 3)
# Compute geodesic loss (gradients flow through)
loss = geodesic_distance(pred_matrix, target_matrix, reduce=False).mean()
loss.backward()
Rotation Conversions
from uni_transform import (
quaternion_to_matrix,
matrix_to_quaternion,
euler_to_matrix,
matrix_to_euler,
rotvec_to_matrix,
convert_rotation,
)
# Direct conversions
quat = np.array([0, 0, 0.707, 0.707]) # xyzw format, 90° around Z
matrix = quaternion_to_matrix(quat)
# Generic conversion function
euler = convert_rotation(quat, from_rep="quat", to_rep="euler", seq="ZYX")
rot6d = convert_rotation(matrix, from_rep="matrix", to_rep="rotation_6d")
Quaternion Operations
from uni_transform import (
quaternion_multiply,
quaternion_apply,
quaternion_slerp,
quaternion_inverse,
)
# Quaternion multiplication (composition)
q_combined = quaternion_multiply(q1, q2)
# Rotate a vector directly (more efficient than matrix multiplication)
rotated_vector = quaternion_apply(quat, vector)
# Spherical interpolation
q_mid = quaternion_slerp(q_start, q_end, t=0.5)
Transform Interpolation
from uni_transform import transform_interpolate, transform_sequence_interpolate
# Interpolate between two transforms
tf_mid = transform_interpolate(tf_start, tf_end, t=0.5)
# Interpolate along a trajectory
keyframes = [tf0, tf1, tf2, tf3]
times = np.array([0.0, 1.0, 2.0, 3.0])
query_times = np.array([0.5, 1.5, 2.5])
interpolated = transform_sequence_interpolate(keyframes, times, query_times)
SE(3) Lie Group Operations
from uni_transform import se3_log, se3_exp
# Convert transform to twist (6D tangent space)
twist = se3_log(transform) # [omega_x, omega_y, omega_z, v_x, v_y, v_z]
# Convert twist back to transform
transform_recovered = se3_exp(twist)
API Reference
Core Classes
| Class | Description |
|---|---|
Transform |
Rigid body transform with rotation matrix and translation |
RotationRepr |
Enum for rotation representations: EULER, QUAT, MATRIX, ROTATION_6D, ROT_VEC |
Rotation Representations
| Representation | Shape | Description |
|---|---|---|
matrix |
(..., 3, 3) |
Rotation matrix (SO(3)) |
quat |
(..., 4) |
Quaternion in xyzw format |
euler |
(..., 3) |
Euler angles (default: ZYX sequence) |
rotation_6d |
(..., 6) |
6D rotation (first two rows of matrix) |
rot_vec |
(..., 3) |
Rotation vector (axis × angle) |
Key Functions
Conversion Functions
quaternion_to_matrix(quat)/matrix_to_quaternion(matrix)euler_to_matrix(euler, seq="ZYX")/matrix_to_euler(matrix, seq="ZYX")rotvec_to_matrix(rotvec)/matrix_to_rotvec(matrix)rotation_6d_to_matrix(rot6d)/matrix_to_rotation_6d(matrix)convert_rotation(rotation, from_rep=..., to_rep=...)
Quaternion Operations
quaternion_multiply(q1, q2)- Hamilton productquaternion_apply(q, v)- Rotate vector by quaternionquaternion_conjugate(q)/quaternion_inverse(q)quaternion_slerp(q0, q1, t)- Spherical linear interpolationquaternion_nlerp(q0, q1, t)- Normalized linear interpolation
Utilities
geodesic_distance(R1, R2)- Rotation angle between matricesorthogonalize_rotation(matrix)- Project to SO(3) via SVDse3_log(transform)/se3_exp(twist)- SE(3) Lie group operations
Transform Class Methods
# Factory methods
Transform.identity(backend="numpy")
Transform.from_matrix(matrix_4x4)
Transform.from_rep(array, from_rep="euler")
Transform.from_pos_quat(position, quaternion)
Transform.stack([tf1, tf2, tf3])
# Instance methods
tf.as_matrix() # Get 4x4 matrix
tf.to_rep("quat") # Convert to representation
tf.inverse() # Inverse transform
tf.transform_point(point) # Apply to points
tf.transform_vector(vector) # Apply rotation only
tf.apply_delta(delta) # Apply incremental transform
tf.relative_to(reference) # Express in reference frame
tf.clone() # Deep copy
tf.to(device="cuda") # Move to device (PyTorch)
tf.requires_grad_(True) # Enable gradients (PyTorch)
Conventions
- Quaternion format:
xyzw(matches SciPy and ROS conventions) - Euler default:
ZYXsequence (yaw-pitch-roll) - Transform composition:
tf1 @ tf2appliestf2first, thentf1
Performance Tips
- For neural networks: Use
rotation_6drepresentation (continuous, no singularities) - For single vector rotations: Use
quaternion_applyinstead of matrix multiplication - For many interpolations: Use
quaternion_nlerpinstead ofquaternion_slerp - For trajectory interpolation: Use vectorized
transform_sequence_interpolate
Testing
pytest test/ -v
License
MIT License - see LICENSE for details.
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file uni_transform-0.1.0.tar.gz.
File metadata
- Download URL: uni_transform-0.1.0.tar.gz
- Upload date:
- Size: 32.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.10.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
71ac26bc15a7b5dcc0b74712dc8498bb3daa604ec1be599e6e5f21557af8a699
|
|
| MD5 |
8a0e5797b78ea3230516d3b80e4fe169
|
|
| BLAKE2b-256 |
3859efdd8d1321eda99d31f3519936c85daa3d3e4152f6e243dcc90f50b62a13
|
File details
Details for the file uni_transform-0.1.0-py3-none-any.whl.
File metadata
- Download URL: uni_transform-0.1.0-py3-none-any.whl
- Upload date:
- Size: 23.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.10.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
67733f07416af0de3f99dfd93ef503d526680301f1468e105d1820928530744c
|
|
| MD5 |
72a3ef1a519704a0ff021d66cc9874d9
|
|
| BLAKE2b-256 |
9808eeb167369e6cba23ea9c7626086a7e52a4156ce88a59e1643e47ec155b0b
|