Skip to content

Commit

Permalink
Basic functionality (#14)
Browse files Browse the repository at this point in the history
* Added default parameter sets to be used for transforms (from brainregister [IBL] or ARA)

* Basic magicgui that can import an atlas, translate the atlas/sample, and perform selected transforms with either elastix defaults or provided ARA defaults

* Added a button to reset the image back to origin

* Added the ability to rotate the image and reset back to original state

* Added start alignment button

* Added start alignment button

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* Transitioning basic function to qpty directly. Widget in registration_widget.py now uses qtpy directly to replicate the majority of _widget.py functionality.

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* Napari image layer is now rotated around the center not at origin

* Tests for setup_parameter_object done

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* Wrote basic tests for registration_widget and register

* Re-factored the core registration_widget.py to split off each individual UI component into its own file

* Added a run settings widget to allow selection of transform types and default param settings

* Added tabs on the left side of the main widget, parameter_list_view represents parameters in a table widget

* Can dynamically load default values from the 3 provided sources and load them into the parameter list view

* Param dictionaries are updated when fields are altered in the table tab view

* Parameter table now expands when new entries are added

* Plugin runs successfully after renaming

* Param dictionaries passed to the backend directly

* First version of transform selection widget allowing arbitrary number of transforms with unique defaults

* Each column now dynamically imports the correct default file based on the selection in the second column of the widget

* Parameters are now read as lists from files, arbitrary numbers of parameter maps can be run in one go

* Moving image adjusts immediately after values are entered, removed adjust image button

* When reading parameter files anything after a '\' will now be discarded to allow comments in parameter file

* Updated tests for braingblobe_registration/register.py, added tests for brainglobe_registration/widgets/adjust_moving_image.py

* Added tests for brainglobe_registration/widgets/select_images_view.py

* Started tests for brainglobe_registration/widgets/parameter_list_view.py

* Finished tests for brainglobe/registration/widgets/parameter_list_view.py

* Started tests for transform_select_view.py

* Updating README.md

* Update README.md

* Updated README.md

* Added tests, added dynamic fetching for sample selection

* Update README.md

* Refactored test_registration_widget.py to account for funcitons moving to utils

* Fixed line lengths

* WIP transforming annotations after registration

* WIP transform annotations after registration

* Transformed annotation and boundaries images from atlas to sample space

* Registered boundaries are now added as an image layer, boundaries overlaid on sample image after run

* Changed the source link in the widget header

Co-authored-by: Adam Tyson <code@adamltyson.com>

* Removed tutorial section of the header

---------

Co-authored-by: IgorTatarnikov <i.tatarnikov@ucl.ac.uk>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: Adam Tyson <code@adamltyson.com>
  • Loading branch information
4 people committed Nov 28, 2023
1 parent 19ff199 commit 53394b4
Show file tree
Hide file tree
Showing 46 changed files with 2,697 additions and 112 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -82,3 +82,6 @@ venv/

# written by setuptools_scm
**/_version.py

# Other test files
Logs/
61 changes: 48 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,29 +11,51 @@ Registration to a BrainGlobe atlas using Elastix

----------------------------------

This [napari] plugin was generated with [Cookiecutter] using [@napari]'s [cookiecutter-napari-plugin] template.

<!--
Don't miss the full getting started guide to set up your new package:
https://github.com/napari/cookiecutter-napari-plugin#getting-started
and review the napari docs for plugin developers:
https://napari.org/stable/plugins/index.html
-->

A [napari] plugin for registering images to a BrainGlobe atlas.

![brainglobe-registration](./imgs/brainglobe_registration_main.png)

## Usage

1. Open `napari`.
2. Install the plugin with `pip install git+https://github.com/brainglobe/brainglobe-registration.git`.
3. Open the widget by selecting `Plugins > BrainGlobe Registration` in the napari menu bar near the
top left of the window.
![brainglobe-registration-plugin](./imgs/brainglobe_registration_plugin_window.png)
The `BrainGlobe Registration` plugin will appear on the right hand side of the napari window.
4. Open the image you want to register in napari (a sample 2D image can be found by selecting `File > Open Sample > Sample Brain Slice`).
5. Select the atlas you want to register to from the dropdown menu.
![brainglobe-registration-atlas-selection](./imgs/brainglobe_registration_atlas_selection.png)
The atlas will appear in the napari viewer. Select the approximate `Z` slice of the atlas that you want to register to,
using the slider at the bottom of the napari viewer.
![brainglobe-registration-atlas-selection](./imgs/brainglobe_registration_atlas_selection_2.png)
6. Adjust the sample image to roughly match the atlas image.
You can do this by adjusting X and Y translation as well as rotating around the centre of the image.
You can overlay the two images by toggling `Grid` mode in the napari viewer (Ctrl+G).
You can then adjust the color map and opacity of the atlas image to make manual alignment easier.
![brainglobe-registration-overlay](./imgs/brainglobe_registration_overlay.png)
The sample image can be reset to its original position and orientation by clicking `Reset Image` in the `BrainGlobe Registration` plugin window.
7. Select the transformations you want to use from the dropdown menu. Set the transformation type to empty to remove a step.
Select from one of the three provided default parameter sets (elastix, ARA, or IBL). Customise the parameters further in the
`Parameters` tab.
8. Click `Run` to register the image. The registered image will appear in the napari viewer.
![brainglobe-registration-registered](./imgs/brainglobe_registration_registered.png)
![brainglobe-registration-registered](./imgs/brainglobe_registration_registered_stacked.png)
## Installation

You can install `brainglobe-registration` via [pip]:
We strongly recommend to use a virtual environment manager (like `conda` or `venv`). The installation instructions below
will not specify the Qt backend for napari, and you will therefore need to install that separately. Please see the
[`napari` installation instructions](https://napari.org/stable/tutorials/fundamentals/installation.html) for further advice on this.

pip install brainglobe-registration
[WIP] You can install `brainglobe-registration` via [pip]:

pip install brainglobe-registration


To install latest development version :

pip install git+https://github.com/brainglobe/brainglobe-registration.git


## Contributing

Contributions are very welcome. Tests can be run with [tox], please ensure
Expand All @@ -48,6 +70,19 @@ Distributed under the terms of the [BSD-3] license,

If you encounter any problems, please [file an issue] along with a detailed description.


## Acknowledgements

This [napari] plugin was generated with [Cookiecutter] using [@napari]'s [cookiecutter-napari-plugin] template.

<!--
Don't miss the full getting started guide to set up your new package:
https://github.com/napari/cookiecutter-napari-plugin#getting-started
and review the napari docs for plugin developers:
https://napari.org/stable/plugins/index.html
-->

[napari]: https://github.com/napari/napari
[Cookiecutter]: https://github.com/audreyr/cookiecutter
[@napari]: https://github.com/napari
Expand Down
Binary file added imgs/brainglobe_registration_atlas_selection.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added imgs/brainglobe_registration_main.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added imgs/brainglobe_registration_overlay.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added imgs/brainglobe_registration_plugin_window.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added imgs/brainglobe_registration_registered.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
8 changes: 7 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,17 @@ build-backend = "setuptools.build_meta"


[tool.setuptools_scm]
write_to = "src/bg_elastix/_version.py"
write_to = "src/brainglobe_registration/_version.py"

[tool.black]
line-length = 79

[tool.isort]
profile = "black"
line_length = 79

[tool.pytest.ini_options]
testpaths = "src/tests"
markers = [
"slow: mark test as slow"
]
1 change: 1 addition & 0 deletions setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ install_requires =
qtpy
itk-elastix
bg-atlasapi
pytransform3d

python_requires = >=3.8
include_package_data = True
Expand Down
21 changes: 0 additions & 21 deletions src/brainglobe_registration/_tests/test_widget.py

This file was deleted.

31 changes: 0 additions & 31 deletions src/brainglobe_registration/_widget.py

This file was deleted.

132 changes: 93 additions & 39 deletions src/brainglobe_registration/elastix/register.py
Original file line number Diff line number Diff line change
@@ -1,66 +1,120 @@
import itk
import numpy as np
from bg_atlasapi import BrainGlobeAtlas
from typing import List


def get_atlas_by_name(atlas_name: str) -> BrainGlobeAtlas:
"""
Get a BrainGlobeAtlas object by its name.
Parameters
----------
atlas_name : str
The name of the atlas.
Returns
-------
BrainGlobeAtlas
The BrainGlobeAtlas object.
"""
atlas = BrainGlobeAtlas(atlas_name)

return atlas


def run_registration(
fixed_image,
atlas_image,
moving_image,
rigid=True,
affine=True,
bspline=True,
affine_iterations="2048",
log=False,
):
annotation_image,
parameter_lists: List[tuple[str, dict]] = None,
) -> tuple[np.ndarray, itk.ParameterObject, np.ndarray]:
"""
Run the registration process on the given images.
Parameters
----------
atlas_image : np.ndarray
The atlas image.
moving_image : np.ndarray
The moving image.
annotation_image : np.ndarray
The annotation image.
parameter_lists : List[tuple[str, dict]], optional
The list of parameter lists, by default None
Returns
-------
np.ndarray
The result image.
itk.ParameterObject
The result transform parameters.
"""
# convert to ITK, view only
fixed_image = itk.GetImageViewFromArray(fixed_image).astype(itk.F)
atlas_image = itk.GetImageViewFromArray(atlas_image).astype(itk.F)
moving_image = itk.GetImageViewFromArray(moving_image).astype(itk.F)

# This syntax needed for 3D images
elastix_object = itk.ElastixRegistrationMethod.New(
fixed_image, moving_image
moving_image, atlas_image
)

parameter_object = setup_parameter_object(
rigid=rigid,
affine=affine,
bspline=bspline,
affine_iterations=affine_iterations,
)
parameter_object = setup_parameter_object(parameter_lists=parameter_lists)

elastix_object.SetParameterObject(parameter_object)
elastix_object.SetLogToConsole(log)

# update filter object
elastix_object.UpdateLargestPossibleRegion()

# get results
result_image = elastix_object.GetOutput()
result_transform_parameters = elastix_object.GetTransformParameterObject()
return np.asarray(result_image), result_transform_parameters
temp_interp_order = result_transform_parameters.GetParameter(
0, "FinalBSplineInterpolationOrder"
)
result_transform_parameters.SetParameter(
"FinalBSplineInterpolationOrder", "0"
)

annotation_image_transformix = itk.transformix_filter(
annotation_image.astype(np.float32, copy=False),
result_transform_parameters,
)

result_transform_parameters.SetParameter(
"FinalBSplineInterpolationOrder", temp_interp_order
)

return (
np.asarray(result_image),
result_transform_parameters,
np.asarray(annotation_image_transformix),
)

def setup_parameter_object(
rigid=True,
affine=True,
bspline=True,
affine_iterations="2048",
):

def setup_parameter_object(parameter_lists: List[tuple[str, dict]] = None):
"""
Set up the parameter object for the registration process.
Parameters
----------
parameter_lists : List[tuple[str, dict]], optional
The list of parameter lists, by default None
Returns
-------
itk.ParameterObject
The parameter object.#
"""
parameter_object = itk.ParameterObject.New()

if rigid:
parameter_map_rigid = parameter_object.GetDefaultParameterMap("rigid")
parameter_object.AddParameterMap(parameter_map_rigid)

if affine:
parameter_map_affine = parameter_object.GetDefaultParameterMap(
"affine"
)
parameter_map_affine["MaximumNumberOfIterations"] = [affine_iterations]
parameter_object.AddParameterMap(parameter_map_affine)

if bspline:
parameter_map_bspline = parameter_object.GetDefaultParameterMap(
"bspline"
)
parameter_object.AddParameterMap(parameter_map_bspline)
for transform_type, parameter_dict in parameter_lists:
parameter_map = parameter_object.GetDefaultParameterMap(transform_type)
parameter_map.clear()

for k, v in parameter_dict.items():
parameter_map[k] = v

parameter_object.AddParameterMap(parameter_map)

return parameter_object
16 changes: 10 additions & 6 deletions src/brainglobe_registration/napari.yaml
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
name: brainglobe-registration
display_name: BrainGlobe Elastix Registration
display_name: BrainGlobe Registration
contributions:
commands:
- id: brainglobe-registration.register
python_name: brainglobe_registration._widget:register
title: BrainGlobe Elastix Registration
- id: brainglobe-registration.make_registration_widget
python_name: brainglobe_registration.registration_widget:RegistrationWidget
title: BrainGlobe Registration
sample_data:
- key: example
display_name: Sample Brain Slice
uri: src/brainglobe_registration/resources/sample_hipp.tif
widgets:
- command: brainglobe-registration.register
display_name: BrainGlobe Elastix Registration
- command: brainglobe-registration.make_registration_widget
display_name: BrainGlobe Registration

0 comments on commit 53394b4

Please sign in to comment.