Skip to main content

Anatomical space conventions made easy

Project description

Python Version PyPI Downloads Wheel Development Status Tests codecov Code style: black Imports: isort pre-commit Contributions Twitter License: GPL v3 DOI

brainglobe-space

Anatomical space conventions made easy.

Working with anatomical images, one often encounters the problem of matching the orientation of stacks with different conventions about axes orientation and order. Moreover, when multiple swaps and flips are involved, it can be annoying to map the same transformations to volumes and points (e.g., coordinates or meshes).

brainglobe-space provides a neat way of defining an anatomical space, and of operating stacks and point transformations between spaces.

If you use brainglobe-space for your analyses, please cite its Zenodo DOI https://zenodo.org/record/4552537#.YDAFzi1Q2Rs!

Installation

You can install brainglobe-space with:

pip install brainglobe-space

Usage

To define a new anatomical space, it is sufficient to give the directions of the stack origin position:

source_origin = ("Left", "Superior", "Anterior")
target_origin = ("Inferior", "Posterior", "Right")

A stack can be then easily transformed from the source to the target space:

import brainglobe_space as bg
import numpy as np
stack = np.random.rand(3, 2, 4)

mapped_stack = bg.map_stack_to(source_origin, target_origin, stack)

The transformation is handled only with numpy index operations; i.e., no complex image affine transformations are applied. This is often useful as the preparatory step for starting any kind of image registration.

A shortened syntax can be used to define a space using initials of the origin directions:

mapped_stack = bg.map_stack_to("lsa", "ipr", stack)

NOTE

When you work with a stack, the origin is the upper left corner when you show the first element stack[0, :, :] with matplotlib or when you open the stack with ImageJ. First dimension is the one that you are slicing, the second the height of the image, and the third the width of the image.


The AnatomicalSpace class

Sometimes, together with the stack we have to move a set of points (cell coordinates, meshes, etc.). This introduces the additional complexity of keeping track, together with the axes swaps and flips, of the change of the origin offset.

To handle this situation, we can define a source space using the AnatomicalSpace class, specifying also the stack shape:

stack = np.random.rand(3, 2, 4)  # a stack in source space
annotations = np.array([[0, 0, 0], [2, 1, 3]])  # related point annotations

source_space = bg.AnatomicalSpace(target_origin, stack.shape)

mapped_stack = source_space.map_stack_to("ipr", stack)  # transform the stack
mapped_annotations = source_space.map_points_to("ipr", annotations)  # transform the points

The points are transformed through the generation of a transformation matrix. Finally, if we want to log this matrix (e.g., to reconstruct the full transformations sequence of a registration), we can get it:

target_space = bg.AnatomicalSpace("ipr", stack.shape)
transformation_matrix = source_space.transformation_matrix_to(target_space)
# equivalent to:
transformation_matrix = source_space.transformation_matrix_to("ipr", stack.shape)

The target get always be defined as a bg.AnatomicalSpace object, or a valid origin specification plus a shape (the shape is required only if axes flips are required).

Matching space resolutions and offsets

The AnatomicalSpace class can deal also with stack resampling/padding/cropping. This requires simply specifying values for resolutions and offsets when instantiating a AnatomicalSpace object. Once that is done, using AnatomicalSpace.transformation_matrix_to creating affine transformation matrices from one space to the other will be a piece of cake!

source_space = bgs.AnatomicalSpace("asl", resolution=(2, 1, 2), offset=(1, 0, 0))
target_space = bgs.AnatomicalSpace("sal", resolution=(1, 1, 1), offset=(0, 0, 2))
source_space.transformation_matrix_to(target_space)

Moreover, we can now use those space objects to resample stacks, and to generate stacks matching a target shape with the correct padding/cropping simply by specifying a target offset:

source_space = bgs.AnatomicalSpace("asl", resolution=(2, 1, 2), offset=(1, 0, 0))
target_space = bgs.AnatomicalSpace("asl", resolution=(1, 1, 1), shape=(5, 4, 2))  # we need a target shape
source_space.transformation_matrix_to(target_space, stack, to_target_shape=True)

Easy iteration over projections

Finally, another convenient feature of BGSpace is the possibility of iterating easily through the projections of the stack and generate section names and axes labels:

sc = bg.AnatomicalSpace("asl")  # origin for the stack to be plotted

for i, (plane, labels) in enumerate(zip(sc.sections, sc.axis_labels)):
    axs[i].imshow(stack.mean(i))

    axs[i].set_title(f"{plane.capitalize()} view")
    axs[i].set_ylabel(labels[0])
    axs[i].set_xlabel(labels[1])

Projection illustrations

Contributing

Contributions are very welcome. Please see the developers guide.

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

brainglobe_space-1.0.2.tar.gz (14.9 kB view details)

Uploaded Source

Built Distribution

brainglobe_space-1.0.2-py3-none-any.whl (11.2 kB view details)

Uploaded Python 3

File details

Details for the file brainglobe_space-1.0.2.tar.gz.

File metadata

  • Download URL: brainglobe_space-1.0.2.tar.gz
  • Upload date:
  • Size: 14.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/5.0.0 CPython/3.12.3

File hashes

Hashes for brainglobe_space-1.0.2.tar.gz
Algorithm Hash digest
SHA256 5706f8b921d747c059120353b34cd67f006facc78d0eedea6dc4144380e85dcf
MD5 11169377594a8401e08f7e7a45bfd5e9
BLAKE2b-256 62c32553bfc856f87b52a127e2f58ae23857501dfcb5a4dd25645d3f7d455474

See more details on using hashes here.

File details

Details for the file brainglobe_space-1.0.2-py3-none-any.whl.

File metadata

File hashes

Hashes for brainglobe_space-1.0.2-py3-none-any.whl
Algorithm Hash digest
SHA256 627e95703c29e695992afc9fe8809e94b20b3b3e9349c02ac80bc2b6080a14c8
MD5 d33c27f8ab3b407e7ced9911a1358ae5
BLAKE2b-256 01a54f37550aafd9adf50608f9fa609cad2c30ca554887474efe25a1f99eb8ed

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page