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

[WIP/ENH] Add antsMotionCorr and related utilities #1812

Closed
wants to merge 60 commits into from

Conversation

rwblair
Copy link
Contributor

@rwblair rwblair commented Feb 14, 2017

Couple of interfaces to use Ants motion correction, and its statistics program. Only included inputs for the affine registration for motion correction.

@oesteban
Copy link
Contributor

Hey @rwblair, would it be very hard to re-bump this? Can you merge current master in? (maybe after S3 recovers from the hiccups)

@rwblair
Copy link
Contributor Author

rwblair commented Feb 28, 2017

@oesteban will do

@oesteban
Copy link
Contributor

oesteban commented Mar 1, 2017

While ANTsX/ANTs#419 is not solved, can we generate the ITK matrices manually?:

  • CSV file has 6 parameters - generate an Euler3DTransform file (see the # Transform <index> entry, that would be associated with the timepoint):
    #Insight Transform File V1.0
    #Transform 0
    Transform: Euler3DTransform_double_3_3
    Parameters: -0.28025704622268 -0.0066158948466181755 -0.0005159910651855171  0.4772340655326843 4.694962024688721 -9.615015983581543
    FixedParameters: 3.5478134155273438 14.090387344360352 0.7471063733100891
    
    #Transform 1
    Transform: Euler3DTransform_double_3_3
    Parameters: -0.18025704622268 -0.016158948466181755 -0.0002159910651855171  1.4772340655326843 2.694962024688721 -19.615015983581543
    FixedParameters: 3.5478134155273438 14.090387344360352 0.7471063733100891
    
  • CSV file has 12 parameters:
    #Insight Transform File V1.0
    #Transform 0
    Transform: AffineTransform_double_3_3
    Parameters: 0.9997254014015198 -0.01978115923702717 -0.012558568269014359 0.022292371839284897 0.9680354595184326 0.24982060492038727 0.007215398363769054 -0.250031977891922 0.9682106971740723 -2.5178310871124268 4.0089569091796875 -32.092098236083984
    FixedParameters: 3.5478134155273438 14.090387344360352 0.7471063733100891
    

The FixedParameters can be calculated with ndimage. The Parameters is just the parameters on the csv file

I will be able to handle you some code to include it.

@codecov-io
Copy link

codecov-io commented Mar 1, 2017

Codecov Report

Merging #1812 into master will increase coverage by 0.75%.
The diff coverage is 69.87%.

Impacted file tree graph

@@            Coverage Diff            @@
##           master   #1812      +/-   ##
=========================================
+ Coverage   72.24%     73%   +0.75%     
=========================================
  Files        1088    1066      -22     
  Lines       55527   53645    -1882     
  Branches     7994       0    -7994     
=========================================
- Hits        40116   39162     -954     
- Misses      14145   14483     +338     
+ Partials     1266       0    -1266
Flag Coverage Δ
#smoketests ?
#unittests 73% <69.87%> (+3.15%) ⬆️
Impacted Files Coverage Δ
...pype/interfaces/ants/tests/test_spec_MotionCorr.py 100% <100%> (ø)
nipype/interfaces/ants/__init__.py 100% <100%> (ø) ⬆️
...interfaces/ants/tests/test_MotionCorr2FSLParams.py 44.73% <44.73%> (ø)
nipype/interfaces/ants/preprocess.py 67.08% <67.08%> (ø)
...pype/interfaces/ants/tests/test_auto_MotionCorr.py 92.85% <92.85%> (ø)
...interfaces/ants/tests/test_auto_MotionCorrStats.py 92.85% <92.85%> (ø)
nipype/interfaces/spm/model.py 41.76% <0%> (-29.98%) ⬇️
nipype/algorithms/rapidart.py 37.46% <0%> (-27.06%) ⬇️
nipype/interfaces/fsl/model.py 54.81% <0%> (-25.81%) ⬇️
nipype/utils/provenance.py 67.86% <0%> (-20.99%) ⬇️
... and 779 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 c26b3de...e87346b. Read the comment docs.


output_average_image = File(hash_files=False, desc="", argstr="%s",
genfile=True, exists=False, usedefault=True)
output_transform_prefix = traits.Str()
Copy link
Contributor

Choose a reason for hiding this comment

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

Please use Str from nipype.interfaces.base, and add a desc field


class AntsMotionCorrStatsOutputSpec(TraitedSpec):
''' Output spec for the antsMotionCorrStats command '''
spatial_map = File(exists=True)
Copy link
Contributor

Choose a reason for hiding this comment

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

please, add desc fields to these two outputs

output_average_image = File(hash_files=False, desc="", argstr="%s",
genfile=True, exists=False, usedefault=True)
output_transform_prefix = traits.Str()
output_warped_image = File(hash_files=False, desc="",
Copy link
Contributor

Choose a reason for hiding this comment

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

please, write desc field


metric_type = traits.Enum("CC", "MeanSquares", "Demons", "GC", "MI",
"Mattes", argstr="%s")
fixed_image = File(requires=['metric_type'], desc="")
Copy link
Contributor

Choose a reason for hiding this comment

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

missing desc


use_scales_estimator = traits.Bool(
argstr="-e %d",
default=True,
Copy link
Contributor

Choose a reason for hiding this comment

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

  • does -e need a value? I think this is just a switch (argstr='-e').
  • Please, set the default value using positional arguments (traits.Bool(True, argstr=...))

Copy link
Contributor Author

Choose a reason for hiding this comment

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

"template image.")
)

use_fixed_reference_image = traits.Bool(
Copy link
Contributor

Choose a reason for hiding this comment

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

  • does -u need a value? I think this is just a switch (argstr='-u').
  • Please, set the default value using positional arguments (traits.Bool(True, argstr=...))

Copy link
Contributor Author

Choose a reason for hiding this comment

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

"the dimensionality from the input image."
)
dimensionality = traits.Enum(3, 2, argstr='-d %d', usedefault=True,
position=0, desc=dimension_desc, default=3)
Copy link
Contributor

Choose a reason for hiding this comment

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

remove the final default=3

average_image = File(argstr='-a %s', position=1, exists=False,
desc="Average the input time series image.")

output_average_image = File(hash_files=False, desc="", argstr="%s",
Copy link
Contributor

Choose a reason for hiding this comment

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

There's no default value, but usedefault=True. Please fix (either remove usedefault or set a default value)

c2 = math.sqrt((float(x[2]) * float(x[2])) + (float(x[3]) * float(x[3])))
t2 = math.atan2(-float(x[4]), c2)
t3 = math.atan2(float(x[3]), float(x[2]))
mat = numpy.zeroes((3, 3))
Copy link
Contributor

Choose a reason for hiding this comment

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

why don't loading data with numpy.loadtxt, and then use numpy fancy indexing for all of this?


def _run_interface(self, runtime):
in_fp = open(self.inputs.matrix)
in_data = csv.reader(in_fp)
Copy link
Member

Choose a reason for hiding this comment

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

A lot of this (parsing, reordering, formatting) can be handled by numpy. How about this?

# Ants motion correction output has a single line header that we ignore
# The first column is XXX (volume index?)
in_data = np.loadtxt(self.inputs.matrix, delimiter=',', skiprows=1, usecols=range(1, 14))

translations = in_data[:, 9:]

# There might be a slightly cleaner way to do this
rotations = np.zeros((in_data.shape[0], 3))
for i, row in enumerate(in_data[:, :9]):
    rotations[i] = mat2euler(row.reshape(3, 3))

# Don't duplicate this from `_list_outputs`
parameters = self._list_outputs()['parameters']
np.savetxt(parameters, np.hstack((rotations, translations)), fmt='%.8f')
return runtime

exists=True,
desc='Motion crrection matrices to be converted into FSL style motion parameters',
mandatory=True
)
Copy link
Member

Choose a reason for hiding this comment

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

Sorry for suggesting API changes, but better before merge than after. Feel free to ignore this if I'm being too fiddly.

  1. Matrix2FSLParams doesn't really imply "ANTs MC" to me. I know this is in ants/preprocess.py, but maybe indicate the source a little more clearly? MotionCorr2FSLParams?

  2. There's a really handy nipype feature:

class Matrix2FSLParamsInputSpec:
    ants_matrix = File(exists=True, mandatory=True,
                       desc='Motion correction matrices to be converted into FSL-style motion parameters')
    fsl_params = File(name_template='%s.par', name_source='ants_matrix',
                      desc='FSL parameter file')

class Matrix2FSLParamsInputSpec:
    fsl_params = File(exists=True, desc='FSL parameter file')

This lets you entirely drop the _list_outputs function. (You'd need to make the entry in the output spec match the one in the input spec.)

  1. Also, there's a typo in "correction". And I'd use "FSL-style" instead of "FSL style".

Copy link
Contributor

Choose a reason for hiding this comment

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

@effigies I think the name_source only works for command line interfaces. (I remember working on this myself, but I don't recall having it merged).

from nipype.utils.tmpdirs import InTemporaryDirectory
from nipype.utils.filemanip import split_filename

def test_MotionCorr2FSLParams():
with InTemporaryDirectory():
cwd = os.getcwd()
fsl_mat_fname = "fsl_style.mat"
fp = open(fsl_mat_fname, 'w+')
Copy link
Contributor

Choose a reason for hiding this comment

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

please use numpy.savetxt to workaround encoding issues (py2/3)

"0.000000 0.000000 0.000000 1.000000\n"
)
fp.close()

in_filename = os.path.join(cwd, 'in_file.csv')
fp = open(in_filename, 'w+')
Copy link
Contributor

Choose a reason for hiding this comment

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

same as before, please use numpy.savetxt

@oesteban oesteban changed the title [ENH] Add ants motion corr [WIP/ENH] Add antsMotionCorr and related utilities Apr 30, 2017
@effigies
Copy link
Member

@rwblair Do you think you could merge master and update the auto-tests?

@effigies
Copy link
Member

This pull request is "orphaned," which means it has been deemed to be abandoned by its original author. Orphaned pull requests have not been rejected, and we hope that if a user sees one that will meet their needs with a little work, that they will fork it and open a new pull request (or, in the case of the original author, reopen the original PR).

We ask that all adopted PRs be updated to merge or rebase the current master. If you would like to adopt a PR and need help getting started, any of a number of contributors will be happy to help.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants