Skip to content

Commit

Permalink
Merge pull request #158 from linum-uqam/dev-10um-tools
Browse files Browse the repository at this point in the history
Adding the 10micron option to the script
  • Loading branch information
joe-from-mtl authored Nov 28, 2023
2 parents 25bc8ee + b56c463 commit 3076b4c
Show file tree
Hide file tree
Showing 8 changed files with 118 additions and 32 deletions.
8 changes: 7 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -148,4 +148,10 @@ dmypy.json

# IDE config files
.vscode/
.idea/
.idea/

# Data
data/
*.nii
*.nii.gz
*.mat
11 changes: 11 additions & 0 deletions docs/installation.rst
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,17 @@ We recommend using Anaconda and to install m2m in a separate environment. Execut
conda activate m2m
pip install -e .
Update
======

To update the toolkit, execute the following command.

.. code-block:: bash
conda activate m2m
git pull
pip install -e . # This command is necessary only if the requirements have changed
Notes
=====

Expand Down
4 changes: 2 additions & 2 deletions m2m/control.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ def add_overwrite_arg(parser):

def add_resolution_arg(parser):
parser.add_argument('res', type=int,
choices=[25, 50, 100],
help='Resolution of the Allen files \n'
choices=[10, 25, 50, 100],
help='Resolution (in micron) of the Allen files \n'
'Please use the same resolution as '
'the transformation matrix.')

Expand Down
2 changes: 1 addition & 1 deletion m2m/version.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
# Format expected by setup.py and doc/source/conf.py: string of form "X.Y.Z"
_version_major = 0
_version_minor = 1
_version_micro = 2
_version_micro = 3
_version_extra = ''

# Construct full version string from these.
Expand Down
8 changes: 4 additions & 4 deletions scripts/m2m_compute_transform_matrix.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

