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

Tag 3.0 RC2 #1052

Merged
merged 193 commits into from Aug 8, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
193 commits
Select commit Hold shift + click to select a range
0f2c63c
initial commit
bjeurissen Oct 1, 2015
bf14e02
added configure
bjeurissen Oct 1, 2015
04e381c
Proposed solution for Viewing each volume of a 4D image in Lightbox m…
rtabbara Jun 28, 2016
ee10ef7
Merge branch 'master' into lightbox_4d
rtabbara Jun 28, 2016
ca8df74
Add GL::Texture cache_copy
rtabbara Jun 28, 2016
52f273b
Lightbox 4d: Cleaning up
rtabbara Jun 28, 2016
2a50bd7
Merge branch 'master' into lightbox_4d
draffelt Jul 22, 2016
5f411bd
Merge branch 'master' into lightbox_4d
draffelt Sep 5, 2016
ef84819
Merge branch 'master' into lightbox_4d
draffelt Sep 7, 2016
6fdb30a
Added command options for mrview:
Apr 10, 2017
8dcedb9
Merge branch 'master' of https://github.com/LeeReidCSIRO/mrtrix3 into…
jdtournier Apr 10, 2017
39cde33
Tidy up indentation to use 2 whitespaces instead of tabs
jdtournier Apr 10, 2017
111cba8
Merge branch 'master' into master
thijsdhollander Apr 11, 2017
c2d31dc
Split tractography.tsf commandline arguments into three
Apr 11, 2017
a83b574
Merge branch 'master' of https://github.com/LeeReidCSIRO/mrtrix3
Apr 11, 2017
53e3448
MRView tractography tool: refactored open tractogram (through gui and…
May 18, 2017
eabe41c
Merge branch 'master' into master
May 18, 2017
32abb92
Fixed build errors introduced by merge with MRtrix3 main repo
May 18, 2017
da512aa
minor fixes for Eigen 3.3 compatibility
jdtournier May 19, 2017
3db1bb2
Remove #include <vector> usages
Lestropie May 19, 2017
6f9e063
replace MR::vector with just vector
jdtournier May 23, 2017
1b50c86
Merge remote-tracking branch 'github/no_include_stl_vector' into LeeR…
jdtournier May 23, 2017
4b8eba7
Merge branch 'master' into master
jdtournier May 23, 2017
dcb90d4
check_memalign: "using namespace std;" also causes a failure
jdtournier May 23, 2017
46ed2b5
Merge branch 'master' into master
May 26, 2017
2c51ce1
tensor2metric: add option to sort eigenvalues by absolute value
jdtournier Jun 16, 2017
be91280
Merge remote-tracking branch 'github/master' into tensor2metric_sort_…
jdtournier Jun 20, 2017
ad05b48
mt_lognorm: Adding new command for intensity normalisation of multi-t…
rtabbara Jun 23, 2017
c746f48
mt_lognorm -> mtlognorm
rtabbara Jun 23, 2017
4246822
mtlognorm: Zero-clamping tissue-image inputs and outputs
rtabbara Jun 23, 2017
80e4345
Merge remote-tracking branch 'github/master' into tensor2metric_sort_…
jdtournier Jun 23, 2017
350d1ad
tensor2metric: fix default eigenvalue/vector selection
jdtournier Jun 23, 2017
b6ad220
Merge remote-tracking branch 'origin/master' into mtlognorm
thijsdhollander Jun 26, 2017
ff43970
no longer needed, and a bit broken and incompatible with the new theory)
thijsdhollander Jun 26, 2017
80d4f45
docs update
thijsdhollander Jun 26, 2017
5915e49
Merge remote-tracking branch 'origin/master' into mtlognorm
thijsdhollander Jun 26, 2017
2ec0848
initial mtlognorm doc changes (more to follow)
thijsdhollander Jun 26, 2017
43e08d3
Merge remote-tracking branch 'origin/master' into mtlognorm
thijsdhollander Jun 26, 2017
9248b5b
fixelcfestats: New option -mask
Lestropie Jun 27, 2017
11911d5
Docs update
Lestropie Jun 27, 2017
7c58e1c
fixelcfestats: Fix compilation
Lestropie Jun 27, 2017
a8acaa4
mtlognorm: Robustness and polishing up
rtabbara Jun 27, 2017
bb62654
docs update
thijsdhollander Jun 27, 2017
1c388e3
mtlognorm tweaks
thijsdhollander Jun 27, 2017
c0a6e36
remove independent scaling
thijsdhollander Jun 27, 2017
fcaf707
mtlognorm iterations tweaks
thijsdhollander Jun 27, 2017
30d6b71
mtlognorm iteration count fix
thijsdhollander Jun 27, 2017
cf720f3
mtlognorm: Changing scale factor convergence criterion
rtabbara Jun 28, 2017
e42403e
mtlognorm: Fixing convergence criterion bug when computing scale norm…
rtabbara Jun 28, 2017
a4f9a2a
inner max iterations tweak based on new convergence observations
thijsdhollander Jun 28, 2017
1d50a70
Merge remote-tracking branch 'origin/master' into mtlognorm
thijsdhollander Jun 28, 2017
585ed8f
mtlognorm: When iterating over multiple input-images concurrently, ma…
rtabbara Jun 28, 2017
3a6aded
fixelcfestats: Various fixels for -mask option
Lestropie Jun 28, 2017
6cad81b
mtlognorm: Adding support for 3d (or lower) input images
rtabbara Jun 28, 2017
30505b5
Merge remote-tracking branch 'origin/master' into mtlognorm
thijsdhollander Jun 29, 2017
36224e5
fixelcfestats: Change type of normalised connectivity matrix
Lestropie Jun 29, 2017
fe72a9e
Getting rid of mtbin, avoiding users accidentally still using it.Ther…
thijsdhollander Jun 30, 2017
dc986a1
mtlognorm interface
thijsdhollander Jun 30, 2017
78cb168
cleaning up mtlognorm
thijsdhollander Jul 3, 2017
1854ef0
cleaning up mtlognorm take 2
thijsdhollander Jul 3, 2017
2ce23d2
cleaning up mtlognorm take 3
thijsdhollander Jul 4, 2017
3510a10
cleaning up mtlognorm take 4
thijsdhollander Jul 4, 2017
3769f48
fixelcfestats: Make sure connectivity matrix access functions are inline
Lestropie Jul 4, 2017
ce49bea
update FBA docs take 1
thijsdhollander Jul 4, 2017
840beac
fixelcfestats: Minor tweaks
Lestropie Jul 4, 2017
726496e
update FBA docs take 2
thijsdhollander Jul 4, 2017
fb9d512
update FBA docs take 2.5
thijsdhollander Jul 4, 2017
5fdfa2c
update global intensity normalisation doc
thijsdhollander Jul 4, 2017
dfc36c8
reinstate mtbin
thijsdhollander Jul 5, 2017
f746055
mrview Fixel plot: Compatibility with fixel data files containing NaNs
Lestropie Jul 5, 2017
07289db
Stats::CFE::NormMatrixElement class: Eigen 3.3 compatibility
Lestropie Jul 5, 2017
0d3daff
Merge branch 'master' into mtlognorm
thijsdhollander Jul 5, 2017
0f13690
fixelcfestats: Remove vestigial debugging call
Lestropie Jul 5, 2017
ca549ce
Merge branch 'master' into fixelcfestats_mask
jdtournier Jul 5, 2017
a595b3e
mtbin --> deprecated with warning, still works, though potential to c…
thijsdhollander Jul 7, 2017
8b5d1ec
delete old mtnormalise: won't break anyone's pipeline in this univers…
thijsdhollander Jul 7, 2017
70db93e
Merge branch 'mtlognorm' of github.com:MRtrix3/mrtrix3 into mtlognorm
thijsdhollander Jul 7, 2017
1f59e72
docs update
thijsdhollander Jul 7, 2017
bcc9b96
mtlognorm --> mtnormalise
thijsdhollander Jul 7, 2017
9866913
fixelcfestats: Add doc information regarding output when using -mask …
Lestropie Jul 7, 2017
22f711a
Merge branch 'master' into mtlognorm
thijsdhollander Jul 7, 2017
577ceb2
mtnormalise: Various tweaks and cleanups
Lestropie Jul 8, 2017
9bdd659
mtnormalise: Fix efficient quartile algorithm
Lestropie Jul 8, 2017
98dfb74
mtnormalise: Adding ability to set order of polynomial function to fi…
rtabbara Jul 10, 2017
7590bcd
mtnormalise: Separating progress bar to distinguish between loading i…
rtabbara Jul 10, 2017
321c607
mtnormalise: Adding missing memalign macros
rtabbara Jul 10, 2017
01c0a90
docs
thijsdhollander Jul 11, 2017
d0023d4
mtnormalise interface updates
thijsdhollander Jul 11, 2017
6e83120
mtnormalise info output tweak
thijsdhollander Jul 11, 2017
1179f08
dirgen: fix repulstion law to default to E = 1/r
jdtournier Jul 11, 2017
e5897db
dirgen: implement multiple restarts to improve robustness
jdtournier Jul 11, 2017
c8808ea
mtnormalise: Changing progress bar for normalisation computation to u…
rtabbara Jul 12, 2017
79638dd
mtnormalise: some more final cleaning up
thijsdhollander Jul 12, 2017
bb35a96
dwipreproc & PhaseEncoding fixes
Lestropie Jul 12, 2017
3338926
Docs: Update paths to reflect FHS
Lestropie Jul 12, 2017
10b3e53
dwipreproc: Force deletion of re-used temp files
Lestropie Jul 12, 2017
50e3cb2
Merge branch 'master' into mtlognorm
thijsdhollander Jul 12, 2017
3606518
Merge branch 'dev' into tensor2metric_sort_by_abs_eigval
jdtournier Jul 12, 2017
8af8bb7
Merge branch 'dev' into master
jdtournier Jul 12, 2017
d9a24ed
Merge branch 'dev' into lightbox_4d
jdtournier Jul 12, 2017
dbf9e1e
Merge branch 'dev' into fixelcfestats_mask
jdtournier Jul 12, 2017
6bf5962
fixed calculation of energy
kpannek Jul 12, 2017
af55ddb
dwipreproc: Prevent variable name ghosting at final output
Lestropie Jul 13, 2017
eb245c2
dwipreproc: Speed up volume recombination
Lestropie Jul 13, 2017
a7698e5
mtbin locked by default, override option for not recommended use
thijsdhollander Jul 13, 2017
1c68777
dirmerge: reinstate moderate bias towards unipolar model
jdtournier Jul 13, 2017
9fbf62c
Merge branch 'fix_dirgen' into kpannek-master
jdtournier Jul 13, 2017
49eb6de
dirstat: report identical energy as dirgen
jdtournier Jul 13, 2017
96be447
dirgen: multi-thread multiople restarts
jdtournier Jul 13, 2017
6034fc2
dirgen: fix minor typo in final console output
jdtournier Jul 13, 2017
dff2919
Merge branch 'master' into dwipreproc_pe_fixes
Lestropie Jul 14, 2017
fc9d9b1
Merge pull request #1030 from MRtrix3/fixelcfestats_mask
Lestropie Jul 14, 2017
febc0a4
mrcalc and mrmath: Erase DW / PE schemes
Lestropie Jul 14, 2017
916a108
mrview: lightbox: Polishing up viewing of volumes
rtabbara Jul 14, 2017
c04c90c
Merge pull request #1036 from MRtrix3/mtlognorm
thijsdhollander Jul 14, 2017
04210ef
dirgen: update testing data
jdtournier Jul 17, 2017
ba8ef0c
Merge pull request #1050 from kpannek/master
jdtournier Jul 17, 2017
7643042
DICOM: add support for multiple image types in one series
jdtournier Jul 17, 2017
86d3a12
DICOM: show image type in GUI selection dialog
jdtournier Jul 17, 2017
039c00b
dirgen and dirmerge docs update
thijsdhollander Jul 18, 2017
f6a205c
dirgen: fixed a couple of typos in the description
thijsdhollander Jul 18, 2017
09d278e
mrview: lightbox: make sure volume increment value persists even afte…
rtabbara Jul 18, 2017
0533ed9
PE and DW scheme: Check before deleting map entries
Lestropie Jul 18, 2017
3686226
image_diff: relax tolerance on vox spacing
jdtournier Jul 17, 2017
3c474c6
DICOM: use a frame from the correct image type to gather info
jdtournier Jul 18, 2017
335038b
DICOM: fix handling of multi-channel data
jdtournier Jul 18, 2017
b315da4
Merge pull request #1047 from MRtrix3/dwipreproc_pe_fixes
Lestropie Jul 19, 2017
0a08cb4
population_template: voxel size option
maxpietsch Jul 5, 2017
cea6bad
docs update
maxpietsch Jul 19, 2017
55ab618
docs: FBA population_template 1.25mm voxel size
maxpietsch Jul 19, 2017
91839dc
Merge pull request #1059 from MRtrix3/image_diff_relax_tolerance_on_s…
jdtournier Jul 19, 2017
05277b9
dirgen: use atomic post-increment operator rather than fetch_add()
jdtournier Jul 19, 2017
f95e67b
Merge branch 'dev' into lightbox_4d
jdtournier Jul 12, 2017
13ac069
mrview: lightbox: Polishing up viewing of volumes
rtabbara Jul 14, 2017
6e2e8a2
mrview: lightbox: make sure volume increment value persists even afte…
rtabbara Jul 18, 2017
58e2497
Merge remote-tracking branch 'origin/lightbox_4d' into lightbox_4d
rtabbara Jul 20, 2017
723e0bc
dcminfo: print out all information for specified tag
jdtournier Jul 20, 2017
2882846
tensor2metric: sort eigenvalues by absolute values as standard
jdtournier Jul 20, 2017
07ce915
write_mrtrix: update to output generic fields
jdtournier Jul 20, 2017
ab3f4c3
tensor2metric: Error if no output specified
Lestropie Jul 21, 2017
60a3cea
mrview: view: Renaming lightbox volume checkbox
rtabbara Jul 21, 2017
b2a0e54
docs update
thijsdhollander Jul 21, 2017
3c943e1
copyrights update
thijsdhollander Jul 21, 2017
78b6eaf
Merge pull request #1026 from MRtrix3/tensor2metric_sort_by_abs_eigval
jdtournier Jul 21, 2017
abfabab
Merge pull request #1063 from MRtrix3/update_matlab_write_mrtrix
jdtournier Jul 21, 2017
3c62cd7
Merge pull request #1056 from MRtrix3/DICOM_split_series_by_image_type
jdtournier Jul 21, 2017
f96cc5f
mrtransform & mrresize: Fix nearest-neighbour downsampling
Lestropie Jul 21, 2017
8199006
mrtransform: add -oversample commmand to over-ride default behaviour
jdtournier Jul 21, 2017
8cc9220
mrtransform: oversample regridding of warp, warning, added oversample…
maxpietsch Jul 21, 2017
ee6ec14
Merge remote-tracking branch 'bjeurissen/master' into mrdegibbs
jdtournier Jul 21, 2017
342542d
mrdegibbs: clean up incoming code
jdtournier Jul 21, 2017
b8148cb
mrdegibbs: command compiles OK with FFTW
jdtournier Jul 22, 2017
5219528
scripts: fix check3DNonunity for 4D input with 1 volume
maxpietsch Jul 24, 2017
27ac14a
mrview: lightbox: Cache current selection
rtabbara Jul 26, 2017
1c70e90
mrview: lightbox: Correctly update current slice focus
rtabbara Jul 27, 2017
fb2c177
update docs
thijsdhollander Aug 1, 2017
f0f384f
Merge remote-tracking branch 'origin/tag_3.0_RC2' into lightbox_4d
thijsdhollander Aug 1, 2017
e725922
Merge pull request #1067 from MRtrix3/mrtransform_add_oversample_option
jdtournier Aug 1, 2017
c519731
mrdegibbs: switch from size_t to int
jdtournier Aug 1, 2017
8008da6
mrdegibbs: use full precision Math::pi
jdtournier Aug 1, 2017
018b729
userdocs update
thijsdhollander Aug 2, 2017
97e8e86
Merge remote-tracking branch 'origin/tag_3.0_RC2' into lightbox_4d
thijsdhollander Aug 2, 2017
91b7206
Merge remote-tracking branch 'origin/master' into tag_3.0_RC2
thijsdhollander Aug 2, 2017
9f79ed1
Merge remote-tracking branch 'origin/tag_3.0_RC2' into lightbox_4d
thijsdhollander Aug 2, 2017
4783280
dwipreproc: Fix volume matching with zero-length gradient vectors
Lestropie Aug 2, 2017
3c6dbd3
mrdegibbs: removed FFTW dependency
jdtournier Aug 2, 2017
d935cd9
mrdegibbs: substantial simplication and avoidance of redundant FFTs
jdtournier Aug 2, 2017
33a6b09
mrdegibbs: add missing options and tidy up help page
jdtournier Aug 2, 2017
c218b4c
mrdegibbs: fix up Eigen memory alignment
jdtournier Aug 2, 2017
eb5c096
mrview: lightbox: Always update slice_focus_delta
rtabbara Aug 3, 2017
0f25e63
mrtrix3.fsl.findImage(): New function
Lestropie Aug 3, 2017
7512a56
fsl.exeName(): Fix bug in initial implementation
Lestropie Aug 3, 2017
9039443
Merge pull request #1077 from MRtrix3/dwipreproc_volmatch_zerovec_fix
Lestropie Aug 3, 2017
03d1d49
mrdegibbs: add support for linking against FFTW
jdtournier Aug 3, 2017
647b24a
mrdegibbs: add test
jdtournier Aug 3, 2017
af82f99
additional INFO output when opening/creating images
jdtournier Aug 3, 2017
3aefda4
dwidenoise: check image is 4-dimensional
jdtournier Aug 3, 2017
3c1ac61
fsl.findImage(): Fix glitches from testing
Lestropie Aug 4, 2017
0bb663c
5ttgen fsl: Find FIRST output despite FSLOUTPUTTYPE non-conformity
Lestropie Aug 4, 2017
40ebb23
Merge pull request #694 from MRtrix3/lightbox_4d
jdtournier Aug 4, 2017
c97dda8
mrdegibbs: additional documentation about partial Fourier and motion …
jdtournier Aug 4, 2017
9f0ec9a
mrdegibbs: update testing data
jdtournier Aug 4, 2017
76acb10
Merge remote-tracking branch 'github/tag_3.0_RC2' into mrdegibbs
jdtournier Aug 4, 2017
2f8af42
Merge branch 'tag_3.0_RC2' into LeeReidCSIRO-master
jdtournier Aug 4, 2017
eda0f33
Merge pull request #961 from LeeReidCSIRO/master
jdtournier Aug 4, 2017
959ed4e
userdocs update
thijsdhollander Aug 7, 2017
8afe98e
Merge pull request #1079 from MRtrix3/mrdegibbs
thijsdhollander Aug 7, 2017
40e01bc
userdocs update
thijsdhollander Aug 7, 2017
48dc307
Merge branch 'master' into tag_3.0_RC2
thijsdhollander Aug 7, 2017
00ad864
copyright updates
thijsdhollander Aug 7, 2017
7cb5077
Merge pull request #1080 from MRtrix3/python_fsl_findimage_function
Lestropie Aug 7, 2017
9a1de6f
Handle shell selection when using msmt_csd
bjeurissen Aug 8, 2017
9635243
Merge pull request #1082 from MRtrix3/dwi2fod-shell-option
thijsdhollander Aug 8, 2017
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
10 changes: 4 additions & 6 deletions bin/dwibiascorrect
Expand Up @@ -51,10 +51,6 @@ if app.args.fsl:
app.error('Could not find FSL program fast; please verify FSL install')

