Skip to content

Commit 80fc936

Browse files
committed
added additional checks between nifti and dicom
1 parent 97237b1 commit 80fc936

File tree

1 file changed

+52
-8
lines changed

1 file changed

+52
-8
lines changed

pypet2bids/pypet2bids/dcm2niix4pet.py

Lines changed: 52 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import shutil
3030
import argparse
3131
import importlib
32+
from nibabel import load
3233

3334
try:
3435
import helper_functions
@@ -176,6 +177,7 @@ def __init__(
176177
silent=False,
177178
tempdir_location=None,
178179
ezbids=False,
180+
ignore_dcm2niix_errors=False,
179181
):
180182
"""
181183
This class is a simple wrapper for dcm2niix and contains methods to do the following in order:
@@ -223,7 +225,7 @@ def __init__(
223225
"dcm2niix not found, this module depends on it for conversions, exiting."
224226
)
225227
sys.exit(1)
226-
228+
self.ignore_dcm2niix_errors = ignore_dcm2niix_errors
227229
# check for the version of dcm2niix
228230
minimum_version = "v1.0.20220720"
229231
version_string = subprocess.run([self.dcm2niix_path, "-v"], capture_output=True)
@@ -489,7 +491,7 @@ def run_dcm2niix(self):
489491
if (
490492
convert.returncode != 0
491493
or "error" in convert.stderr.decode("utf-8").lower()
492-
):
494+
) and not self.ignore_dcm2niix_errors:
493495
print(
494496
"Check output .nii files, dcm2iix returned these errors during conversion:"
495497
)
@@ -570,12 +572,46 @@ def run_dcm2niix(self):
570572
# often a series of dicoms is incomplete (missing files) but dcm2niix can still
571573
# output a nifti at the end. We can compare the outputs of dcm2niix with the
572574
# frame information in the dicom header.
573-
574-
# collect the number of frames that are present in the nifti
575-
576-
# collect the number of frames that are listed in the sidecar, duration, etc
577-
578-
# collect any frame timing info that may be contained in additional arguments or the spreadsheet metadata
575+
for dicom, matched in matched_dicoms_and_headers.items():
576+
matched_dicom = pydicom.dcmread(
577+
join(self.image_folder, dicom), stop_before_pixels=True
578+
)
579+
matched_json = next(
580+
(f for f in matched if f.endswith(".json")), None
581+
)
582+
matched_nii = next(
583+
(
584+
load(f)
585+
for f in matched
586+
if f.endswith(".nii") or f.endswith(".nii.gz")
587+
),
588+
None,
589+
)
590+
if matched_nii:
591+
try:
592+
nifti_time_dim = matched_nii.shape[3]
593+
except IndexError:
594+
nifti_time_dim = 0
595+
if (
596+
matched_dicom.get("NumberOfTimeSlices")
597+
!= nifti_time_dim
598+
and not self.ignore_dcm2niix_errors
599+
):
600+
raise Exception(
601+
f"NifTi produced has {nifti_time_dim} timing frames, should have {matched_dicom.get('NumberOfTimeSlices')} instead."
602+
)
603+
if matched_json:
604+
with open(matched_json, "r") as infile:
605+
matched_json = json.load(infile)
606+
json_num_frames = len(matched_json.get("FrameDuration", []))
607+
if (
608+
matched_dicom.get("NumberOfTimeSlices")
609+
!= json_num_frames
610+
and not self.ignore_dcm2niix_errors
611+
):
612+
raise Exception(
613+
f"Length of FrameDuration is {json_num_frames} should match {matched_dicom.filename}'s NumberOfTimeSlices value {matched_dicom.get('NumberOfTimeSlices')} instead"
614+
)
579615

580616
# we check to see what's missing from our recommended and required jsons by gathering the
581617
# output of check_json silently
@@ -1193,6 +1229,13 @@ def cli():
11931229
help="Add fields to json output that are useful for ezBIDS or other conversion software. This will de-anonymize"
11941230
" pet2bids output and add AcquisitionDate an AcquisitionTime into the output json.",
11951231
)
1232+
parser.add_argument(
1233+
"--ignore-dcm2niix-errors",
1234+
action="store_true",
1235+
default=False,
1236+
help="Accept any NifTi produced by dcm2niix even if it contains errors. This flag should only be used for "
1237+
"batch processing and only if you're performing robust QC after the fact.",
1238+
)
11961239
return parser
11971240

11981241

@@ -1360,6 +1403,7 @@ def main():
13601403
tempdir_location=cli_args.tempdir,
13611404
silent=cli_args.silent,
13621405
ezbids=cli_args.ezbids,
1406+
ignore_dcm2niix_errors=cli_args.ignore_dcm2niix_errors,
13631407
)
13641408

13651409
if cli_args.trc:

0 commit comments

Comments
 (0)