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

[ENH] Registration tools #78

Open
wants to merge 15 commits into
base: master
Choose a base branch
from
Open

Conversation

dPys
Copy link
Collaborator

@dPys dPys commented Feb 11, 2020

*This new module adds a set of Dipy-based linear registration tools to dMRIprep to use for EMC. These are based on @arokem 's original API's, though have been modified to input/output NIfti1Images rather than numpy arrays, includes support for inverted transform application, and includes a new average affine utility (@oesteban -- might something like this already be available from nitransforms?).

The original API's have additionally been modified to draw the hyperparameters for 3Dtransform from several presets which are stored in coarse/precise affine/rigid templates now located in the config module.

@dPys dPys requested a review from arokem February 12, 2020 02:49
@arokem
Copy link
Collaborator

arokem commented Feb 24, 2020

This looks good to me. I think that the travis failure is because we need to up our nibabel requirements (to 3.0.1) to comply with niworkflows requirements.

@dPys
Copy link
Collaborator Author

dPys commented Feb 24, 2020

Great, I will proceed to write some unit tests for it then (unless @oesteban has any additional revision requests).

arokem added a commit to arokem/dmriprep that referenced this pull request Feb 25, 2020
Copy link
Member

@oesteban oesteban left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM.

i'd rename dmriprep/utils/register.py -> dmriprep/utils/registration.py.

Examples would be very much appreciated.

Comment on lines 31 to 54
def apply_affine(moving, static, transform_affine, invert=False):
"""Apply an affine to transform an image from one space to another.

Parameters
----------
moving : array
The image to be resampled

static : array

Returns
-------
warped_img : the moving array warped into the static array's space.

"""
affine_map = AffineMap(
transform_affine, static.shape, static.affine, moving.shape, moving.affine
)
if invert is True:
warped_arr = affine_map.transform_inverse(np.asarray(moving.dataobj))
else:
warped_arr = affine_map.transform(np.asarray(moving.dataobj))

return nb.Nifti1Image(warped_arr, static.affine)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@arokem - this is exactly one of the responsibilities of poldracklab/nitransforms which will finally be merged into nibabel when ready.

Would you like me to go through dipy and send a PR to use it (when it is closer to be merged into nibabel)?

(please check the code coverage of nitransforms... that was one of the priorities for the project).

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes - nitransforms looks solid. Do I understand correctly that it ultimately uses scipy.ndimage under the hood to do the resampling? Looks like it always does spline interpolation. What happens if you want nearest neighbors? Maybe nitransforms could use dipy.align.imaffine?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yup, it uses scipy.ndimage. You can pass in order=0 for nn interpolation 👍 .

The idea for nitransforms is to be as lightweight as possible, as it aims to be merged in nibabel (using dipy.align.imaffine would create a circular dependency, I believe).

I'll have a look into dipy.align.imaffine and potentially ask for your permission to upstream code if that makes sense.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yup. Upstreaming code from dipy.align would make sense. There are some gems in there :-)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BTW, at some point I will stop depending on scipy and implement interpolation on a single, lightweight package. Reason: allowing for 4d tensor-bspline interpolation (which might not make sense for diffusion, but will be useful in fmri).

On the diffusion side of things, such package would also include polar interpolation for gradients (and that is relevant to dmriprep). Surely dipy has something for this.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On the diffusion side of things, such package would also include polar interpolation for gradients (and that is relevant to dmriprep). Surely dipy has something for this.

I'm not sure it does... but it would be great to have.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To clarify @oesteban -- should we go ahead and drop this apply_affine function in favor of the nitransforms equivalent or should we wait to do that until the interpolation point if that has already been upstreamed?

moving, static, static_affine, moving_affine, reg, starting_affine, params0=None
):
transform = transform_centers_of_mass(static, static_affine, moving, moving_affine)
transformed = transform.transform(moving)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this mean that the registration will operate on the resampled image after initialization - @arokem ?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure I understand this question. The transform object calculates the center of mass affine. This is the line in which this is applied.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yup, in the following registration levels, you could use the affine as initialization or use the transformed image (with identity initialization). I'm pretty sure it is the first option.

If it is the first option, I don't think we really need this resampling to happen, do we?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Gotcha - yes, that is a very good point. Will also be relevant to dipy/dipy#2025

@ghost
Copy link

ghost commented Feb 27, 2020

Warnings are found on analyzing the commit 756a1ef.

1 warning:

We recommend to address them as possible, for example, update outdated dependencies, fix the tool's configuration, configure sider.yml, turn off unused tools, and so on.

If you are struggling with these errors or warnings, feel free to ask us via chat. 💬

@oesteban oesteban added this to the 0.4.0 milestone Mar 23, 2020
@codecov
Copy link

codecov bot commented Mar 24, 2020

Codecov Report

Merging #78 into master will decrease coverage by 1.01%.
The diff coverage is 52.47%.

Impacted file tree graph

@@            Coverage Diff            @@
##           master     #78      +/-   ##
=========================================
- Coverage   52.71%   51.7%   -1.02%     
=========================================
  Files          16      23       +7     
  Lines         901    1319     +418     
  Branches      111     166      +55     
=========================================
+ Hits          475     682     +207     
- Misses        425     626     +201     
- Partials        1      11      +10
Impacted Files Coverage Δ
dmriprep/utils/registration.py 35.55% <35.55%> (ø)
dmriprep/interfaces/registration.py 66.07% <66.07%> (ø)
dmriprep/config/__init__.py 56.72% <0%> (-43.28%) ⬇️
dmriprep/cli/run.py 4.1% <0%> (-26.98%) ⬇️
dmriprep/utils/vectors.py 94.37% <0%> (-5.63%) ⬇️
dmriprep/workflows/base.py 24.67% <0%> (-4.91%) ⬇️
dmriprep/interfaces/vectors.py 100% <0%> (ø) ⬆️
dmriprep/__init__.py 100% <0%> (ø) ⬆️
dmriprep/cli/parser.py 56.57% <0%> (ø)
dmriprep/config/testing.py 26.92% <0%> (ø)
... and 7 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 7e194c3...1581d67. Read the comment docs.

@pep8speaks
Copy link

pep8speaks commented Mar 24, 2020

Hello @dPys, Thank you for updating!

Cheers! There are no style issues detected in this Pull Request. 🍻 To test for issues locally, pip install flake8 and then run flake8 dmriprep.

Comment last updated at 2020-09-24 05:31:28 UTC

Copy link
Member

@oesteban oesteban left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's finish this.

dmriprep/interfaces/registration.py Outdated Show resolved Hide resolved
dmriprep/interfaces/registration.py Outdated Show resolved Hide resolved
dmriprep/interfaces/registration.py Outdated Show resolved Hide resolved
dmriprep/interfaces/registration.py Show resolved Hide resolved
dmriprep/interfaces/registration.py Outdated Show resolved Hide resolved
dmriprep/interfaces/registration.py Outdated Show resolved Hide resolved
dmriprep/interfaces/registration.py Outdated Show resolved Hide resolved
@dPys
Copy link
Collaborator Author

dPys commented Sep 24, 2020

All of your suggested changes committed @oesteban :-) Merge?

@oesteban
Copy link
Member

The new tests are failing (TravisCI). I just fixed the CircleCI failure, that's not a problem of this PR.

@oesteban oesteban modified the milestones: 0.4.0, 0.5.0 Dec 10, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants