From bed3f1186394d3637146186a3bcf880d80061560 Mon Sep 17 00:00:00 2001 From: Michael Krause Date: Mon, 11 Nov 2024 22:37:59 +0100 Subject: [PATCH] Handle dcm2niix not compressing nifti files --- heudiconv/bids.py | 27 +++++++++++++++++++++++---- heudiconv/convert.py | 33 +++++++++++++++++++++++++++++---- 2 files changed, 52 insertions(+), 8 deletions(-) diff --git a/heudiconv/bids.py b/heudiconv/bids.py index 43781678..bb57ba2a 100644 --- a/heudiconv/bids.py +++ b/heudiconv/bids.py @@ -491,7 +491,7 @@ def save_scans_key( for bids_file in bids_files: # get filenames f_name = "/".join(bids_file.split("/")[-2:]) - f_name = f_name.replace("json", "nii.gz") + f_name = f_name.replace("json", outtype_from_bidsfile(bids_file)) rows[f_name] = get_formatted_scans_key_row(item[-1][0]) subj_, ses_ = find_subj_ses(f_name) if not subj_: @@ -938,9 +938,9 @@ def select_fmap_from_compatible_groups( # acq_times for the compatible fmaps: acq_times_fmaps = { k: acq_times[ - # remove session folder and '.json', add '.nii.gz': + # remove session folder and '.json', add outtype: remove_suffix(remove_prefix(v[0], sess_folder + op.sep), ".json") - + ".nii.gz" + + '.' + outtype_from_bidsfile(v[0]) ] for k, v in compatible_fmap_groups.items() } @@ -956,7 +956,7 @@ def select_fmap_from_compatible_groups( acq_times[ # remove session folder and '.json', add '.nii.gz': remove_suffix(remove_prefix(json_file, sess_folder + op.sep), ".json") - + ".nii.gz" + + '.' + outtype_from_bidsfile(json_file) ] ) # differences in acquisition time (abs value): @@ -1209,3 +1209,22 @@ def sanitize_label(label: str) -> str: clean_label, ) return clean_label + + +def outtype_from_bidsfile(json_file: str) -> str: + """Returns outtype ('nii' or 'nii.gz') for an existing json bids file + + Parameters + ---------- + filename: string + + Returns + ------- + fileext: string + file extension / outtype + """ + json_path = Path(json_file) + for suffix in ['nii.gz', 'nii']: + if op.exists(json_path.with_suffix('.' + suffix)): + return suffix + raise RuntimeError('No accompanying file found for %s' % json_file) diff --git a/heudiconv/convert.py b/heudiconv/convert.py index ec5639c6..a83b2cab 100644 --- a/heudiconv/convert.py +++ b/heudiconv/convert.py @@ -10,6 +10,7 @@ import re import shutil import sys +import json from types import ModuleType from typing import TYPE_CHECKING, Any, List, Optional, cast @@ -620,16 +621,40 @@ def convert( description="DICOM to NIfTI + .json sidecar conversion utility", tags=["implementation"], ) - outname, scaninfo = (prefix + "." + outtype, prefix + scaninfo_suffix) + outnames = [prefix + "." + t for t in ["nii", "nii.gz"]] + scaninfo = prefix + scaninfo_suffix - if not op.exists(outname) or overwrite: + if not any([op.exists(outname) for outname in outnames]) or overwrite: tmpdir = tempdirs("dcm2niix") + # demote outtype if dcmconfig explicitly disables compression + # and issue a warning (user supplied mixed signals here) + if dcmconfig is not None: + with open(dcmconfig) as f: + dcmconfig_dict = json.loads(f.read()) + if dcmconfig_dict.get('compress', 'y') == 'n': + outtype = 'nii' + lgr.warning("Demoting outtype to uncompressed nifti, because " + "compress is set to 'n' in supplied dcmconfig") + # run conversion through nipype res, prov_file = nipype_convert( item_dicoms, prefix, with_prov, bids_options, tmpdir, dcmconfig ) + # try to handle compression failures from dcm2niix + if outtype == 'nii.gz': + converted_files = res.outputs.converted_files + if isinstance(converted_files, list): + # we do not handle mixed compression results from dcm2niix, yet + # fail, if any of the outputs weren't compressed properly + assert all([x.endswith('nii.gz') for x in converted_files]) + else: + if converted_files.endswith('nii'): + lgr.warning("Conversion returned uncompressed nifti (>4GB?) - " + "demoting outtype to 'nii'") + outtype = 'nii' + bids_outfiles = save_converted_files( res, item_dicoms, @@ -653,8 +678,8 @@ def convert( tempdirs.rmtree(tmpdir) else: raise RuntimeError( - "was asked to convert into %s but destination already exists" - % (outname) + "was asked to convert into %s.nii[.gz] but destination already exists" + % (prefix) ) # add the taskname field to the json file(s):