fsl_suffix = fsl.suffix()
if fast_cmd == 'fast':
fast_suffix = fsl_suffix
else:
fast_suffix = '.nii.gz'

elif app.args.ants:

Expand Down Expand Up @@ -101,10 +97,12 @@ else:
run.command('dwiextract in.mif - -bzero | mrmath - mean mean_bzero.mif -axis 3')

if app.args.fsl:

# FAST doesn't accept a mask input; therefore need to explicitly mask the input image
run.command('mrcalc mean_bzero.mif mask.mif -mult - | mrconvert - mean_bzero_masked.nii -stride -1,+2,+3')
run.command(fast_cmd + ' -t 2 -o fast -n 3 -b mean_bzero_masked.nii')
bias_path = 'fast_bias' + fast_suffix
bias_path = fsl.findImage('fast_bias')

elif app.args.ants:

# If the mask image was provided manually, and doesn't match the input image perfectly
Expand All @@ -118,7 +116,7 @@ elif app.args.ants:
run.command('mrconvert mean_bzero.mif mean_bzero.nii -stride +1,+2,+3')
run.command('mrconvert mask.mif mask.nii -stride +1,+2,+3')
bias_path = 'bias.nii'
run.command('N4BiasFieldCorrection -d 3 -i mean_bzero.nii -w mask.nii -o [corrected.nii,' + bias_path + '] -s 2 -b [150] -c [200x200,0.0]')
run.command('N4BiasFieldCorrection -d 3 -i mean_bzero.nii -w mask.nii -o [corrected.nii,' + bias_path + '] -b [150,3] -c [1000x1000,0.0]')

