Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Basic functionality #14

Merged
merged 47 commits into from
Nov 28, 2023
Merged
Show file tree
Hide file tree
Changes from 44 commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
e098aad
Added default parameter sets to be used for transforms (from brainreg…
Oct 10, 2023
0adedfa
Basic magicgui that can import an atlas, translate the atlas/sample, …
Oct 10, 2023
8265262
Added a button to reset the image back to origin
Oct 10, 2023
8f37fad
Added the ability to rotate the image and reset back to original state
Oct 10, 2023
ab375f8
Added start alignment button
Oct 12, 2023
d0bf17c
Added start alignment button
Oct 12, 2023
ce73b7b
Merge remote-tracking branch 'origin/basic-functionality' into basic-…
Oct 12, 2023
d92810c
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Oct 12, 2023
ed93f0c
Transitioning basic function to qpty directly. Widget in registration…
Oct 13, 2023
65c04a6
Merge remote-tracking branch 'origin/basic-functionality' into basic-…
Oct 13, 2023
d53696f
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Oct 13, 2023
7297aec
Napari image layer is now rotated around the center not at origin
Oct 16, 2023
2125849
Tests for setup_parameter_object done
Oct 17, 2023
15a6e3e
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Oct 17, 2023
35d39f0
Wrote basic tests for registration_widget and register
IgorTatarnikov Oct 24, 2023
5ee9e99
Re-factored the core registration_widget.py to split off each individ…
IgorTatarnikov Oct 24, 2023
4a7de5f
Added a run settings widget to allow selection of transform types and…
IgorTatarnikov Oct 24, 2023
d141831
Added tabs on the left side of the main widget, parameter_list_view r…
IgorTatarnikov Oct 24, 2023
6fd7270
Can dynamically load default values from the 3 provided sources and l…
IgorTatarnikov Oct 24, 2023
e635d81
Param dictionaries are updated when fields are altered in the table t…
IgorTatarnikov Oct 25, 2023
d7e072f
Parameter table now expands when new entries are added
IgorTatarnikov Oct 25, 2023
b0dea23
Fixed merge conflicts with renaming main
IgorTatarnikov Nov 1, 2023
72259cb
Plugin runs successfully after renaming
IgorTatarnikov Nov 1, 2023
f015b7a
Param dictionaries passed to the backend directly
IgorTatarnikov Nov 2, 2023
44c0d02
First version of transform selection widget allowing arbitrary number…
IgorTatarnikov Nov 3, 2023
eb635e8
Each column now dynamically imports the correct default file based on…
IgorTatarnikov Nov 3, 2023
b668c7e
Parameters are now read as lists from files, arbitrary numbers of par…
IgorTatarnikov Nov 6, 2023
89065b2
Moving image adjusts immediately after values are entered, removed ad…
IgorTatarnikov Nov 7, 2023
cc1ec57
When reading parameter files anything after a '\' will now be discard…
IgorTatarnikov Nov 8, 2023
5e93b54
Updated tests for braingblobe_registration/register.py, added tests f…
IgorTatarnikov Nov 9, 2023
381e2b9
Added tests for brainglobe_registration/widgets/select_images_view.py
IgorTatarnikov Nov 9, 2023
fb0dc0e
Started tests for brainglobe_registration/widgets/parameter_list_view.py
IgorTatarnikov Nov 9, 2023
6945993
Finished tests for brainglobe/registration/widgets/parameter_list_vie…
IgorTatarnikov Nov 10, 2023
f9e1d90
Started tests for transform_select_view.py
IgorTatarnikov Nov 10, 2023
8b51abc
Updating README.md
IgorTatarnikov Nov 22, 2023
c3db983
Update README.md
IgorTatarnikov Nov 22, 2023
b6eadfc
Updated README.md
IgorTatarnikov Nov 23, 2023
63de272
Added tests, added dynamic fetching for sample selection
IgorTatarnikov Nov 23, 2023
1cef635
Update README.md
IgorTatarnikov Nov 23, 2023
beaa9ad
Refactored test_registration_widget.py to account for funcitons movin…
IgorTatarnikov Nov 24, 2023
b325d56
Fixed line lengths
IgorTatarnikov Nov 24, 2023
a19a95c
WIP transforming annotations after registration
IgorTatarnikov Nov 24, 2023
1e7de58
WIP transform annotations after registration
IgorTatarnikov Nov 24, 2023
b188101
Transformed annotation and boundaries images from atlas to sample space
IgorTatarnikov Nov 27, 2023
9614ce8
Registered boundaries are now added as an image layer, boundaries ove…
IgorTatarnikov Nov 28, 2023
cdd5f1d
Changed the source link in the widget header
IgorTatarnikov Nov 28, 2023
77c28c9
Removed tutorial section of the header
IgorTatarnikov Nov 28, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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