RegistrationInfo classes

RegistrationInfo classes are the interface to registration that are used in SiffPy. The point of this class is that there are many registration methods one might want to use, but most of them don’t accept a .siff file. If you convert it to a .tiff file, you usually end up duplicating your data and you also lose the FLIM data. So these classes are used to bridge your .siff file’s intensity data to a format palatable for registration and then retain the way that the images were warped so that the transformations can be applied to photons in the .siff file.

Core implementation

SiffIO frame objects perform registration during reads, meaning they accept an argument registration_dict : Dict[int, Tuple[int,int]] to functions like get_frames(...), where each key is the index of a frame and each value is the pixelwise shifts in the y and x direction respectively. This means that the current implementations only perform rigid registration – future implementations may permit non-rigid registration, but it will be more complicated to store (especially without duplicating the whole file the way many pipelines do). The additional latency in rigid registration of frames as they are read is nearly-negligible, so I have not spent time worrying about implementing duplicative-type registration methods that are fixed. TODO: provide this option?

Any RegistrationInfo class must define the following methods:

  • register(self, siffio : SiffIO, *args, alignment_color_channel : int =0, **kwargs)->None:

    This function is usually the one called on a file opened by a _siffio<``SiffIO`>` object. It accepts whatever other arguments and keyword arguments are needed to perform the registration. It should then modify the SiffIO object in place to store the registration parameters, e.g. in a reference_frames or yx_shifts parameter.

Any RegistrationInfo class can, but is not required to define the following class attributes:

  • multithreaading_compatible : bool

    multithreaading_compatible defines whether or not you can run the register method outside of the main thread. Some packages, e.g. suite2p, do not permit this, because they use multithreading internally already and some of their tools fail in nested threads

  • backend : RegistrationType

    The registration_type<``RegistrationType`>` enum defined in registration_info.py enumerates the list of implemented core RegistrationInfo classes and provides typical str names for them, making it easier for automated code inspection to generate GUI tools (as in siff-napari) and providing aliases that can be stored in metadata to reconstruct the class of tool being used (as in the base class’s load method).

Saving and loading

registration_info_abc<``RegistrationInfo`>` classes are designed to be saved and loaded from disk. The RegistrationInfo base class provides a save and load_as_dict method that stores the basic paremeters in a .h5 file (with no custom suffix, in this case). The stored attributes are:

  • filename

    The filename of the source .siff file. This only saves the stem (e.g. a file named a_long_custom_path/in_a_private_directory/on_a_machine_that_deanonymizes_the_user/imaging.siff will be stored as imaging) – it’s not intended to perfectly uniquely identify a file, but provide a reminder.

  • registration_type

    A string that can be mapped using the registration_type<``RegistrationType`>` Enum to the class of RegistrationInfo that was used to register the file.

  • registration_color

    The color channel used for registration

  • yx_shifts

    The framewise shifts in the y and x direction for that frame, stored as a Group with h5py. The Datasets stored are: - frame_index the indices for stored frames - shift_values tuples of (y,x) shifts - reference_frames the reference frames used for registration, if any

Rather than a direct load class function or staticmethod, this package uses load_as_dict to return a dict object which can be parsed (and passed through inspection tools) to determine the class of RegistrationInfo (and reinstantiate it if needed). This is partly to get around needing a SiffIO object if you don’t need to work directly with a file anymore and partly to make it easy for others to use the objects without learning to use this specific framework if they want…

class siffpy.core.utils.registration_tools.registration_info.RegistrationType(value)

Bases: Enum

An enumeration.

Average = 'average'
Caiman = 'caiman'
Other = 'other'
Siffpy = 'siffpy'
Suite2p = 'suite2p'
class siffpy.core.utils.registration_tools.registration_info.RegistrationInfo(siffio: SiffIO, im_params: ImParams)

Bases: ABC

Base class for all Registration implementations

REGISTRATION_INFO_SUFFIX = '.h5'
align_to_reference(images: ndarray, z_plane: int) Tuple[int, int]
assign_siffio(siffio: SiffIO)

Required to call if you load a RegistrationInfo from a file and want to use new frames.

backend: RegistrationType = 'siffpy'
from_dict(dict: Dict)
classmethod load_as_dict(path: str | Path) dict

Returns a dict that can be used to instantiate a RegistrationInfo subclass

multithreading_compatible: bool = True
abstract register(siffio: SiffIO, *args, alignment_color_channel: int = 0, **kwargs)

Register a virtual subclass of an ABC.

Returns the subclass, to allow usage as a class decorator.