run.command('mrcalc in.mif ' + bias_path + ' -div result.mif')
run.command('mrconvert result.mif ' + path.fromUser(app.args.output, True) + (' -force' if app.force else ''))
Expand Down
138 changes: 104 additions & 34 deletions bin/dwipreproc
Expand Up @@ -2,7 +2,7 @@

# Script for performing DWI pre-processing using FSL 5.0 tools eddy / topup / applytopup

# This script is generally the first operation that will be applied to diffusion image data (with the possible exception of dwidenoise). The precise details of how this image pre-processing takes place depends heavily on the DWI acquisition; specifically, the presence or absence of reversed phase-encoding data for the purposes of EPI susceptibility distortion correction.
# This script is generally one of the first operations that will be applied to diffusion image data. The precise details of how this image pre-processing takes place depends heavily on the DWI acquisition; specifically, the presence or absence of reversed phase-encoding data for the purposes of EPI susceptibility distortion correction.

# The script is capable of handling a wide range of DWI acquisitions with respect to the design of phase encoding directions. This is dependent upon information regarding the phase encoding being embedded within theimage headers. The relevant information should be captured by MRtrix when importing DICOM images; it should also be the case for BIDS-compatible datasets. If the user expects this information to be present within the image headers, the -rpe_header option must be specified.

