Using Custom Functions in FLoRIN

Because of the wide array of computer vision methods, FLoRIN comes with utilities to prepare functions. This section will go over the two cases for preparing functions: without parameters, and with parameters.

Single-Argument Functions

Functions with a single argument (e.g., those taking a single image or a single numpy array and no other arguments) require no additional preparation. This example shows how to incorporate np.squeeze into a pipeline:

import florin
import florin.conncomp as conncomp
import florin.morphology as morphology
import florin.thresholding as thresholding

import numpy as np

# Set up a serial pipeline
pipeline = florin.Serial(
    # Load in the volume from file
    florin.load(),

    # Tile the volume into overlapping 64 x 64 x 10 subvolumes
    florin.tile(shape=(10, 64, 64), stride=(10, 32, 32)),

    # Remove any axes with shape 1. Simply pass np.squeeze without invoking
    np.squeeze,

    # Threshold with NDNT
    thresholding.ndnt(shape=(10, 64, 64), threshold=0.3),

    # Clean up a little bit
    morphology.binary_opening(),

    # Save the output to a TIFF stack
    florin.save('segmented.tiff')
)

# Run the pipeline
segmented = pipeline()

Note that np.squeeze is not invoked. The function is just passed to the pipeline as-is, and FLoRIN will call it later.

Parameterizing Functions with florinate

Functions with parameters can also be used within FLoRIN by wrapping them with florin.florinate. This function records any parameters passed while setting up the pipeline and then automatically applies them when the data comes through (i.e. partial function application):

.. content-tabs::

Decorator

import florin
import florin.conncomp as conncomp
import florin.morphology as morphology
import florin.thresholding as thresholding

# Create the custom function and decorate it with ``florinate``
@florin.florinate
def scale(image, scalar=1):
    """Scale an images values by some number.

    Parameters
    ----------
    image : array_like
    scale : int or float

    Returns
    -------
    image * scale
    """
    return image * scale

# Set up a serial pipeline
pipeline = florin.Serial(
    # Load in the volume from file
    florin.load(),

    # Tile the volume into overlapping 64 x 64 x 10 subvolumes
    florin.tile(shape=(10, 64, 64), stride=(10, 32, 32)),

    # Add the custom function to the pipeline
    scale(scalar=2.0),

    # Threshold with NDNT
    thresholding.ndnt(shape=(10, 64, 64), threshold=0.3),

    # Clean up a little bit
    morphology.binary_opening(),

    # Save the output to a TIFF stack
    florin.save('segmented.tiff')
)

# Run the pipeline
segmented = pipeline()

In-Line

import florin
import florin.conncomp as conncomp
import florin.morphology as morphology
import florin.thresholding as thresholding

# Create the custom function
def scale(image, scalar=1):
    """Scale an images values by some number.

    Parameters
    ----------
    image : array_like
    scale : int or float

    Returns
    -------
    image * scale
    """
    return image * scale

# Set up a serial pipeline
pipeline = florin.Serial(
    # Load in the volume from file
    florin.load(),

    # Add the custom function to the pipeline and wrap it in ``florinate``
    florin.florinate(scale)(scalar=2.0),

    # Tile the volume into overlapping 64 x 64 x 10 subvolumes
    florin.tile(shape=(10, 64, 64), stride=(10, 32, 32)),

    # Add the custom function to the pipeline
    scale(scalar=2.0),

    # Threshold with NDNT
    thresholding.ndnt(shape=(10, 64, 64), threshold=0.3),

    # Clean up a little bit
    morphology.binary_opening(),

    # Save the output to a TIFF stack
    florin.save('segmented.tiff')
)

# Run the pipeline
segmented = pipeline()

florinate will handle any number of arguments and keyword arguments passed to it, applying them every time the function is called during the pipeline.

Why florinate?

The functools module already has an implementation of partial functions (functools.partial), the the natural question is: why reinvent the wheel? When building FLoRIN, we noticed that most computer vision functions take the image as the first argument; functools.partial, however will only append arguments when called. florinate solves this by prepending the argument(s) when called, lining up with the norm for computer vision APIs.

If a custom function takes the image as the last argument, functools.partial can be used in place of florinate with no changes.