Piping Images to the Loader

Subtomogram alignment usually requires a template and mask images, with appropriate pre-processing. In acryo, this kind of workflow is provided as “Image Provider” and “Image Converter”, and they can directly passed to the template or mask arguments in alignment functions.

Image Provider

An image provider is an object that provide an image when called. Currently, all the image providers are named starting with from_.

Provide an image from a file

The most commonly useful image provider is the image reading pipeline from_file().

from acryo import SubtomogramLoader
from acryo.pipe import from_file

loader = SubtomogramLoader(image, molecules, scale=0.27)  # create a loader

aligned = loader.align(
    template=from_file("path/to/template.mrc"),
)

Image scale (nm/pixel) of the template image will be extracted from the image metadata. If you want to provide it manually, you can pass the second argument.

aligned = loader.align(
    template=from_file("path/to/template.mrc", 0.18)
)

Note

The reason why we use a pipeline here is that the template image has to be rescaled differently for different images. Indeed, an image provider is a function that takes a float value as an input and returns an image.

provider = from_file("path/to/template.mrc")
type(provider(0.27))  # -> numpy.ndarray

Provid an image from an array

If you already have an image array, you can use from_array() to create a provider. The input array will be properly rescaled considering the scale argument.

from acryo.pipe import from_array
arr = np.zeros((10, 10, 10))
aligned = loader.align(
    template=from_array(arr, scale=0.18)
)

Image Converter

An image converter is an object that convert an image to another. This pipeline is usually used for the mask argument in alignment functions. When an image converter is passed, mask images will be generated from the template image using the converter.

from acryo import SubtomogramLoader
from acryo.pipe import from_file, soft_otsu

loader = SubtomogramLoader(image, molecules, scale=0.27)  # create a loader

aligned = loader.align(
    template=from_file("path/to/template.mrc"),
    mask=soft_otsu(sigma=2.0, radius=1.0),
)

What is actually happening here is,

# created by user
reader_function = from_file("path/to/template.mrc")
soft_otsu_function = soft_otsu(sigma=2.0, radius=1.0)

# images are generated inside the alignment method
template = reader_function(0.27)
mask = soft_otsu_function(template, 0.27)

Custom Pipelines

To define custom pipelines, you can use decorators provider_function() and converter_function().

from acryo.pipe import provider_function, converter_function

# the first argument of a provider function must be a float
@provider_function
def my_provider_function(scale: float, arg0, arg1=0):
    # do something
    return image

# the first and the second argument of a converter function must be
# an array and a float respectively
@converter_function
def my_converter_function(image: np.ndarray, scale: float, arg0, arg1=0):
    # do something
    return image

In both cases, the first one or two arguments are to be provided inside a loader. You can create a pipeline by calling these function without the first argument(s).

from acryo import SubtomogramLoader

loader = SubtomogramLoader(image, molecules, scale=0.27)  # create a loader

aligned = loader.align(
    template=my_provider_function(arg0, arg1=0),
    mask=my_converter_function(arg0, arg1=0),
)

Note

These decorators are similar to toolz.curry().

Composing Pipelines

Pipelines can be composed by @ or compose().

from acryo.pipe import gaussian_filter, from_file, soft_otsu

# `converter * provider` is a provider
# Functions will be called in "reading image -> filtering" order
composed = gaussian_filter(2.0) @ from_file("path/to/template.mrc")
composed(0.27)  # -> numpy.ndarray

# `converter * converter` is a converter
# Functions will be called in "soft Otsu -> filtering" order
composed = gaussian_filter(2.0) @ soft_otsu(sigma=2.0, radius=1.0)
composed(np.zeros((4, 4, 4)))  # -> numpy.ndarray