Expand All @@ -24,7 +24,7 @@ if not os.path.isdir(lib_folder):
sys.path.insert(0, lib_folder)


import math
import math, shutil
from distutils.spawn import find_executable
from mrtrix3 import app, file, fsl, image, path, phaseEncoding, run

Expand Down Expand Up @@ -182,6 +182,27 @@ if not len(grad) == num_volumes:
do_topup = (not PE_design == 'None')


def grads_match(one, two):
# Dot product between gradient directions
# First, need to check for zero-norm vectors:
# - If both are zero, skip this check
# - If one is zero and the other is not, volumes don't match
# - If neither is zero, test the dot product
if any([val for val in one[0:3]]):
if not any([val for val in two[0:3]]):
return False
dot_product = one[0]*two[0] + one[1]*two[1] + one[2]*two[2]
if abs(dot_product) < 0.999:
return False
elif any([val for val in two[0:3]]):
return False
# b-value
if abs(one[3]-two[3]) > 10.0:
return False
return True



# Manually generate a phase-encoding table for the input DWI based on user input
dwi_manual_pe_scheme = None
topup_manual_pe_scheme = None
Expand Down Expand Up @@ -220,26 +241,39 @@ if manual_pe_dir:
# If -rpe_all, need to scan through grad and figure out the pairings
# This will be required if relying on user-specified phase encode direction
# It will also be required at the end of the script for the manual recombination
# Update: The possible permutations of volume-matched acquisition is limited within the
# context of the -rpe_all option. In particular, the potential for having more
# than one b=0 volume within each half means that it is not possible to permit
# arbitrary ordering of those pairs, since b=0 volumes would then be matched
# despite having the same phase-encoding direction. Instead, explicitly enforce
# that volumes must be matched between the first and second halves of the DWI data.
elif PE_design == 'All':
grad_matchings = [ num_volumes ] * num_volumes
if num_volumes%2:
app.error('If using -rpe_all option, input image must contain an even number of volumes')
grads_matched = [ num_volumes ] * num_volumes
grad_pairs = [ ]
for index1 in range(num_volumes):
if grad_matchings[index1] == num_volumes: # As yet unpaired
for index2 in range(index1+1, num_volumes):
if grad_matchings[index2] == num_volumes: # Also as yet unpaired
if grad[index1] == grad[index2]:
grad_matchings[index1] = index2;
grad_matchings[index2] = index1;
app.debug('Commencing gradient direction matching; ' + str(num_volumes) + ' volumes')
for index1 in range(int(num_volumes/2)):
if grads_matched[index1] == num_volumes: # As yet unpaired
for index2 in range(int(num_volumes/2), num_volumes):
if grads_matched[index2] == num_volumes: # Also as yet unpaired
if grads_match(grad[index1], grad[index2]):
grads_matched[index1] = index2;
grads_matched[index2] = index1;
grad_pairs.append([index1, index2])
app.debug('Matched volume ' + str(index1) + ' with ' + str(index2) + ': ' + str(grad[index1]) + ' ' + str(grad[index2]))
break
else:
app.error('Unable to determine matching reversed phase-encode direction volume for DWI volume ' + str(index1))
if not len(grad_pairs) == num_volumes/2:
app.error('Unable to determine matching DWI volume pairs for reversed phase-encode combination')
app.error('Unable to determine complete matching DWI volume pairs for reversed phase-encode combination')
# Construct manual PE scheme here:
# Regardless of whether or not there's a scheme in the header, need to have it:
# if there's one in the header, want to compare to the manually-generated one
dwi_manual_pe_scheme = [ ]
for index in range(0, num_volumes):
line = list(manual_pe_dir)
if grad_matchings[index] < index:
if index >= int(num_volumes/2):
line = [ (-i if i else 0.0) for i in line ]
line.append(trt)
dwi_manual_pe_scheme.append(line)
Expand Down Expand Up @@ -435,22 +469,36 @@ if do_topup:
else:
run.command('mrinfo dwi.mif -export_pe_eddy applytopup_config.txt applytopup_indices.txt')

