From 262cb3e87b16f70ce8a1ea27731ffcd1f1916f59 Mon Sep 17 00:00:00 2001 From: Siddhartha Dhiman Date: Fri, 18 Oct 2019 18:33:04 -0400 Subject: [PATCH 1/7] Add function to write missing BVEC/BVAL --- designer/preprocessing/util.py | 44 +++++++++++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/designer/preprocessing/util.py b/designer/preprocessing/util.py index d801a8b6..bea290f9 100644 --- a/designer/preprocessing/util.py +++ b/designer/preprocessing/util.py @@ -377,6 +377,7 @@ def cat(self, path, ext='.nii' ,verbose=False, force=False): miflist = [] # The following loop first converts NifTis to a .mif file for (idx, i) in enumerate(self.DWIlist): + self.json2fslgrad(i) convert_args = ['mrconvert -stride 1,2,3,4'] if verbose is False: convert_args.append('-quiet') @@ -438,4 +439,45 @@ def getPath(self): """Returns directory where first file in DWI list is stored """ path = os.path.dirname(os.path.abspath(self.DWIlist[0])) - return path \ No newline at end of file + return path + + def json2fslgrad(self, path): + """Creates FSL .bvec and .bval for series missing that information. + Some datasets have their B0s separately that do not produce fsl + gradients upon conversion to NifTi. This function creates those + missing features for complete concatenation from .json file. Use + with caution if and only if you know your input series is a DWI. + + Parameters + ---------- + path: string + Path to NifTi file + """ + print(path) + image = DWIFile(path) + args_info = ['mrinfo', path] + cmd = ' '.join(str(e) for e in args_info) + # Reads the "Dimension line of `mrinfo` and extracts the size + # of NifTi + pipe = subprocess.Popen(cmd, shell=True, + stdout=subprocess.PIPE) + strlist = pipe.stdout.readlines()[3].split() + dims = [int(i) for i in strlist if i.isdigit()] + print(dims) + nDWI = dims[-1] + # Check whether for inexistence of gradient table in JSON and + # some mention of B0 in EPI + if ('b0' in image.json['SeriesDescription'] or \ + 'B0' in image.json['SeriesDescription'] or \ + 'b0' in image.json['ProtocolName'] or \ + 'B0' in image.json['ProtocolName']): + bval = np.zeros(nDWI, dtype=int) + bvec = np.zeros((3, nDWI), dtype=int) + fPath = op.splitext(path)[0] + np.savetxt((fPath + '.bvec'), bvec, delimiter=' ', fmt='%d') + np.savetxt((fPath + '.bval'), np.c_[bval], delimiter=' ', + fmt='%d') + + + + From b5d64e66f492b86e66536c767d8048e7abb672ad Mon Sep 17 00:00:00 2001 From: Siddhartha Dhiman Date: Fri, 18 Oct 2019 18:33:20 -0400 Subject: [PATCH 2/7] Update DWIParser docstring --- designer/preprocessing/util.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/designer/preprocessing/util.py b/designer/preprocessing/util.py index bea290f9..2022b3b9 100644 --- a/designer/preprocessing/util.py +++ b/designer/preprocessing/util.py @@ -357,6 +357,8 @@ def __init__(self, path): def cat(self, path, ext='.nii' ,verbose=False, force=False): """Concatenates all input series when nDWI > 1 into a 4D NifTi along with a appropriate BVAL, BVEC and JSON files. + Concatenation of series via MRTRIX3 requires every NifTi file to + come with BVAL/BVEC to produce a .json with `dw_scheme`. Parameters ---------- From 286ef9e039da964ee12444af351d880a22af2d2e Mon Sep 17 00:00:00 2001 From: Siddhartha Dhiman Date: Fri, 18 Oct 2019 18:40:09 -0400 Subject: [PATCH 3/7] Remove debugging console prints --- designer/preprocessing/util.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/designer/preprocessing/util.py b/designer/preprocessing/util.py index 2022b3b9..4403eaf4 100644 --- a/designer/preprocessing/util.py +++ b/designer/preprocessing/util.py @@ -455,7 +455,6 @@ def json2fslgrad(self, path): path: string Path to NifTi file """ - print(path) image = DWIFile(path) args_info = ['mrinfo', path] cmd = ' '.join(str(e) for e in args_info) @@ -465,7 +464,6 @@ def json2fslgrad(self, path): stdout=subprocess.PIPE) strlist = pipe.stdout.readlines()[3].split() dims = [int(i) for i in strlist if i.isdigit()] - print(dims) nDWI = dims[-1] # Check whether for inexistence of gradient table in JSON and # some mention of B0 in EPI From f0efa3e5524478c840ee1c3cad5336a4efc57ca0 Mon Sep 17 00:00:00 2001 From: Siddhartha Dhiman Date: Fri, 18 Oct 2019 18:42:58 -0400 Subject: [PATCH 4/7] Change file name references dwi_desiger.nii to raw_dwi.nii --- designer/preprocessing/util.py | 14 +++++++------- designer/pydesigner.py | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/designer/preprocessing/util.py b/designer/preprocessing/util.py index 4403eaf4..1538a9af 100644 --- a/designer/preprocessing/util.py +++ b/designer/preprocessing/util.py @@ -411,13 +411,13 @@ def cat(self, path, ext='.nii' ,verbose=False, force=False): for i,fname in enumerate(miflist): cat_arg.append(fname) cat_arg.append( - op.join(path, ('dwi_designer' + '.mif'))) + op.join(path, ('raw_dwi' + '.mif'))) cmd = ' '.join(str(e) for e in cat_arg) completion = subprocess.run(cmd, shell=True) if completion.returncode != 0: raise Exception('Failed to concatenate multiple ' 'series.') - miflist.append(op.join(path, 'dwi_designer' + '.mif')) + miflist.append(op.join(path, 'raw_dwi' + '.mif')) # Output concatenate .mif into .nii convert_args = ['mrconvert -stride 1,2,3,4'] if verbose is False: @@ -425,12 +425,12 @@ def cat(self, path, ext='.nii' ,verbose=False, force=False): if force is True: convert_args.append('-force') convert_args.append('-export_grad_fsl') - convert_args.append(op.join(path, 'dwi_designer.bvec')) - convert_args.append(op.join(path, 'dwi_designer.bval')) + convert_args.append(op.join(path, 'raw_dwi.bvec')) + convert_args.append(op.join(path, 'raw_dwi.bval')) convert_args.append('-json_export') - convert_args.append(op.join(path, 'dwi_designer.json')) - convert_args.append(op.join(path, 'dwi_designer.mif')) - convert_args.append(op.join(path, 'dwi_designer' + ext)) + convert_args.append(op.join(path, 'raw_dwi.json')) + convert_args.append(op.join(path, 'raw_dwi.mif')) + convert_args.append(op.join(path, 'raw_dwi' + ext)) cmd = ' '.join(str(e) for e in convert_args) completion = subprocess.run(cmd, shell=True) if completion.returncode != 0: diff --git a/designer/pydesigner.py b/designer/pydesigner.py index fe55d2a1..440d3b73 100644 --- a/designer/pydesigner.py +++ b/designer/pydesigner.py @@ -224,7 +224,7 @@ image.cat(path=outpath, verbose=args.verbose, force=args.force) - args.dwi = op.join(outpath, 'dwi_designer.nii') + args.dwi = op.join(outpath, 'raw_dwi.nii') #--------------------------------------------------------------------- # Validate Arguments From 447255155a1d14891d912590983ff56497b0998a Mon Sep 17 00:00:00 2001 From: Siddhartha Dhiman Date: Fri, 18 Oct 2019 19:18:54 -0400 Subject: [PATCH 5/7] Add exception if concatenated gradient table fails --- designer/preprocessing/util.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/designer/preprocessing/util.py b/designer/preprocessing/util.py index 1538a9af..5300c02f 100644 --- a/designer/preprocessing/util.py +++ b/designer/preprocessing/util.py @@ -434,7 +434,13 @@ def cat(self, path, ext='.nii' ,verbose=False, force=False): cmd = ' '.join(str(e) for e in convert_args) completion = subprocess.run(cmd, shell=True) if completion.returncode != 0: - raise Exception('Conversion to ' + ext + ' failed.') + raise Exception('Conversion to ' + ext + ' failed. Please ' + 'ensure that your input NifTi files have ' + 'the same phase encoding directions, and ' + 'are accompanied by valid .bval, .bvec, ' + 'and .json. If this is not possible, ' + 'please provide manually concatenated ' + 'DWIs or run with single series input.') for i, fname in enumerate(miflist): os.remove(fname) def getPath(self): @@ -456,6 +462,11 @@ def json2fslgrad(self, path): Path to NifTi file """ image = DWIFile(path) + if not image.hasJSON(): + raise Exception('It is not advisable to run multi-series ' + 'processing without `.json` files. Please ' + 'ensure your NifTi files come with .json ' + 'files.') args_info = ['mrinfo', path] cmd = ' '.join(str(e) for e in args_info) # Reads the "Dimension line of `mrinfo` and extracts the size From b480baa81128c861e7f8a34fd938e919d03547a4 Mon Sep 17 00:00:00 2001 From: Siddhartha Dhiman Date: Fri, 18 Oct 2019 19:25:30 -0400 Subject: [PATCH 6/7] Expands reason for concatenation failure --- designer/preprocessing/util.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/designer/preprocessing/util.py b/designer/preprocessing/util.py index 5300c02f..d6d4ddc5 100644 --- a/designer/preprocessing/util.py +++ b/designer/preprocessing/util.py @@ -434,10 +434,13 @@ def cat(self, path, ext='.nii' ,verbose=False, force=False): cmd = ' '.join(str(e) for e in convert_args) completion = subprocess.run(cmd, shell=True) if completion.returncode != 0: - raise Exception('Conversion to ' + ext + ' failed. Please ' - 'ensure that your input NifTi files have ' - 'the same phase encoding directions, and ' - 'are accompanied by valid .bval, .bvec, ' + for i, fname in enumerate(miflist): + os.remove(fname) + os.remove(op.join(path, 'raw_dwi' + ext)) + raise Exception('Concatenation to ' + str(ext) + 'failed. ' + 'Please ensure that your input NifTi files ' + 'have the same phase encoding directions, ' + 'and are accompanied by valid .bval, .bvec, ' 'and .json. If this is not possible, ' 'please provide manually concatenated ' 'DWIs or run with single series input.') From 9f622ebd9269e8b6a26b2e345d7f38d7e2673864 Mon Sep 17 00:00:00 2001 From: Siddhartha Dhiman Date: Fri, 18 Oct 2019 19:32:02 -0400 Subject: [PATCH 7/7] Remove dirty whitespace --- designer/preprocessing/util.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/designer/preprocessing/util.py b/designer/preprocessing/util.py index d6d4ddc5..efd25f0b 100644 --- a/designer/preprocessing/util.py +++ b/designer/preprocessing/util.py @@ -490,8 +490,4 @@ def json2fslgrad(self, path): fPath = op.splitext(path)[0] np.savetxt((fPath + '.bvec'), bvec, delimiter=' ', fmt='%d') np.savetxt((fPath + '.bval'), np.c_[bval], delimiter=' ', - fmt='%d') - - - - + fmt='%d') \ No newline at end of file