nipy / nipype

Workflows and interfaces for neuroimaging packages
https://nipype.readthedocs.org/en/latest/
Other
742 stars 523 forks source link

antsApplyTransforms is a different result between command line and nipype #3320

Open cmpetty opened 3 years ago

cmpetty commented 3 years ago

Summary

I am warping mrtrix3 identity matrices with antsApplyTransforms. The same command on the command line versus through nipype is giving me a slightly different result. nipype interface was used on L image, command line call on the right. The calls were exactly the same as far as i can tell. Results mostly look the same, with the exception of the grey pieces of tracts in the corner. If i display these as points instead of pseudo-tubes they disappear.

image

Expected behavior

identical results

Script/Workflow details

Command line version, which looks correct:

#create base warp of template
warpinit /mnt/munin/Song/Lab/Chris/templateflow/tpl-MNI152NLin2009cAsym/tpl-MNI152NLin2009cAsym_res-02_T1w.nii.gz inv_identity_warp[].nii -force

#invwarp tracts
for i in {0..2}; do
    antsApplyTransforms -d 3 -e 0 -i inv_identity_warp${i}.nii -o inv_mrtrix_warp${i}.nii -r mean_b0.nii.gz -t ../../../../../derivatives/fmriprep/sub-0152/ses-01/anat/sub-0152_ses-01_from-MNI152NLin2009cAsym_to-T1w_mode-image_xfm.h5 -t ants_2InverseWarp.nii.gz -t [ants_1Affine.mat,1] -v 1 --default-value 2147483647;
done

#correct them and put back together
warpcorrect inv_mrtrix_warp[].nii inv_mrtrix_warp_corrected.mif -marker 2147483647 -force

#apply inv warp to tck ( puts in atlas space )
tcktransform 10k_b0_space.tck inv_mrtrix_warp_corrected.mif 10k_atlas_space.tck -force

Python version, using nipype wrapper for ants:

#create init for MNI->T1->B0
init_cmd = ['warpinit','/mnt/munin/Song/Lab/Chris/templateflow/tpl-MNI152NLin2009cAsym/tpl-MNI152NLin2009cAsym_res-02_T1w.nii.gz','inv_identity_warp[].nii','-force']
subprocess.call(init_cmd)

#apply transforms of b0 -> T1 -> precomputed T1 -> MNI
for i in range(3):
    at = ApplyTransforms()
    at.inputs.dimension = 3
    at.inputs.args = "-e 0 -v 1"
    at.inputs.float = False
    at.inputs.input_image = "inv_identity_warp%s.nii" % str(i)
    at.inputs.reference_image = "mean_b0.nii.gz"
    at.inputs.output_image = "inv_mrtrix_warp%s.nii" % str(i)
    at.inputs.transforms = ['../../../../../derivatives/fmriprep/sub-0152/ses-01/anat/sub-0152_ses-01_from-MNI152NLin2009cAsym_to-T1w_mode-image_xfm.h5','ants_2InverseWarp.nii.gz','ants_1Affine.mat']
    at.inputs.invert_transform_flags = [False,False,True]
    at.inputs.default_value = 2147483647
    print(at.cmdline)
    res = at.run()

#correct them back into 4d warp KEEP
corr_cmd = ['warpcorrect','inv_mrtrix_warp[].nii','inv_mrtrix_warp_corrected.mif','-marker','2147483647','-force']
subprocess.call(corr_cmd)

#keep
tcktr_cmd = ['tcktransform','10k_b0_space.tck','inv_mrtrix_warp_corrected.mif','10k_atlas_space.tck','-force']
subprocess.call(tcktr_cmd)

Platform details:

