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.0.tar.gz (30.8 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.0-py3-none-any.whl (17.1 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: unitfield-0.1.0.tar.gz
  • Upload date:
  • Size: 30.8 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.0.tar.gz
Algorithm Hash digest
SHA256 1d0623edb12ca9a4b7936e1fbe7ea97bbf69ebb147add441eaba56c9045759aa
MD5 afe85f95bc0672fdced7a695414928d9
BLAKE2b-256 604eef8be1b7d7f80ecf89450b0a497c762e59db4f450088f7eececd13de4ed5

See more details on using hashes here.

File details

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

File metadata

  • Download URL: unitfield-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 17.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.0-py3-none-any.whl
Algorithm Hash digest
SHA256 bfb847bb9d7cef9da5bda06a8aa59e0b51179c4b6db589fc159b66a6f603dcf4
MD5 8b74824edfcc5a94f1e7ca6f4a16f503
BLAKE2b-256 10cc3d6ef6580d5f54a89bb354dfc62c3544d5c5391a78f76fea689cf21eee1d

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