"""
Compute an Affine transformation matrix for a specific resolution
in the Allen (25, 50, 100) using ANTsPyX.
in the Allen using ANTsPyX.
Thoses matrices are needed for the other scripts in order
to align Allen data on User Data Space.
Expand Down Expand Up @@ -48,7 +48,7 @@ def main():
parser = _build_arg_parser()
args = parser.parse_args()

# Verying args validity
# Checking args validity
check_input_file(parser, args.reference)
if not (args.reference).endswith(".nii") and \
not (args.reference).endswith(".nii.gz"):
Expand All @@ -64,10 +64,10 @@ def main():
# Loading User template
user_vol = load_user_template(str(args.reference))

# Pretransform volumes orientations
# Pre-transform volumes orientations
allen_reorient = pretransform_vol_PIR_UserDataSpace(allen_vol, user_vol)

# Registrating with ANTsPyX
# Registration with ANTsPyX
affine_mat = compute_transform_matrix(allen_reorient, user_vol, fixed_res=args.user_res, moving_res=args.res)

# Saving the matrix
Expand Down
55 changes: 45 additions & 10 deletions scripts/m2m_download_annotation.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,12 @@
from allensdk.core.reference_space_cache import ReferenceSpaceCache
from pathlib import Path
import SimpleITK as sitk
import nrrd
import numpy as np
import nibabel as nib
from m2m.transform import (registrate_allen2UserDataSpace)
from m2m.util import (load_user_template,
save_nifti, )

ALLEN_RESOLUTIONS = [10, 25, 50, 100]

Expand All @@ -23,6 +29,13 @@ def _build_arg_parser():
p.add_argument("-r", "--resolution", default=100, type=int, choices=ALLEN_RESOLUTIONS,
help="Template resolution in micron. Default=%(default)s")

# Add optional arguments to align the template to the user space
p.add_argument_group("Align the template to the user space")
p.add_argument("-m", "--file_mat", default=None, type=str,
help="Path to the transform matrix (.mat)")
p.add_argument("-R", "--reference", default=None, type=str,
help="Path to the reference volume (.nii.gz)")

return p


Expand Down Expand Up @@ -64,26 +77,48 @@ def main():
# Download the brain annotations and structure information - WIP
# ID 1 is the adult mouse structure graph
rsp = rspc.get_reference_space(structure_file_name=json_file, annotation_file_name=nrrd_file)
rsp.write_itksnap_labels(str(nrrd_file), str(output_labels))
rsp.write_itksnap_labels(str(nrrd_file), str(output_labels)) # TODO: this step takes a long time, can we speed it up?

# Loading the nrrd file
vol = sitk.ReadImage(str(nrrd_file))
vol, metadata = nrrd.read(str(nrrd_file))

# Preparing the affine to align the template in the RAS+
r_mm = args.resolution / 1e3 # Convert the resolution from micron to mm
vol.SetSpacing([r_mm] * 3) # Set the spacing in mm
# Converting to PIR to RAS+
vol = np.moveaxis(vol, [0, 1, 2], [1, 2, 0])
vol = np.flip(vol, axis=1) # To move from A->P to P->A
vol = np.flip(vol, axis=2) # To move from S->I to I->S

# Apply the transform
vol = sitk.PermuteAxes(vol, (2, 0, 1))
vol = sitk.Flip(vol, (False, False, True))
vol.SetDirection([1, 0, 0, 0, 1, 0, 0, 0, 1])
# Preparing the affine
r_mm = args.resolution / 1e3 # Convert the resolution from micron to mm
affine = np.eye(4) * r_mm
affine[3, 3] = 1

# Save the volume
sitk.WriteImage(vol, str(output))
img = nib.Nifti1Image(vol, affine)
nib.save(img, str(output))

# Remove the temporary files
nrrd_file.unlink() # Removes the nrrd file
json_file.unlink()

# If the affine matrix was provided, apply it
if args.reference is not None and args.file_mat is not None:
user_vol = load_user_template(args.reference)

# Load the allen template
allen_vol = load_user_template(str(output))
allen_vol = allen_vol.get_fdata()

# Applying ANTsPyX registration
warped_vol = registrate_allen2UserDataSpace(
args.file_mat,
allen_vol,
user_vol,
allen_res=args.resolution,
smooth=False
)

# Saving the warped volume
save_nifti(warped_vol, user_vol.affine, args.output)

if __name__ == "__main__":
main()
58 changes: 46 additions & 12 deletions scripts/m2m_download_template.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,12 @@
import argparse
from allensdk.api.queries.reference_space_api import ReferenceSpaceApi
from pathlib import Path
import SimpleITK as sitk
import numpy as np
import nibabel as nib

from m2m.transform import (registrate_allen2UserDataSpace)
from m2m.util import (load_user_template,
save_nifti, )

ALLEN_RESOLUTIONS = [10, 25, 50, 100]

Expand All @@ -21,6 +26,13 @@ def _build_arg_parser():
p.add_argument("-r", "--resolution", default=100, type=int, choices=ALLEN_RESOLUTIONS,
help="Template resolution in micron. Default=%(default)s")

# Add optional arguments to align the template to the user space
p.add_argument_group("Align the template to the user space")
p.add_argument("-m", "--file_mat", default=None, type=str,
help="Path to the transform matrix (.mat)")
p.add_argument("-R", "--reference", default=None, type=str,
help="Path to the reference volume (.nii.gz)")

return p


Expand All @@ -44,24 +56,46 @@ def main():

# Downloading the template
rpa = ReferenceSpaceApi(base_uri=str(output.parent))
rpa.download_template_volume(resolution=args.resolution, file_name=nrrd_file)
vol, metadata = rpa.download_template_volume(resolution=args.resolution, file_name=nrrd_file)

# Loading the nrrd file
vol = sitk.ReadImage(str(nrrd_file))
# Converting to PIR to RAS+
vol = np.moveaxis(vol, [0, 1, 2], [1, 2, 0])
vol = np.flip(vol, axis=1) # To move from A->P to P->A
vol = np.flip(vol, axis=2) # To move from S->I to I->S

# Preparing the affine to align the template in the RAS+
# Preparing the affine
r_mm = args.resolution / 1e3 # Convert the resolution from micron to mm
vol.SetSpacing([r_mm] * 3) # Set the spacing in mm

# Apply the transform
vol = sitk.PermuteAxes(vol, (2, 0, 1))
vol = sitk.Flip(vol, (False, False, True))
vol.SetDirection([1, 0, 0, 0, 1, 0, 0, 0, 1])
affine = np.eye(4) * r_mm
affine[3, 3] = 1

# Save the volume
sitk.WriteImage(vol, str(output))
img = nib.Nifti1Image(vol, affine)
nib.save(img, str(output))
nrrd_file.unlink() # Removes the nrrd file

# If the affine matrix was provided, apply it
if args.reference is not None and args.file_mat is not None:
user_vol = load_user_template(args.reference)

# Load the allen template
allen_vol = load_user_template(str(output))
allen_vol = allen_vol.get_fdata()

# Applying ANTsPyX registration
warped_vol = registrate_allen2UserDataSpace(
args.file_mat,
allen_vol,
user_vol,
allen_res=args.resolution,
smooth=True
)

# Deleting negatives values introduced by b-spline interpolation
warped_vol[warped_vol < 0] = 0

# Saving the warped volume
save_nifti(warped_vol, user_vol.affine, args.output)


if __name__ == "__main__":
main()
4 changes: 2 additions & 2 deletions scripts/m2m_import_proj_density.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ def _build_arg_parser():
'is nearestNeighbor by default.\n'
'Using --smooth will change the method to bSpline.')
p.add_argument('--threshold', type=float, default=.5,
help='Threshold for the binarised map.')
help='Threshold for the binarized map.')
p.add_argument('--not_all', action="store_true",
help='If set, only saves the files specified')
add_resolution_arg(p)
Expand All @@ -112,7 +112,7 @@ def _build_arg_parser():
help='Save a binarized projection density map (.nii.gz)'
'with a certain --threshold.')
g.add_argument('--infos', action="store_true",
help='Save informations about the experiment (.json):\n'
help='Save information about the experiment (.json):\n'
'- Injection coordinates (MI-Brain, Allen)\n'
'- Hemisphere (L or R)\n'
'- Injection ROI\n')
Expand Down

0 comments on commit 3076b4c

Please sign in to comment.