In [43]: from pprint import pprint; pprint(nipype.get_info())
{'commit_hash': '10388b0',
 'commit_source': 'installation',
 'networkx_version': '2.1',
 'nibabel_version': '3.0.0',
 'nipype_version': '1.6.0',
 'numpy_version': '1.18.1',
 'pkg_path': '/usr/local/lib/python3.6/site-packages/nipype-1.6.0-py3.6.egg/nipype',
 'scipy_version': '1.4.1',
 'sys_executable': '/usr/bin/python3.6',
 'sys_platform': 'linux',
 'sys_version': '3.6.8 (default, Apr  1 2020, 10:29:41) \n'
                '[GCC 4.8.5 20150623 (Red Hat 4.8.5-39)]',
 'traits_version': '4.6.0'}

In [44]: at.version
Out[44]: '2.3.4'

Execution environment

Scientific Linux 7.8 3.10.0-1160.2.2.el7.x86_64

verbose output from one antsApplyTransforms call

command line:

Using double precision for computations.
Input scalar image: inv_identity_warp0.nii
Reference image: mean_b0.nii.gz
=============================================================================
The composite transform comprises the following transforms (in order): 
  1. inverse of ants_1Affine.mat (type = AffineTransform)
  2. ants_2InverseWarp.nii.gz (type = DisplacementFieldTransform)
  3. ../../../../../derivatives/fmriprep/sub-0152/ses-01/anat/sub-0152_ses-01_from-MNI152NLin2009cAsym_to-T1w_mode-image_xfm.h5[0] (type = DisplacementFieldTransform)
  4. ../../../../../derivatives/fmriprep/sub-0152/ses-01/anat/sub-0152_ses-01_from-MNI152NLin2009cAsym_to-T1w_mode-image_xfm.h5[1] (type = AffineTransform)
=============================================================================
Default pixel value: 2.14748e+09
Interpolation type: LinearInterpolateImageFunction
Output warped image: inv_mrtrix_warp0.nii

Python:

210401-10:43:49,723 nipype.interface INFO:
     stdout 2021-04-01T10:43:49.723207:Using double precision for computations.
210401-10:43:49,723 nipype.interface INFO:
     stdout 2021-04-01T10:43:49.723207:Input scalar image: inv_identity_warp0.nii
210401-10:43:49,763 nipype.interface INFO:
     stdout 2021-04-01T10:43:49.763428:Reference image: mean_b0.nii.gz
210401-10:43:52,26 nipype.interface INFO:
     stdout 2021-04-01T10:43:52.026845:=============================================================================
210401-10:43:52,27 nipype.interface INFO:
     stdout 2021-04-01T10:43:52.026845:The composite transform comprises the following transforms (in order): 
210401-10:43:52,27 nipype.interface INFO:
     stdout 2021-04-01T10:43:52.026845:  1. inverse of ants_1Affine.mat (type = AffineTransform)
210401-10:43:52,27 nipype.interface INFO:
     stdout 2021-04-01T10:43:52.026845:  2. ants_2InverseWarp.nii.gz (type = DisplacementFieldTransform)
210401-10:43:52,27 nipype.interface INFO:
     stdout 2021-04-01T10:43:52.026845:  3. ../../../../../derivatives/fmriprep/sub-0152/ses-01/anat/sub-0152_ses-01_from-MNI152NLin2009cAsym_to-T1w_mode-image_xfm.h5[0] (type = DisplacementFieldTransform)
210401-10:43:52,27 nipype.interface INFO:
     stdout 2021-04-01T10:43:52.026845:  4. ../../../../../derivatives/fmriprep/sub-0152/ses-01/anat/sub-0152_ses-01_from-MNI152NLin2009cAsym_to-T1w_mode-image_xfm.h5[1] (type = AffineTransform)
210401-10:43:52,27 nipype.interface INFO:
     stdout 2021-04-01T10:43:52.026845:=============================================================================
210401-10:43:52,28 nipype.interface INFO:
     stdout 2021-04-01T10:43:52.028040:Default pixel value: 2.14748e+09
210401-10:43:52,28 nipype.interface INFO:
     stdout 2021-04-01T10:43:52.028040:Interpolation type: LinearInterpolateImageFunction
210401-10:43:52,678 nipype.interface INFO:
     stdout 2021-04-01T10:43:52.678686:Output warped image: inv_mrtrix_warp0.nii