property registration_type: RegistrationType
save(save_path: str | Path | None = None)

Saves the RegistrationInfo object to save_path

# Arguments

  • save_pathPathLike

    The path to save the RegistrationInfo object to. If None, saves to the same directory as the original file, down a level in a directory with the same name as the original file.

class siffpy.core.utils.registration_tools.suite2p.Suite2pRegistrationInfo(siffio: SiffIO, im_params: ImParams)

Bases: RegistrationInfo

align_to_reference(image: ndarray, z_plane: int) Tuple[int, int]
backend: RegistrationType = 'suite2p'
multithreading_compatible: bool = False
register(siffio: SiffIO, *args, alignment_color_channel: int = 0, **kwargs)

Registers individual planes using suite2p’s registration method.

If a kwarg called ops is provided, that’s passed to suite2p’s registration_wrapper function. Otherwise, the default_ops are used.

registration_params = {'align_by_chan2': <Parameter "align_by_chan2: bool = False">, 'batch_size': <Parameter "batch_size: int = 500">, 'do_bidiphase': <Parameter "do_bidiphase: bool = True">, 'maxregshift': <Parameter "maxregshift: float = 0.4">, 'nimg_init': <Parameter "nimg_init: int = 300">, 'nonrigid': <Parameter "nonrigid: bool = False">, 'norm_frames': <Parameter "norm_frames: bool = True">, 'smooth_sigma': <Parameter "smooth_sigma: float = 2.0">, 'smooth_sigma_time': <Parameter "smooth_sigma_time: int = 2">, 'two_step_registration': <Parameter "two_step_registration: bool = False">}
saved_attrs = ['_ops']
class siffpy.core.utils.registration_tools.siffpy.SiffpyRegistrationInfo(siffio: SiffIO, im_params: ImParams)

Bases: RegistrationInfo

A lightweight and simple version of suite2p’s registration method. Benefits from being able to use the SiffIO object, rather than needing all of the frames provided as a numpy array up front. For very large arrays, this is very helpful. For small ones, you’re likely better off using suite2p’s registration method.

align_reference_frames()
align_to_reference(image: ndarray, z_plane: int, *args, **kwargs) Tuple[int, int]
backend: RegistrationType = 'siffpy'
multithreading_compatible: bool = True
register(siffio, *args, alignment_color_channel: int = 0, num_cycles: int = 2, align_z: bool = False, **kwargs)

Registers using the siffpy registration method, which is fairly similar to suite2p’s registration method. Overview of the algorithm:

  • Sample a subset of frames, take their average

  • Take another subset of frames, find those most

correlated to the average, and take their average to use as a reference. - Align all frames to these references by finding the location of the maximum of the ratio of their FFT to the reference image’s FFT.

Each successive cycle takes the preceding one’s final alignment shifts as the starting point for creating a new reference image (from which the next batch of most-correlated frames is produced).

Keyword args are passed to siffpy.core.utils.registration_tools.siffpy.registration_method.register_frames.

Parameters

num_cycles : int

The number of cycles to run registration. This is how many times to run all of the steps enumerated above.

Calling with SiffReader

You can call the register method of a SiffReader object to perform registration:

from siffpy import SiffReader
from siffpy.core.utils.registration_tools import RegistrationType

reader = SiffReader("path/to/file.siff")
reader.register(
    registration_method = 'suite2p',
    alignment_color_channel = 0,
    batch_size = 200,
    do_bidiphase = True,
    smooth_sigma_time = 5,
    norm_frames = False
)

The convention and syntax for calling register is:

class siffpy.core.siffreader.SiffReader(filename: str | Path | None = None, open: bool = True, backend: str = 'corrosiff')

Centralized Pythonic interface to the SiffReader module implemented in C.

Designed to streamline several types of operations one might perform with a single file, so it operates by opening a file and then taking arguments that relate to that specific file, e.g. frame numbers or slice numbers, as opposed to accepting numpy arrays of frames.

register(registration_method='siffpy', save_path: str | Path | None = None, alignment_color_channel: int = 0, **kwargs) Dict

Performs image registration dependent on the registration method called

Arguments

registration_method (optional)string

String version of the RegistrationInfo class to use. Defaults to “siffpy”.

alignment_color_channelint

Color channel to use for alignment (0-indexed). Defaults to 0, the green channel, if present.

save_path (optional)PathLike

Whether or not to save the dict. Name will be as TODO

Other kwargs are passed to the registration method! If nowarn is included as a kwarg, it will suppress the zplane alignment warning.