Skip to content

Extension API

multiview-stitcher as a modular framework for registration and fusion

While multiview-stitcher contains a set of built-in functions for stitching, it is also possible to extend the package with custom functions. This can be useful for adding new registration algorithms, fusion methods, or other functionality. This page provides an overview of the extension API.

Pairwise registration

Custom functions for pairwise registration can be passed to the registration.register function:

def register(
    ...
    transform_key,
    pairwise_reg_func: Callable = phase_correlation_registration,
    pairwise_reg_func_kwargs: dict = None,
    ...
)

Custom registration functions can have one of the following two signatures. registration.register will automatically detect which signature is used and call the function accordingly, passing to the function - pairwise_reg_func_kwargs - the below detailed parameters to the functions.

Registration in pixel space

This API is for adding registration functions that operate on pixel data without any knowledge of the physical space.

Initial transformation

The moving data array is pre-transformed to match the pixel coordinate space of the fixed data array, using the affine matrices of the transform_key passed to registration.register.

Expected output transformation

The affine matrix returned by a registration following this API transforms pixel indices of the fixed image to pixel indices of the moving image. registration.register will take care of converting this matrix to a transformation that transforms the physical space.

def pairwise_registration(
    fixed_data: Array-like,
    moving_data: Array-like,
    **kwargs, # additional keyword arguments passed `pairwise_reg_func_kwargs`
    ) -> dict:

    # Registration code here

    return {
        "affine_matrix": affine_matrix, # homogenous matrix of shape (ndim + 1, ndim + 1), axis order (z, y, x)
        "quality": , # float between 0 and 1 (if not available, set to 1.0)
    }

Example implementation: multiview_stitcher.registration.phase_correlation_registration (default pairwise registration function).

Registration in physical coordinate space

This API is for adding registration functions that operate in physical coordinates.

Transformations in physical space

Both the pre-calculated initial_affine parameter passed to the pairwise registration function and the affine matrix returned by a registration following this API transform physical positions of the fixed image to physical positions of the moving image. Here, physical positions are calculated as origin + spacing * pixel_index.

def custom_pairwise_registration_function(
    fixed_data: Array-like,
    moving_data: Array-like,
    *,
    fixed_origin: dict[str, float], # e.g. {"z": 10.0, "y": 20.0, "x": 30.0}
    moving_origin: dict[str, float],
    fixed_spacing: dict[str, float], # e.g. {"z": 1.0, "y": 0.5, "x": 0.5}
    moving_spacing: dict[str, float],
    initial_affine: xr.DataArray, # see note below
    **kwargs, # `pairwise_reg_func_kwargs` passed to `registration.register`
) -> dict:
    # Registration code here

    return {
        "affine_matrix": affine_matrix, # homogenous matrix of shape (ndim + 1, ndim + 1), axis order (z, y, x)
        "quality": 1.0, # float between 0 and 1 (if not available, set to 1.0)
    }

For a description of the object that will be passed as an initial affine matrix, see here.

Fusion

Custom functions can be passed to the fusion.fuse function. multiview-stitcher provides the custom fusion and weights functions with pre-transformed chunks corresponding to the transform_key passed to fusion.fuse. Only those views will be passed which contribute to the given output chunks. The elements of the input lists correspond to the different input views / tiles and conserve the order of the input views / tiles passed to fusion.fuse.

def fuse(
    ...
    transform_key: str = None,
    fusion_func: Callable = weighted_average_fusion,
    fusion_func_kwargs: dict = None,
    weights_func: Callable = None, # by default no additional fusion weights are used
    weights_func_kwargs: dict = None,
    ...

Custom fusion methods

Custom function for fusion of pre-transformed view chunks. This could implement e.g. a maximum intensity projection, a weighted average, or a multi-view deconvolution.

def custom_fusion_function(
    transformed_views: List[Array-like], # list of pre-transformed view chunks
    blending_weights: List[Array-like], # optional functional argument
    fusion_weights: List[Array-like], # optional functional argument
    **kwargs, # `fusion_func_kwargs` passed to `fusion.fuse`
) -> Array-like:

    # Fusion code here

    return fused_array

If the optional funtion arguments are not part of the function signature, the arguments will be ignored.

Example implementation: multiview_stitcher.fusion.weighted_average_fusion.

Custom weight functions

Custom function for calculating additional fusion weights passed to the fusion function as fusion_weights. This could implement e.g. a content-based weighting scheme. The function should return a list of weights, one for each view chunk.

def custom_weight_function(
    transformed_views : List[Array-like],
    blending_weights : List[Array-like],
    **kwargs, # `weights_func_kwargs` passed to `fusion.fuse`
) - > List[Array-like]:

    # Weight calculation code here

    return weights

Example implementation: multiview_stitcher.weights.content_based.

Global parameter resolution

Custom function API to be added.