cmpetty commented 3 years ago

as a follow-up, if i do the same applytransform step above through a subprocess, it comes out normal as well:

for i in range(3):
    at_cmd = ['antsApplyTransforms','-d','3','-e','0','-i','inv_identity_warp%s.nii' % str(i),
    '-o','inv_mrtrix_warp%s.nii' % str(i),'-r','mean_b0.nii.gz',
    '-t',os.path.join(dvdir,'fmriprep',subj,sess,'anat','%s_%s_from-MNI152NLin2009cAsym_to-T1w_mode-image_xfm.h5' % (subj,sess)),
    '-t','ants_2InverseWarp.nii.gz',
    '-t','[ants_1Affine.mat,1]',
    '-v','1','--default-value','2147483647']
    subprocess.call(at_cmd)
effigies commented 3 years ago

Sorry for the slow response. Could you show the result of print(at.cmdline) for comparison?

cmpetty commented 3 years ago
for i in range(3):
    at = ApplyTransforms()
    at.inputs.dimension = 3
    at.inputs.args = "-e 0 -v 1"
    at.inputs.float = False
    at.inputs.input_image = "inv_identity_warp%s.nii" % str(i)
    at.inputs.reference_image = "mean_b0.nii.gz"
    at.inputs.output_image = "inv_mrtrix_warp%s.nii" % str(i)
    at.inputs.transforms = [os.path.join(dvdir,'fmriprep',subj,sess,'anat','%s_%s_from-MNI152NLin2009cAsym_to-T1w_mode-image_xfm.h5' % (subj,sess)),'ants_2InverseWarp.nii.gz','ants_1Affine.mat']
    at.inputs.invert_transform_flags = [False,False,True]
    at.inputs.default_value = 2147483647
    print(at.cmdline)
##     res = at.run()

results in:

antsApplyTransforms -e 0 -v 1 --default-value 2.14748e+09 --dimensionality 3 --float 0 --input inv_identity_warp0.nii --interpolation Linear --output inv_mrtrix_warp0.nii --reference-image mean_b0.nii.gz --transform /mnt/munin2/Lee/HCPcovid.01/Analysis/derivatives/fmriprep/sub-0137/ses-02/anat/sub-0137_ses-02_from-MNI152NLin2009cAsym_to-T1w_mode-image_xfm.h5 --transform ants_2InverseWarp.nii.gz --transform [ ants_1Affine.mat, 1 ]

antsApplyTransforms -e 0 -v 1 --default-value 2.14748e+09 --dimensionality 3 --float 0 --input inv_identity_warp1.nii --interpolation Linear --output inv_mrtrix_warp1.nii --reference-image mean_b0.nii.gz --transform /mnt/munin2/Lee/HCPcovid.01/Analysis/derivatives/fmriprep/sub-0137/ses-02/anat/sub-0137_ses-02_from-MNI152NLin2009cAsym_to-T1w_mode-image_xfm.h5 --transform ants_2InverseWarp.nii.gz --transform [ ants_1Affine.mat, 1 ]

antsApplyTransforms -e 0 -v 1 --default-value 2.14748e+09 --dimensionality 3 --float 0 --input inv_identity_warp2.nii --interpolation Linear --output inv_mrtrix_warp2.nii --reference-image mean_b0.nii.gz --transform /mnt/munin2/Lee/HCPcovid.01/Analysis/derivatives/fmriprep/sub-0137/ses-02/anat/sub-0137_ses-02_from-MNI152NLin2009cAsym_to-T1w_mode-image_xfm.h5 --transform ants_2InverseWarp.nii.gz --transform [ ants_1Affine.mat, 1 ]

then put them back together:

#correct them back into 4d warp KEEP
corr_cmd = ['warpcorrect','inv_mrtrix_warp[].nii','inv_mrtrix_warp_corrected.mif','-marker','2147483647','-force']
subprocess.call(corr_cmd)