applytopup_index_list = [ ]
# Update: Call applytopup separately for each unique phase-encoding
# This should be the most compatible option with more complex phase-encoding acquisition designs,
# since we don't need to worry about applytopup performing volume recombination
# Plus, recombination doesn't need to be optimal; we're only using this to derive a brain mask
applytopup_image_list = [ ]
index = 1
with open('applytopup_config.txt', 'r') as f:
for line in f:
image_path = 'dwi_pe_' + str(index) + '.nii'
run.command('dwiextract dwi.mif' + import_dwi_pe_table_option + ' -pe ' + ','.join(line.split()) + ' ' + image_path)
applytopup_index_list.append(str(index))
applytopup_image_list.append(image_path)
input_path = 'dwi_pe_' + str(index) + '.nii'
json_path = 'dwi_pe_' + str(index) + '.json'
temp_path = 'dwi_pe_' + str(index) + '_topup' + fsl_suffix
output_path = 'dwi_pe_' + str(index) + '_topup.mif'
run.command('dwiextract dwi.mif' + import_dwi_pe_table_option + ' -pe ' + ','.join(line.split()) + ' - | mrconvert - ' + input_path + ' -json_export ' + json_path)
run.command(applytopup_cmd + ' --imain=' + input_path + ' --datain=applytopup_config.txt --inindex=' + str(index) + ' --topup=field --out=' + temp_path + ' --method=jac')
file.delTempFile(input_path)
temp_path = fsl.findImage(temp_path)
run.command('mrconvert ' + temp_path + ' ' + output_path + ' -json_import ' + json_path)
file.delTempFile(json_path)
file.delTempFile(temp_path)
applytopup_image_list.append(output_path)
index += 1

