From 8e34c065050864e9756eee8fa1e139e58f7c16de Mon Sep 17 00:00:00 2001 From: frheault Date: Wed, 24 Feb 2021 13:16:08 -0600 Subject: [PATCH 01/13] Concatenate dwi new scripts --- scripts/scil_concatenate_dwi.py | 92 +++++++++++++++++++++++++++ scripts/scil_extract_dwi_shell.py | 5 +- scripts/tests/test_concatenate_dwi.py | 32 ++++++++++ 3 files changed, 128 insertions(+), 1 deletion(-) create mode 100755 scripts/scil_concatenate_dwi.py create mode 100644 scripts/tests/test_concatenate_dwi.py diff --git a/scripts/scil_concatenate_dwi.py b/scripts/scil_concatenate_dwi.py new file mode 100755 index 000000000..f7a19cccb --- /dev/null +++ b/scripts/scil_concatenate_dwi.py @@ -0,0 +1,92 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +""" +Concatenate DWI, bval and bvecs together. File must be specified in matching +order. +""" + +import argparse + +from dipy.io import read_bvals_bvecs +import nibabel as nib +import numpy as np + +from scilpy.io.utils import (add_overwrite_arg, + assert_inputs_exist, + assert_outputs_exist) + + +def _build_arg_parser(): + p = argparse.ArgumentParser( + description=__doc__, + formatter_class=argparse.RawTextHelpFormatter) + + p.add_argument('out_dwi', + help='The name of the output DWI file.') + p.add_argument('out_bvals', + help='The name of the output b-values.') + p.add_argument('out_bvecs', + help='The name of the output b-vectors') + + p.add_argument('--in_dwi', nargs='+', + help='The DWI file (.nii) to concatenate.') + p.add_argument('--in_bvals', nargs='+', + help='The b-values in FSL format.') + p.add_argument('--in_bvecs', nargs='+', + help='The b-vectors in FSL format.') + + p.add_argument('--data_type', + help='Data type of the output image. Use the format: ' + 'uint8, int16, int/float32, int/float64.') + + add_overwrite_arg(p) + + return p + + +def main(): + parser = _build_arg_parser() + args = parser.parse_args() + + if len(args.in_dwi) != len(args.in_bvals) \ + or len(args.in_dwi) != len(args.in_bvecs): + parser.error('DWI, bvals and bvecs must have the same length') + + assert_inputs_exist(parser, args.in_dwi + args.in_bvals + args.in_bvecs) + assert_outputs_exist(parser, args, [args.out_dwi, args.out_bvals, + args.out_bvecs]) + + all_bvals = [] + all_bvecs = [] + total_size = 0 + for i in range(len(args.in_dwi)): + bvals, bvecs = read_bvals_bvecs(args.in_bvals[i], args.in_bvecs[i]) + if len(bvals) != len(bvecs): + raise ValueError('Paired bvals and bvecs must have the same size.') + total_size += len(bvals) + all_bvals.append(bvals) + all_bvecs.append(bvecs) + all_bvals = np.concatenate(all_bvals) + all_bvecs = np.concatenate(all_bvecs) + + ref_dwi = nib.load(args.in_dwi[0]) + all_dwi = np.zeros(ref_dwi.shape[0:3] + (total_size,), + dtype=args.data_type) + last_count = ref_dwi.shape[-1] + all_dwi[..., 0:last_count] = ref_dwi.get_fdata() + for i in range(1, len(args.in_dwi)): + curr_dwi = nib.load(args.in_dwi[i]) + if curr_dwi.shape != ref_dwi.shape: + raise ValueError('All DWI must have the same shape.') + curr_size = curr_dwi.shape[-1] + all_dwi[..., last_count:last_count+curr_size] = curr_dwi.get_fdata() + + np.savetxt(args.out_bvals, all_bvals, '%d') + np.savetxt(args.out_bvecs, all_bvecs.T, '%0.15f') + nib.save(nib.Nifti1Image(all_dwi, ref_dwi.affine, header=ref_dwi.header), + args.out_dwi) + + +if __name__ == "__main__": + main() diff --git a/scripts/scil_extract_dwi_shell.py b/scripts/scil_extract_dwi_shell.py index 0d6d967ab..ebabf7df3 100755 --- a/scripts/scil_extract_dwi_shell.py +++ b/scripts/scil_extract_dwi_shell.py @@ -28,7 +28,9 @@ assert_inputs_exist, assert_outputs_exist) from scilpy.utils.bvec_bval_tools import extract_dwi_shell - +# TODO switch from parser to p +# TODO switch to in_* +# TODO switch to out_* def _build_arg_parser(): parser = argparse.ArgumentParser( description=__doc__, @@ -100,6 +102,7 @@ def main(): np.savetxt(args.output_bvals, new_bvals, '%d') np.savetxt(args.output_bvecs, new_bvecs.T, '%0.15f') + # use named argument header= nib.save(nib.Nifti1Image(shell_data, img.affine, img.header), args.output_dwi) diff --git a/scripts/tests/test_concatenate_dwi.py b/scripts/tests/test_concatenate_dwi.py new file mode 100644 index 000000000..db768e8e4 --- /dev/null +++ b/scripts/tests/test_concatenate_dwi.py @@ -0,0 +1,32 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +import os +import tempfile + +from scilpy.io.fetcher import fetch_data, get_home, get_testing_files_dict + +# If they already exist, this only takes 5 seconds (check md5sum) +fetch_data(get_testing_files_dict(), keys=['processing.zip']) +tmp_dir = tempfile.TemporaryDirectory() + + +def test_help_option(script_runner): + ret = script_runner.run('scil_concatenate_dwi.py', '--help') + assert ret.success + + +def test_execution_processing_concatenate(script_runner): + os.chdir(os.path.expanduser(tmp_dir.name)) + in_dwi = os.path.join(get_home(), 'processing', + 'dwi_crop.nii.gz') + in_bval = os.path.join(get_home(), 'processing', + 'dwi.bval') + in_bvec = os.path.join(get_home(), 'processing', + 'dwi.bvec') + ret = script_runner.run('scil_concatenate_dwi.py', 'dwi_concat.nii.gz', + 'concat.bval', 'concat.bvec', + '--in_dwi', in_dwi, in_dwi, + '--in_bvals', in_bval, in_bval, + '--in_bvecs', in_bvec, in_bvec) + assert ret.success From 369e4ec679f081d9e28bb022dc2026a36b9504d5 Mon Sep 17 00:00:00 2001 From: frheault Date: Wed, 24 Feb 2021 13:20:03 -0600 Subject: [PATCH 02/13] Default doc --- scripts/scil_concatenate_dwi.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/scil_concatenate_dwi.py b/scripts/scil_concatenate_dwi.py index f7a19cccb..4ef7fdc3c 100755 --- a/scripts/scil_concatenate_dwi.py +++ b/scripts/scil_concatenate_dwi.py @@ -3,7 +3,7 @@ """ Concatenate DWI, bval and bvecs together. File must be specified in matching -order. +order. Default data type will be the same as the first input DWI. """ import argparse From e4207a8aa9885276f25812041d740162b290c42f Mon Sep 17 00:00:00 2001 From: Francois Rheault Date: Wed, 24 Feb 2021 15:30:00 -0600 Subject: [PATCH 03/13] Update scripts/scil_concatenate_dwi.py Co-authored-by: arnaudbore --- scripts/scil_concatenate_dwi.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/scil_concatenate_dwi.py b/scripts/scil_concatenate_dwi.py index 4ef7fdc3c..6dd2b0845 100755 --- a/scripts/scil_concatenate_dwi.py +++ b/scripts/scil_concatenate_dwi.py @@ -24,7 +24,7 @@ def _build_arg_parser(): p.add_argument('out_dwi', help='The name of the output DWI file.') - p.add_argument('out_bvals', + p.add_argument('out_bval', help='The name of the output b-values.') p.add_argument('out_bvecs', help='The name of the output b-vectors') From ad27cc17dd6a041457b791a180f98b5cb83f576a Mon Sep 17 00:00:00 2001 From: Francois Rheault Date: Wed, 24 Feb 2021 15:30:10 -0600 Subject: [PATCH 04/13] Update scripts/scil_concatenate_dwi.py Co-authored-by: arnaudbore --- scripts/scil_concatenate_dwi.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/scil_concatenate_dwi.py b/scripts/scil_concatenate_dwi.py index 6dd2b0845..d08bb89e5 100755 --- a/scripts/scil_concatenate_dwi.py +++ b/scripts/scil_concatenate_dwi.py @@ -29,7 +29,7 @@ def _build_arg_parser(): p.add_argument('out_bvecs', help='The name of the output b-vectors') - p.add_argument('--in_dwi', nargs='+', + p.add_argument('--in_dwis', nargs='+', help='The DWI file (.nii) to concatenate.') p.add_argument('--in_bvals', nargs='+', help='The b-values in FSL format.') From 0fa6a268cfcac191b099f12c7aa2779c0894cb58 Mon Sep 17 00:00:00 2001 From: Francois Rheault Date: Wed, 24 Feb 2021 15:30:19 -0600 Subject: [PATCH 05/13] Update scripts/scil_concatenate_dwi.py Co-authored-by: arnaudbore --- scripts/scil_concatenate_dwi.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/scil_concatenate_dwi.py b/scripts/scil_concatenate_dwi.py index d08bb89e5..b51630cb6 100755 --- a/scripts/scil_concatenate_dwi.py +++ b/scripts/scil_concatenate_dwi.py @@ -27,7 +27,7 @@ def _build_arg_parser(): p.add_argument('out_bval', help='The name of the output b-values.') p.add_argument('out_bvecs', - help='The name of the output b-vectors') + help='The name of the output b-vectors.') p.add_argument('--in_dwis', nargs='+', help='The DWI file (.nii) to concatenate.') From 8f01d44091478d329afb3113ef6e271bda815224 Mon Sep 17 00:00:00 2001 From: Francois Rheault Date: Wed, 24 Feb 2021 15:30:28 -0600 Subject: [PATCH 06/13] Update scripts/scil_concatenate_dwi.py Co-authored-by: arnaudbore --- scripts/scil_concatenate_dwi.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/scil_concatenate_dwi.py b/scripts/scil_concatenate_dwi.py index b51630cb6..a23e061a9 100755 --- a/scripts/scil_concatenate_dwi.py +++ b/scripts/scil_concatenate_dwi.py @@ -54,7 +54,7 @@ def main(): parser.error('DWI, bvals and bvecs must have the same length') assert_inputs_exist(parser, args.in_dwi + args.in_bvals + args.in_bvecs) - assert_outputs_exist(parser, args, [args.out_dwi, args.out_bvals, + assert_outputs_exist(parser, args, [args.out_dwi, args.out_bval, args.out_bvecs]) all_bvals = [] From 7c8721e631c2c97f42613d118004beae0b784081 Mon Sep 17 00:00:00 2001 From: Francois Rheault Date: Wed, 24 Feb 2021 15:30:33 -0600 Subject: [PATCH 07/13] Update scripts/scil_concatenate_dwi.py Co-authored-by: arnaudbore --- scripts/scil_concatenate_dwi.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/scil_concatenate_dwi.py b/scripts/scil_concatenate_dwi.py index a23e061a9..5e08ee2d2 100755 --- a/scripts/scil_concatenate_dwi.py +++ b/scripts/scil_concatenate_dwi.py @@ -55,7 +55,7 @@ def main(): assert_inputs_exist(parser, args.in_dwi + args.in_bvals + args.in_bvecs) assert_outputs_exist(parser, args, [args.out_dwi, args.out_bval, - args.out_bvecs]) + args.out_bvec]) all_bvals = [] all_bvecs = [] From 19e8adfe4934c541698b4ca29d0985ae92a62e58 Mon Sep 17 00:00:00 2001 From: Francois Rheault Date: Wed, 24 Feb 2021 15:30:39 -0600 Subject: [PATCH 08/13] Update scripts/scil_concatenate_dwi.py Co-authored-by: arnaudbore --- scripts/scil_concatenate_dwi.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/scil_concatenate_dwi.py b/scripts/scil_concatenate_dwi.py index 5e08ee2d2..f45066805 100755 --- a/scripts/scil_concatenate_dwi.py +++ b/scripts/scil_concatenate_dwi.py @@ -60,7 +60,7 @@ def main(): all_bvals = [] all_bvecs = [] total_size = 0 - for i in range(len(args.in_dwi)): + for i in range(len(args.in_dwis)): bvals, bvecs = read_bvals_bvecs(args.in_bvals[i], args.in_bvecs[i]) if len(bvals) != len(bvecs): raise ValueError('Paired bvals and bvecs must have the same size.') From c13e39025f140d2c72ca09908188cd356377c034 Mon Sep 17 00:00:00 2001 From: Francois Rheault Date: Wed, 24 Feb 2021 15:30:45 -0600 Subject: [PATCH 09/13] Update scripts/scil_concatenate_dwi.py Co-authored-by: arnaudbore --- scripts/scil_concatenate_dwi.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/scil_concatenate_dwi.py b/scripts/scil_concatenate_dwi.py index f45066805..2ed26e53c 100755 --- a/scripts/scil_concatenate_dwi.py +++ b/scripts/scil_concatenate_dwi.py @@ -75,7 +75,7 @@ def main(): dtype=args.data_type) last_count = ref_dwi.shape[-1] all_dwi[..., 0:last_count] = ref_dwi.get_fdata() - for i in range(1, len(args.in_dwi)): + for i in range(1, len(args.in_dwis)): curr_dwi = nib.load(args.in_dwi[i]) if curr_dwi.shape != ref_dwi.shape: raise ValueError('All DWI must have the same shape.') From 4f4808cbda8fe20fded1725ea998b675d2ed0116 Mon Sep 17 00:00:00 2001 From: Francois Rheault Date: Wed, 24 Feb 2021 15:31:02 -0600 Subject: [PATCH 10/13] Update scripts/scil_concatenate_dwi.py Co-authored-by: arnaudbore --- scripts/scil_concatenate_dwi.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/scil_concatenate_dwi.py b/scripts/scil_concatenate_dwi.py index 2ed26e53c..fe67d2862 100755 --- a/scripts/scil_concatenate_dwi.py +++ b/scripts/scil_concatenate_dwi.py @@ -76,7 +76,7 @@ def main(): last_count = ref_dwi.shape[-1] all_dwi[..., 0:last_count] = ref_dwi.get_fdata() for i in range(1, len(args.in_dwis)): - curr_dwi = nib.load(args.in_dwi[i]) + curr_dwi = nib.load(args.in_dwis[i]) if curr_dwi.shape != ref_dwi.shape: raise ValueError('All DWI must have the same shape.') curr_size = curr_dwi.shape[-1] From 164eee18c41b86145d1c11edbe2642468ca46528 Mon Sep 17 00:00:00 2001 From: Francois Rheault Date: Wed, 24 Feb 2021 15:31:10 -0600 Subject: [PATCH 11/13] Update scripts/scil_concatenate_dwi.py Co-authored-by: arnaudbore --- scripts/scil_concatenate_dwi.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/scil_concatenate_dwi.py b/scripts/scil_concatenate_dwi.py index fe67d2862..2249bb853 100755 --- a/scripts/scil_concatenate_dwi.py +++ b/scripts/scil_concatenate_dwi.py @@ -82,7 +82,7 @@ def main(): curr_size = curr_dwi.shape[-1] all_dwi[..., last_count:last_count+curr_size] = curr_dwi.get_fdata() - np.savetxt(args.out_bvals, all_bvals, '%d') + np.savetxt(args.out_bval, all_bvals, '%d') np.savetxt(args.out_bvecs, all_bvecs.T, '%0.15f') nib.save(nib.Nifti1Image(all_dwi, ref_dwi.affine, header=ref_dwi.header), args.out_dwi) From f3138eea6915ace5031ebbb99f40bde97f3c360d Mon Sep 17 00:00:00 2001 From: Francois Rheault Date: Wed, 24 Feb 2021 15:31:16 -0600 Subject: [PATCH 12/13] Update scripts/scil_concatenate_dwi.py Co-authored-by: arnaudbore --- scripts/scil_concatenate_dwi.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/scil_concatenate_dwi.py b/scripts/scil_concatenate_dwi.py index 2249bb853..0d6a7f378 100755 --- a/scripts/scil_concatenate_dwi.py +++ b/scripts/scil_concatenate_dwi.py @@ -83,7 +83,7 @@ def main(): all_dwi[..., last_count:last_count+curr_size] = curr_dwi.get_fdata() np.savetxt(args.out_bval, all_bvals, '%d') - np.savetxt(args.out_bvecs, all_bvecs.T, '%0.15f') + np.savetxt(args.out_bvec, all_bvecs.T, '%0.15f') nib.save(nib.Nifti1Image(all_dwi, ref_dwi.affine, header=ref_dwi.header), args.out_dwi) From 691a3cdb921feae03f3c9e9a6a71a33d66dacf9b Mon Sep 17 00:00:00 2001 From: frheault Date: Wed, 24 Feb 2021 16:01:50 -0600 Subject: [PATCH 13/13] Fix arnaud comments --- scripts/scil_concatenate_dwi.py | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/scripts/scil_concatenate_dwi.py b/scripts/scil_concatenate_dwi.py index 0d6a7f378..bf25b46f6 100755 --- a/scripts/scil_concatenate_dwi.py +++ b/scripts/scil_concatenate_dwi.py @@ -8,7 +8,8 @@ import argparse -from dipy.io import read_bvals_bvecs +from dipy.io.gradients import read_bvals_bvecs +from dipy.io.utils import is_header_compatible import nibabel as nib import numpy as np @@ -26,7 +27,7 @@ def _build_arg_parser(): help='The name of the output DWI file.') p.add_argument('out_bval', help='The name of the output b-values.') - p.add_argument('out_bvecs', + p.add_argument('out_bvec', help='The name of the output b-vectors.') p.add_argument('--in_dwis', nargs='+', @@ -49,11 +50,11 @@ def main(): parser = _build_arg_parser() args = parser.parse_args() - if len(args.in_dwi) != len(args.in_bvals) \ - or len(args.in_dwi) != len(args.in_bvecs): + if len(args.in_dwis) != len(args.in_bvals) \ + or len(args.in_dwis) != len(args.in_bvecs): parser.error('DWI, bvals and bvecs must have the same length') - assert_inputs_exist(parser, args.in_dwi + args.in_bvals + args.in_bvecs) + assert_inputs_exist(parser, args.in_dwis + args.in_bvals + args.in_bvecs) assert_outputs_exist(parser, args, [args.out_dwi, args.out_bval, args.out_bvec]) @@ -70,17 +71,18 @@ def main(): all_bvals = np.concatenate(all_bvals) all_bvecs = np.concatenate(all_bvecs) - ref_dwi = nib.load(args.in_dwi[0]) + ref_dwi = nib.load(args.in_dwis[0]) all_dwi = np.zeros(ref_dwi.shape[0:3] + (total_size,), dtype=args.data_type) last_count = ref_dwi.shape[-1] all_dwi[..., 0:last_count] = ref_dwi.get_fdata() for i in range(1, len(args.in_dwis)): curr_dwi = nib.load(args.in_dwis[i]) - if curr_dwi.shape != ref_dwi.shape: - raise ValueError('All DWI must have the same shape.') + if not is_header_compatible(curr_dwi, ref_dwi): + raise ValueError('All DWI must have the compatible header.') curr_size = curr_dwi.shape[-1] - all_dwi[..., last_count:last_count+curr_size] = curr_dwi.get_fdata() + all_dwi[..., last_count:last_count+curr_size] = \ + curr_dwi.get_fdata() np.savetxt(args.out_bval, all_bvals, '%d') np.savetxt(args.out_bvec, all_bvecs.T, '%0.15f')