-
Notifications
You must be signed in to change notification settings - Fork 36
Added the feature to read DICOM images into a 4D Nifti image #99
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
base: main
Are you sure you want to change the base?
Changes from 1 commit
4bc40f2
1e060cd
a4ce220
e331dfc
1247c2c
a5f63e6
0e496b6
ae56831
317d72d
783e2f3
5347a31
22df73a
d18c2e6
3dbb64c
606b667
9a17fb1
614c8f8
dda0e88
ac752cb
92abf87
201f495
d32460b
9cd090f
30a0603
64dc1bc
682d655
814cdc9
015f7dc
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,11 +1,51 @@ | ||
import argparse | ||
import json | ||
import os | ||
from pathlib import Path | ||
import subprocess | ||
import nibabel as nib | ||
from src.wrappers.OsipiBase import OsipiBase | ||
import numpy as np | ||
from tqdm import tqdm | ||
|
||
def dicom_to_niix(vol_dir: Path): | ||
""" | ||
For converting DICOM images to a (compresssed) 4d nifti image | ||
""" | ||
|
||
try: | ||
res = subprocess.run( | ||
[ | ||
"dcm2niix", | ||
"-f", "%s_%p", # dcm2niix attempts to provide a sensible file naming scheme | ||
"-o", vol_dir, | ||
"-z", "y", #specifying compressed nii.gz file | ||
# https://www.nitrc.org/plugins/mwiki/index.php/dcm2nii:MainPage | ||
# for further configuration for general usage see page above | ||
vol_dir | ||
jph6366 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
], | ||
capture_output=True, | ||
text=True, | ||
check=True | ||
) | ||
|
||
nifti_files = list(Path(vol_dir).glob("*.nii.gz")) | ||
if not nifti_files: | ||
raise RuntimeError("No NIfTI file generated by dcm2niix.") | ||
if len(nifti_files) > 1: | ||
raise RuntimeError("Multiple NIfTI files generated; expected one 4D NIfTI.") | ||
|
||
bval_files = list(vol_dir.glob("*.bval")) | ||
bvec_files = list(vol_dir.glob("*.bvec")) | ||
bval_path = str(bval_files[0]) if bval_files else None | ||
bvec_path = str(bvec_files[0]) if bvec_files else None | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is all making the assumption that we only want one. What if they're different, which do we choose then? I'm not exactly sure what dcm2niix outputs, but probably best is to require just one output and error if there are more. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For handling batch conversion for many files we could leverage the yaml config for batch processing, as specfied in the dicom2niix repo, so we can provide that option and updated instructions in the README. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
dicom2niix handles it nicely really by just adding characters in an alphabetical order e.g. len(nifti_files) = 0 *.bval, *.bvec *.nii.gz len(nifti_files) = 1 *a.bval, *a.bvec *a.nii.gz len(nifti_files) = 2 *b.bval, *b.bvec *b.nii.gz len(nifti_files) = 3 *c.bval, *c.bvec *c.nii.gz |
||
|
||
|
||
return vol_dir / "dicom2nifti.nii.gz", bval_path, bvec_path | ||
jph6366 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
except subprocess.CalledProcessError as e: | ||
raise RuntimeError(f"dcm2niix failed: {e.stderr}") | ||
|
||
|
||
def read_nifti_file(input_file): | ||
""" | ||
|
@@ -81,22 +121,35 @@ def loop_over_first_n_minus_1_dimensions(arr): | |
|
||
if __name__ == "__main__": | ||
parser = argparse.ArgumentParser(description="Read a 4D NIfTI phantom file along with BIDS JSON, b-vector, and b-value files.") | ||
parser.add_argument("input_file", type=str, help="Path to the input 4D NIfTI file.") | ||
parser.add_argument("bvec_file", type=str, help="Path to the b-vector file.") | ||
parser.add_argument("bval_file", type=str, help="Path to the b-value file.") | ||
parser.add_argument("input_file", type=Path, help="Path to the input 4D NIfTI file or DICOM files 4D images like fMRI and DTI/DKI are supported..") | ||
parser.add_argument("bvec_file", type=Path, help="Path to the b-vector file.") | ||
parser.add_argument("bval_file", type=Path, help="Path to the b-value file.") | ||
parser.add_argument("--affine", type=float, nargs="+", help="Affine matrix for NIfTI image.") | ||
parser.add_argument("--algorithm", type=str, default="OJ_GU_seg", help="Select the algorithm to use.") | ||
parser.add_argument("--algorithm_args", nargs=argparse.REMAINDER, help="Additional arguments for the algorithm.") | ||
|
||
args = parser.parse_args() | ||
|
||
try: | ||
if args.input_file.is_dir(): | ||
# Convert DICOM to NIfTI using dicom2niix | ||
nifti_file, bval_path, bvec_path = dicom_to_niix(args.input_file) # read dir | ||
if bval_path is None or bvec_path is None: | ||
raise RuntimeError("dcm2niix did not generate bval/bvec files.") | ||
bval_file = Path(bval_path) | ||
bvec_file = Path(bvec_path) | ||
else: | ||
# Assume input is already a NIfTI file | ||
nifti_file = args.input_file | ||
bval_file = args.bval_file | ||
bvec_file = args.bvec_file | ||
|
||
# Read the 4D NIfTI file | ||
data, _ = read_nifti_file(args.input_file) | ||
data, _ = read_nifti_file(nifti_file) | ||
|
||
# Read the b-vector, and b-value files | ||
bvecs = read_bvec_file(args.bvec_file) | ||
bvals = read_bval_file(args.bval_file) | ||
bvecs = read_bvec_file(bvec_file) | ||
bvals = read_bval_file(bval_file) | ||
|
||
# Pass additional arguments to the algorithm | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This could be a separate build stage in the dockerfile. That simplifies the cleanup.
I'm also wondering about the version. Is there a way we can select the latest stable?
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it seems the easiest way to do it is just pin the latest version.
We could query the GitHub API but then our docker environment will get rate limited without a personal access token for authorization. Ideally, we dont want to increase our dependency and just lean towards manual updates based on alerting users to make an issue to update the dockerfile.
there is an update check option to add to our dicom2niix subprocess call, this command will cause the software report if there are any newer versions of dcm2niix available online. (UNIX ONLY)