# Finally ready to run applytopup
run.command(applytopup_cmd + ' --imain=' + ','.join(applytopup_image_list) + ' --datain=applytopup_config.txt --inindex=' + ','.join(applytopup_index_list) + ' --topup=field --out=dwi_post_topup' + fsl_suffix + ' --method=jac')

# Use the initial corrected volumes to derive a brain mask for eddy
run.command('mrconvert dwi_post_topup' + fsl_suffix + ' -grad grad.b - | dwi2mask - - | maskfilter - dilate - | mrconvert - mask.nii -datatype float32 -stride -1,+2,+3')
if len(applytopup_image_list) == 1:
run.command('dwi2mask ' + applytopup_image_list[0] + ' - | maskfilter - dilate - | mrconvert - mask.nii -datatype float32 -stride -1,+2,+3')
else:
run.command('mrcat ' + ' '.join(applytopup_image_list) + ' - | dwi2mask - - | maskfilter - dilate - | mrconvert - mask.nii -datatype float32 -stride -1,+2,+3')

for entry in applytopup_image_list:
file.delTempFile(entry)

eddy_in_topup_option = ' --topup=field'

Expand Down Expand Up @@ -491,22 +539,26 @@ if not os.path.isfile(bvecs_path):
# The phase-encoding scheme needs to be checked also
volume_matchings = [ num_volumes ] * num_volumes
volume_pairs = [ ]
app.debug('Commencing gradient direction matching; ' + str(num_volumes) + ' volumes')
for index1 in range(num_volumes):
if volume_matchings[index1] == num_volumes: # As yet unpaired
for index2 in range(index1+1, num_volumes):
if volume_matchings[index2] == num_volumes: # Also as yet unpaired
# Here, need to check both gradient matching and reversed phase-encode direction
if not any(dwi_pe_scheme[index1][i] + dwi_pe_scheme[index2][i] for i in range(0,3)) and grad[index1] == grad[index2]:
if not any(dwi_pe_scheme[index1][i] + dwi_pe_scheme[index2][i] for i in range(0,3)) and grads_match(grad[index1], grad[index2]):
volume_matchings[index1] = index2;
volume_matchings[index2] = index1;
volume_pairs.append([index1, index2])
app.debug('Matched volume ' + str(index1) + ' with ' + str(index2) + '\n' +
'Phase encoding: ' + str(dwi_pe_scheme[index1]) + ' ' + str(dwi_pe_scheme[index2]) + '\n' +
'Gradients: ' + str(grad[index1]) + ' ' + str(grad[index2]))
break



