Skip to main content

kaffine

codecov PyPI version Maintainer PyPI pyversions PyPI status PyPI download day

kaffine

Kaffine is inspired by pint and affine. nd aims to make the creation of unit-aware affine transformations as easy as possible. kaffine simplifies constructing complex 4x4 affine transformation matrices. It r offers native integration with Pint for physical units (mixing microns, millimeters, and inches), and bridges seamlessly with Scipy for advanced usage.

Designed for Computer Vision, Microscopy, and Robotics applications where "Sample-to-Camera" or "Stage-to-World" coordinates are critical.

🚀 Features

  • Fluent Interface: Chain operations like .translate_x(10).rotate_z(90).
  • Unit Aware: Native support for Pint. Move 100 microns on X and 2 mm on Y without manual conversion.
  • Hardware Ready: Includes decompose() to extract pixel size, rotation, and stage position from a raw matrix.
  • Type Safe: Built with modern Python 3.11+ type hints (typing.Self, | unions).
  • Scipy Bridge: Cast to/from scipy.spatial.transform.Rotation for quaternions and slerp.
  • Zero-Crash Defaults: Scipy and Pint are optional dependencies. The library falls back to pure NumPy if they aren't installed.

📦 Installation

uv add kaffine

⚡ Quick Start

1. The Simple Math Interface

Perfect for standard graphics or geometry.

from kaffine import Affine

# Create a transform: Move 10 units X, then Rotate 45 deg Z
# (Note: Order is intuitive "Operation 1 -> Operation 2")
tf = Affine.new().translate_x(10).rotate_z(45)

# Apply to a point
point = [0, 0, 0]
result = tf * point 

print(result) 
# Output (4D homogeneous): [10.0, 0.0, 0.0, 1.0]

2. The "Hardware" Interface (with Units)

Perfect for controlling stages, cameras, or mixing scales.

from kaffine import Affine
import pint

ureg = pint.UnitRegistry()

# Define your setup's units
ureg.define("step = 0.1 um")  # Piezo stepper resolution
ureg.define("pixel = 3.45 um") # Camera sensor pixel size

# Construct a Matrix that converts Pixels to Stage Coordinates (mm)
# Scenario: 
# 1. Scale pixels to physical size
# 2. Rotate camera 90 degrees
# 3. Translate to stage position (defined in steps)
tf = Affine.new(base_unit="um", registry=ureg) \
    .scale_uniform("1 pixel") \
    .rotate_z(90) \
    .translate_x("50000 step") 

# Transform a point from Pixel Space to Millimeters
pixel_point = [100, 100, 0] # 100x100 px on image
world_point = tf.apply(pixel_point)

print(world_point)
# Output: <Quantity([5.0 -0.345 0. 1.], 'millimeter')>

📚 Advanced Usage

Matrix Decomposition (Calibration)

If you have a calibration matrix and need to know the physical properties of your setup (e.g., "What is my effective pixel size?"), use .decompose().

# Assume 'tf' is a calibrated matrix loaded from a file
info = tf.decompose()

print(f"Position:   {info.translation}") # e.g., [10.5, 2.0, 0] mm
print(f"Pixel Size: {info.scale}")       # e.g., [0.00345, 0.00345, 1.0]
print(f"Rotation:   {info.rotation}")    # e.g., [0, 0, 1.5] degree

Scipy Interoperability

Need Quaternions or Spherical Interpolation?

tf = Affine.new().rotate_x(45).rotate_y(30)

# Cast to Scipy
r_scipy = tf.to_scipy_rotation()
print(r_scipy.as_quat())

# ... do complex math ...
r_scipy_inverted = r_scipy.inv()

# Cast back
tf_inv = Affine.from_scipy(r_scipy_inverted)

🛠 API Reference

Affine.new(base_unit="mm", registry=None)

Starts a new transformation chain.

  • base_unit: The physical unit the internal matrix numbers represent.
  • registry: Your pint.UnitRegistry.

Builder Methods

All methods return a new Affine instance (immutable-style chaining).

  • .translate(x, y, z) / .translate_x(val) ...
  • .rotate(angle, axis='z') / .rotate_x(angle) ...
  • .scale(x, y, z) / .scale_uniform(s)

Application

  • tf * [x, y, z]: Returns a raw Numpy array (4D).
  • tf * other_tf: Composes two transforms.
  • tf.apply(points): Accepts/Returns Pint Quantities.

Utilities

  • tf.decompose(): Returns Decomposition(translation, scale, rotation).
  • tf.to_scipy_rotation(): Returns scipy.spatial.transform.Rotation.

🧪 Running Tests

The project includes a comprehensive pytest suite covering math accuracy, unit conversion, and edge cases.

uv run pytest tests/

📄 License

MIT License. Feel free to use this in your commercial or open-source projects.

Metadata

Release files for kaffine 3.0.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for kaffine 3.0.0
File Size Uploaded Provenance Actions
kaffine-3.0.0.tar.gz 7.6 kB Without provenance Details for kaffine-3.0.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for kaffine 3.0.0
File Interpreter ABI Platform Actions
kaffine-3.0.0-py3-none-any.whl Python 3 none any Details for kaffine-3.0.0-py3-none-any.whl

Total release size: 14.4 kB

Release files / kaffine-3.0.0.tar.gz

Download URL kaffine-3.0.0.tar.gz
Size 7.6 kB
Tags Source
SHA-256 checksum
How to use checksums
dd1ee4982e1710b6cf5f7e5fba4ebf2d34e2712f1d512edf4ac45f177aa2dd95
BLAKE2b-256 checksum
How to use checksums
ccb3fba58e5d2cba5f8a23c48f64f391e610fa3fc22fc7eb139212e1cbf9d122
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.13.6 {"installer":{"name":"uv","version":"0.13.6","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / kaffine-3.0.0-py3-none-any.whl

Download URL kaffine-3.0.0-py3-none-any.whl
Size 6.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
cbc5f86c90c3f2121eddfdbe2321e4dcbc0648654d57ad09d96d85191f8dcd75
BLAKE2b-256 checksum
How to use checksums
72ab63b9f1d8f1e887a7cb925820aa9f6a6ee95a6f9688b35b9fa45cc0beb058
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.13.6 {"installer":{"name":"uv","version":"0.13.6","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Security for kaffine 3.0.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page