Skip to main content

High-performance N-dimensional unit field transformations with interpolation

Project description

UnitField

License: MIT Python 3.8+

UnitField is a high-performance Python library for N-dimensional unit field transformations with interpolation. It provides efficient tools for mapping unit-space coordinates (values in [0, 1]) to transformed coordinates, with support for various interpolation methods and optimized backends.

Features

  • N-dimensional unit field transformations with flexible interpolation
  • Multiple interpolation methods: Nearest neighbor (Manhattan/Euclidean), Linear, Cubic, Lanczos4
  • Dual backends: NumPy for N-dimensional fields, OpenCV for optimized 2D operations
  • 2D image remapping with endomorphism composition
  • Type-safe with comprehensive type hints
  • Well-tested with extensive test coverage
  • Performance optimized with LRU caching and vectorized operations

Installation

From Source

git clone https://github.com/Grayjou/UnitField.git
cd UnitField
pip install -e .

Requirements

  • Python >= 3.8
  • NumPy >= 1.20.0
  • OpenCV (cv2) >= 4.5.0
  • boundednumbers >= 0.1.0
  • typing-extensions >= 4.0.0

Quick Start

Basic Unit Field Usage

import numpy as np
from unitfield.core.unitfield import MappedUnitField
from unitfield.core.enums import InterpMethod

# Create a 2D unit field (5x5 grid mapping to 2D vectors)
x, y = np.meshgrid(np.linspace(0, 1, 5), np.linspace(0, 1, 5))
data = np.stack([x, y], axis=-1)

# Create the field with linear interpolation
field = MappedUnitField(data=data, interp_method=InterpMethod.LINEAR)

# Query single coordinate
result = field.get_value((0.5, 0.5))
print(f"Value at (0.5, 0.5): {result}")

# Query multiple coordinates
coords = np.array([[0.0, 0.0], [0.5, 0.5], [1.0, 1.0]])
results = field.get_values(coords)
print(f"Batch results shape: {results.shape}")

2D Image Remapping with Endomorphisms

import numpy as np
import cv2
from unitfield.core.unitfield import Unit2DMappedEndomorphism
from unitfield.core.enums import InterpMethod

# Create an identity endomorphism
height, width = 100, 100
xs, ys = np.meshgrid(
    np.linspace(0, 1, width),
    np.linspace(0, 1, height),
    indexing='xy'
)
identity_data = np.stack([xs, ys], axis=-1)

# Create endomorphism with cubic interpolation
endo = Unit2DMappedEndomorphism(
    data=identity_data,
    interp_method=InterpMethod.CUBIC
)

# Remap an image
image = cv2.imread('input.jpg')
remapped = endo.remap(image, interpolation=cv2.INTER_LINEAR)

# Compose two endomorphisms
endo2 = Unit2DMappedEndomorphism(data=other_data)
composed = endo.compose(endo2)

API Reference

Core Classes

MappedUnitField

N-dimensional unit field with interpolation.

Parameters:

  • data (UnitArray): N+1 dimensional array of shape (*spatial_dims, N)
  • interp_method (InterpMethod): Interpolation strategy (default: NEAREST_MANHATTAN)
  • cache_size (int, optional): LRU cache size for single queries (default: 128)

Methods:

  • get_value(coords): Get value at single coordinate
  • get_values(coords_array): Get values at multiple coordinates
  • with_interp_method(method): Create copy with different interpolation

Unit2DMappedEndomorphism

2D unit field endomorphism with optimized OpenCV backend.

Parameters:

  • data (UnitArray): 3-dimensional array of shape (H, W, 2)
  • interp_method (InterpMethod): Interpolation strategy
  • cache_size (int, optional): LRU cache size

Methods:

  • get_value(coords): Get single coordinate value
  • get_values(coords_array): Get multiple coordinate values
  • rasterize_mapping(width, height): Convert to pixel-space mapping
  • remap(data): Remap arbitrary (H, W, J) array
  • compose(other): Compose with another endomorphism

Interpolation Methods

from unitfield.core.enums import InterpMethod

# Available methods:
InterpMethod.NEAREST_MANHATTAN  # Nearest neighbor (Manhattan distance)
InterpMethod.NEAREST_EUCLIDEAN  # Nearest neighbor (Euclidean distance)
InterpMethod.LINEAR             # Linear/bilinear interpolation
InterpMethod.CUBIC              # Cubic/bicubic interpolation
InterpMethod.LANCZOS4           # Lanczos-4 interpolation

Utility Functions

remap_tensor_cv2

Remap arbitrary tensors using pixel-space mappings.

from unitfield.core.unitfield import remap_tensor_cv2

result = remap_tensor_cv2(
    data=tensor,
    mapping=pixel_mapping,
    interpolation=cv2.INTER_LINEAR,
    border_mode=cv2.BORDER_REPLICATE,
    border_value=0.0
)

Coordinate System

UnitField operates in unit space where coordinates are in the range [0, 1]:

  • 0.0 represents the start of each dimension
  • 1.0 represents the end of each dimension
  • Coordinates are automatically scaled to array indices

Coordinate Constraints and Behavior