if not len(volume_pairs) == num_volumes/2:
if not len(volume_pairs) == int(num_volumes/2):

# Convert the resulting volume to the output image, and re-insert the diffusion encoding
run.command('mrconvert dwi_post_eddy' + fsl_suffix + ' result.mif' + stride_option + ' -fslgrad ' + bvecs_path + ' bvals')
run.command('mrconvert ' + fsl.findImage('dwi_post_eddy') + ' result.mif' + stride_option + ' -fslgrad ' + bvecs_path + ' bvals')

else:
app.console('Detected matching DWI volumes with opposing phase encoding; performing explicit volume recombination')
Expand All @@ -533,6 +585,14 @@ else:
float(bvecs[1][pair[0]]) + float(bvecs[1][pair[1]]),
float(bvecs[2][pair[0]]) + float(bvecs[2][pair[1]]) ]
norm2 = bvec_sum[0]*bvec_sum[0] + bvec_sum[1]*bvec_sum[1] + bvec_sum[2]*bvec_sum[2]
# If one diffusion sensitisation gradient direction is reversed with respect to
# the other, still want to enable their recombination; but need to explicitly
# account for this when averaging the two directions
if norm2 < 0.0:
bvec_sum = [ float(bvecs[0][pair[0]]) - float(bvecs[0][pair[1]]),
float(bvecs[1][pair[0]]) - float(bvecs[1][pair[1]]),
float(bvecs[2][pair[0]]) - float(bvecs[2][pair[1]]) ]
norm2 = bvec_sum[0]*bvec_sum[0] + bvec_sum[1]*bvec_sum[1] + bvec_sum[2]*bvec_sum[2]
# Occasionally a bzero volume can have a zero vector
if norm2:
factor = 1.0 / math.sqrt(norm2)
Expand All @@ -559,12 +619,12 @@ else:
# Detect this, and manually replace the transform if necessary
# (even if this doesn't cause an issue with the subsequent mrcalc command, it may in the future, it's better for
# visualising the script temporary files, and it gives the user a warning about an out-of-date FSL)
field_map_image = 'field_map' + fsl_suffix
field_map_image = fsl.findImage('field_map')
if not image.match('topup_in.nii', field_map_image):
app.warn('topup output field image has erroneous header; recommend updating FSL to version 5.0.8 or later')
run.command('mrtransform ' + field_map_image + ' -replace topup_in.nii field_map_fix' + fsl_suffix)
run.command('mrtransform ' + field_map_image + ' -replace topup_in.nii field_map_fix.mif')
file.delTempFile(field_map_image)
field_map_image = 'field_map_fix' + fsl_suffix
field_map_image = 'field_map_fix.mif'



Expand Down Expand Up @@ -594,27 +654,37 @@ else:
run.command('mrcalc ' + jacobian_path + ' ' + jacobian_path + ' -mult weight' + str(index+1) + '.mif')
file.delTempFile(jacobian_path)

# If eddy provides its main image output in a compressed format, the code block below will need to
# uncompress that image independently for every volume pair. Instead, if this is the case, let's
# convert it to an uncompressed format before we do anything with it.
eddy_output = fsl.findImage('dwi_post_eddy')
if eddy_output.endswith('.gz'):
run.command('mrconvert ' + eddy_output + ' dwi_post_eddy.nii')
file.delTempFile(eddy_output)
eddy_output = 'dwi_post_eddy.nii'

# This section extracts the two volumes corresponding to each reversed phase-encoded volume pair, and
# derives a single image volume based on the recombination equation
combined_image_list = [ ]
for index, volumes in enumerate(volume_pairs):
pe_indices = [ eddy_indices[i] for i in volumes ]
run.command('mrconvert dwi_post_eddy' + fsl_suffix + ' volume0.mif -coord 3 ' + str(volumes[0]))
run.command('mrconvert dwi_post_eddy' + fsl_suffix + ' volume1.mif -coord 3 ' + str(volumes[1]))
run.command('mrconvert ' + eddy_output + ' volume0.mif -coord 3 ' + str(volumes[0]))
run.command('mrconvert ' + eddy_output + ' volume1.mif -coord 3 ' + str(volumes[1]))
# Volume recombination equation described in Skare and Bammer 2010
run.command('mrcalc volume0.mif weight' + str(pe_indices[0]) + '.mif -mult volume1.mif weight' + str(pe_indices[1]) + '.mif -mult -add weight' + str(pe_indices[0]) + '.mif weight' + str(pe_indices[1]) + '.mif -add -divide 0.0 -max combined' + str(index) + '.mif')
combined_image_list.append('combined' + str(index) + '.mif')
file.delTempFile('volume0.mif')
file.delTempFile('volume1.mif')
os.remove('volume0.mif')
os.remove('volume1.mif')
file.delTempFile(eddy_output)