Important Limitations:

  1. Infinite and NaN coordinates are NOT supported and will produce undefined behavior. This is by design to keep the functions simple and avoid overhead:

    # ❌ AVOID - undefined behavior
    field.get_value((np.inf, 0.5))  
    field.get_value((np.nan, 0.5))  
    
  2. Out-of-bounds coordinates (< 0 or > 1) are handled via clipping to [0, 1] range:

    # ✓ OK - will be clipped to valid range
    field.get_value((-0.5, 1.5))  # Treated as (0.0, 1.0)
    
  3. Why this design?

    • Unit field transformations are intended for normalized coordinate spaces
    • Checking for inf/NaN on every coordinate adds unnecessary overhead
    • Out-of-bounds handling beyond [0, 1] is simple to implement externally if needed
    • Keeps the core functions fast and focused

Best Practices:

  • Validate coordinates before passing to UnitField methods if they may contain special values
  • For out-of-bounds behavior beyond simple clipping, preprocess coordinates externally

Examples

Creating Different Field Types

# 1D field
data_1d = np.linspace(0, 1, 100).reshape(-1, 1)
field_1d = MappedUnitField(data=data_1d, interp_method=InterpMethod.LINEAR)

# 3D field
data_3d = np.random.rand(10, 10, 10, 3)
field_3d = MappedUnitField(data=data_3d, interp_method=InterpMethod.CUBIC)

Switching Interpolation Methods

# Create field with one method
field = MappedUnitField(data=data, interp_method=InterpMethod.LINEAR)

# Switch to another method
cubic_field = field.with_interp_method(InterpMethod.CUBIC)

Batch Processing

# Process large batches efficiently
batch_size = 1000
coords = np.random.rand(batch_size, 2)
results = field.get_values(coords)

Image Warping Example

import numpy as np
import cv2
from unitfield.core.unitfield import Unit2DMappedEndomorphism

# Create a simple distortion field (barrel distortion)
h, w = 256, 256
y, x = np.ogrid[:h, :w]
center_x, center_y = w / 2, h / 2

# Calculate distance from center
dx = (x - center_x) / center_x
dy = (y - center_y) / center_y
r = np.sqrt(dx**2 + dy**2)

# Apply barrel distortion
distortion = 1 + 0.3 * r**2
new_x = center_x + dx * distortion * center_x
new_y = center_y + dy * distortion * center_y

# Normalize to unit space
unit_x = new_x / (w - 1)
unit_y = new_y / (h - 1)
distortion_field = np.stack([unit_x, unit_y], axis=-1).astype(np.float32)

# Create endomorphism and apply
endo = Unit2DMappedEndomorphism(data=distortion_field)
image = cv2.imread('input.jpg')
warped = endo.remap(image)
cv2.imwrite('output.jpg', warped)

Performance Tips

  1. Use caching for repeated queries: Set appropriate cache_size when creating fields
  2. Batch operations: Use get_values() instead of multiple get_value() calls
  3. Choose the right backend: Use Unit2DMappedEndomorphism for 2D operations (faster via OpenCV)
  4. Appropriate interpolation: Nearest neighbor is fastest, cubic/Lanczos are slower but smoother

Development

Running Tests

pip install pytest pytest-benchmark
pytest tests/ -v

Code Style

This project follows modern Python conventions:

  • PEP 8 style guide
  • Type hints throughout
  • Comprehensive docstrings (Google style)

Known Limitations

  1. Inf/NaN coordinates: Not supported in remapping functions (see Coordinate Constraints section)
  2. Memory usage: Large N-dimensional fields may consume significant memory
  3. 2D optimization: Only 2D endomorphisms benefit from OpenCV backend optimization

Contributing

Contributions are welcome! Please:

  1. Fork the repository
  2. Create a feature branch
  3. Add tests for new functionality
  4. Ensure all tests pass
  5. Submit a pull request

License

This project is licensed under the MIT License - see the LICENSE file for details.

Citation

If you use UnitField in your research, please cite:

@software{unitfield2025,
  author = {GrayJou},
  title = {UnitField: N-dimensional Unit Field Transformations},
  year = {2025},
  url = {https://github.com/Grayjou/UnitField}
}

Acknowledgments

  • Built with NumPy and OpenCV
  • Inspired by coordinate transformation needs in computer vision and graphics

Support

For issues, questions, or contributions, please visit:

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

unitfield-0.1.2.tar.gz (32.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

unitfield-0.1.2-py3-none-any.whl (18.1 kB view details)

Uploaded Python 3

File details

Details for the file unitfield-0.1.2.tar.gz.

File metadata

  • Download URL: unitfield-0.1.2.tar.gz
  • Upload date:
  • Size: 32.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.10

File hashes

Hashes for unitfield-0.1.2.tar.gz
Algorithm Hash digest
SHA256 aac56f8b29ce937079fc08ff0b1e4c5ccec6090887cf02d24404f040c2af70e8
MD5 5f635bf89fc7542f31e5d367c4bbccd8
BLAKE2b-256 993b4ad3b8f8f9eee644b997c725aae3c921fe63b5261eadcf3b8d7a9e070384

See more details on using hashes here.

File details

Details for the file unitfield-0.1.2-py3-none-any.whl.

File metadata

  • Download URL: unitfield-0.1.2-py3-none-any.whl
  • Upload date:
  • Size: 18.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.10

File hashes

Hashes for unitfield-0.1.2-py3-none-any.whl
Algorithm Hash digest
SHA256 1a81ae991c036d723afc9e1235f2d252d2c8e85110d91ace5a1d17d5e7df56f6
MD5 ef2fd0efee3654f18de939130de79efd
BLAKE2b-256 cb168d96c0f26beb2fa3a03fbdf4646d474c430cf77111823be78f12b75f65b6

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page