for index in range(0, len(eddy_config)):
file.delTempFile('weight' + str(index+1) + '.mif')

# Finally the recombined volumes must be concatenated to produce the resulting image series
run.command('mrcat ' + ' '.join(combined_image_list) + ' - -axis 3 | mrconvert - result.mif -fslgrad bvecs_combined bvals_combined' + stride_option)

for path in combined_image_list:
file.delTempFile(path)
for entry in combined_image_list:
file.delTempFile(entry)



Expand Down
2 changes: 1 addition & 1 deletion bin/labelsgmfix
Expand Up @@ -83,7 +83,7 @@ if app.args.premasked:
first_input_is_brain_extracted = ' -b'
run.command(first_cmd + ' -s ' + ','.join(structure_map.keys()) + ' -i T1.nii' + first_input_is_brain_extracted + ' -o first')

# Generate an empty image that will be used to contruct the new SGM nodes
# Generate an empty image that will be used to construct the new SGM nodes
run.command('mrcalc parc.mif 0 -min sgm.mif')

# Read the local connectome LUT file
Expand Down
23 changes: 21 additions & 2 deletions bin/population_template
Expand Up @@ -188,6 +188,7 @@ nloptions.add_argument('-nl_grad_step', default='0.5', help='The gradient step s

options = app.cmdline.add_argument_group('Input, output and general options')
options.add_argument('-type', help='Specifiy the types of registration stages to perform. Options are "rigid" (perform rigid registration only which might be useful for intra-subject registration in longitudinal analysis), "affine" (perform affine registration) and "nonlinear" as well as cominations of registration types: %s. Default: rigid_affine_nonlinear' % ', '.join('"'+x+'"' for x in registration_modes if "_" in x), default='rigid_affine_nonlinear')
options.add_argument('-voxel_size', help='Define the template voxel size in mm. Use either a single value for isotropic voxels or 3 comma separated values.')
options.add_argument('-initial_alignment', default='mass', help='Method of alignment to form the initial template. Options are "mass" (default), "geometric" and "none".')
options.add_argument('-mask_dir', help='Optionally input a set of masks inside a single directory, one per input image (with the same file name prefix). Using masks will speed up registration significantly')
options.add_argument('-warp_dir', help='Output a directory containing warps from each input to the template. If the folder does not exist it will be created')
Expand Down Expand Up @@ -216,6 +217,18 @@ if len(inFiles) <= 1:
else:
app.console('Generating a population-average template from ' + str(len(inFiles)) + ' input images')

voxel_size = None
if app.args.voxel_size:
voxel_size = app.args.voxel_size.split()
if len(voxel_size) == 1:
voxel_size = voxel_size * 3
try:
if len(voxel_size) != 3:
raise
[float(v) for v in voxel_size]
except:
app.error('voxel size needs to be a single or three comma separated floating point numbers, received: '+str(app.args.voxel_size))

initial_alignment = app.args.initial_alignment
if initial_alignment not in ["mass", "geometric", "none"]:
message.error('initial_alignment must be one of ' + " ".join(["mass", "geometric", "none"]));
Expand Down Expand Up @@ -428,7 +441,10 @@ app.console('Generating initial template')
input_filenames = []
for i in input:
input_filenames.append (abspath(i.directory, i.filename));
run.command('mraverageheader ' + ' '.join(input_filenames) + ' average_header.mif' ' -fill')
if voxel_size is None:
run.command('mraverageheader ' + ' '.join(input_filenames) + ' average_header.mif -fill')
else:
run.command('mraverageheader -fill ' + ' '.join(input_filenames) + ' - | mrresize - -voxel '+','.join(voxel_size)+' average_header.mif')

# crop average space to extent defined by original masks
if useMasks:
Expand Down Expand Up @@ -480,7 +496,10 @@ else:
' ' + os.path.join('masks_transformed', i.prefix + '_translated.mif'))
# update average space to new extent
run.command('mraverageheader ' + ' '.join([os.path.join('input_transformed', i.prefix + '_translated.mif') for i in input]) + ' average_header_tight.mif')
run.command('mrpad -uniform 10 average_header_tight.mif average_header.mif -force')
if voxel_size is None:
run.command('mrpad -uniform 10 average_header_tight.mif average_header.mif -force')
else:
run.command('mrpad -uniform 10 average_header_tight.mif - | mrresize - -voxel '+','.join(voxel_size)+' average_header.mif -force')
run.function(remove, 'average_header_tight.mif')
if useMasks:
# reslice masks
Expand Down