Skip to content

Commit a27e683

Browse files
authored
Merge pull request #55 from Unique-Usman/solved
Generate a variety of testing data and came up command_line version of sim_vim_sig.py
2 parents 1a8785a + 56ee717 commit a27e683

File tree

6 files changed

+2152
-239
lines changed

6 files changed

+2152
-239
lines changed

phantoms/MR_XCAT_qMRI/b_values.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"original": [0.0, 1.0, 2.0, 5.0, 10.0, 20.0, 30.0, 50.0, 75.0, 100.0, 150.0, 250.0, 350.0, 400.0, 550.0, 700.0, 850.0, 1000.0],
3+
"one": [0.0, 1.0, 2.0, 5.0, 10.0, 20.0, 30.0, 50.0, 75.0, 100.0, 150.0, 250.0, 350.0, 400.0, 550.0, 700.0, 850.0, 1000.0, 1100.0, 1200.0],
4+
"two": [0.0, 1.0, 2.0, 5.0, 10.0, 20.0, 30.0, 50.0, 75.0, 100.0, 150.0, 250.0, 350.0, 400.0, 500.0, 700.0, 800.0, 1000.0, 1100.0, 1200.0],
5+
"three": [0.0, 1.0, 2.0, 5.0, 10.0, 20.0, 30.0, 50.0, 75.0, 100.0, 150.0, 250.0, 350.0, 450.0, 550.0, 675.0, 800.0],
6+
"four": [0.0, 1.0, 2.0, 5.0, 10.0, 20.0, 30.0, 50.0, 75.0, 100.0, 150.0, 250.0, 300.0, 400.0, 500.0, 600.0, 700.0, 800.0]
7+
}

phantoms/MR_XCAT_qMRI/sim_ivim_sig.py

Lines changed: 112 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
from scipy.io import loadmat
33
import nibabel as nib
44
import json
5+
import argparse
6+
import os
57
from utilities.data_simulation.Download_data import download_data
68

79
##########
@@ -10,7 +12,6 @@
1012
# This code generates a 4D IVIM phantom as nifti file
1113

1214
def phantom(bvalue, noise, TR=3000, TE=40, motion=False, rician=False, interleaved=False):
13-
download_data()
1415
np.random.seed(42)
1516
if motion:
1617
states = range(1,21)
@@ -366,76 +367,124 @@ def XCAT_to_MR_DCE(XCAT, TR, TE, bvalue, D, f, Ds, b0=3, ivim_cont = True):
366367
return MR, Dim, fim, Dpim, legend
367368

368369
if __name__ == '__main__':
369-
bvalue = np.array([0., 1, 2, 5, 10, 20, 30, 50, 75, 100, 150, 250, 350, 400, 550, 700, 850, 1000])
370-
noise = 0.0005
371-
motion = False
372-
interleaved = False
373-
sig, XCAT, Dim, fim, Dpim, legend = phantom(bvalue, noise, motion=motion, interleaved=interleaved)
374-
# sig = np.flip(sig,axis=0)
375-
# sig = np.flip(sig,axis=1)
376-
res=np.eye(4)
377-
res[2]=2
370+
parser = argparse.ArgumentParser(description=f"""
371+
A commandline for generating a 4D IVIM phantom as nifti file
372+
""")
378373

379-
voxel_selector_fraction = 0.5
380-
D, f, Ds = contrast_curve_calc()
381-
ignore = np.isnan(D)
382-
generic_data = {}
383-
for level, name in legend.items():
384-
if len(ignore) > level and ignore[level]:
385-
continue
386-
selector = XCAT == level
387-
voxels = sig[selector]
388-
if len(voxels) < 1:
389-
continue
390-
signals = np.squeeze(voxels[int(voxels.shape[0] * voxel_selector_fraction)]).tolist()
391-
generic_data[name] = {
392-
'noise': noise,
393-
'D': np.mean(Dim[selector], axis=0),
394-
'f': np.mean(fim[selector], axis=0),
395-
'Dp': np.mean(Dpim[selector], axis=0),
396-
'data': signals
397-
}
398-
generic_data['config'] = {
399-
'bvalues': bvalue.tolist()
400-
}
401-
with open('generic.json', 'w') as f:
402-
json.dump(generic_data, f, indent=4)
374+
def parse_bvalues_file(file_path):
375+
"""Used for passing the JSON file"""
376+
if not os.path.exists(file_path):
377+
raise argparse.ArgumentTypeError(f"File '{file_path}' does not exist")
403378

379+
try:
380+
with open(file_path, "r") as file:
381+
bvalues_dict = json.load(file)
382+
if not isinstance(bvalues_dict, dict):
383+
raise argparse.ArgumentTypeError("JSON file does not contain a dict of b-values")
384+
for _, bvalue in bvalues_dict.items():
385+
if not isinstance(bvalue, list):
386+
raise argparse.ArgumentTypeError("bvalues in JSON file are not list")
387+
for value in bvalue:
388+
if not isinstance(value, float):
389+
raise argparse.ArgumentTypeError("Values in lists are not float")
390+
except json.JSONDecodeError as e:
391+
raise argparse.ArgumentTypeError(f"Invalid JSON file: {e}")
404392

405-
nifti_img = nib.Nifti1Image(sig, affine=res) # Replace affine if necessary
406-
# Save the NIfTI image to a file
407-
nifti_img.header.set_data_dtype(np.float64)
408-
if not motion:
409-
output_file = 'output.nii.gz' # Replace with your desired output file name
410-
elif interleaved:
411-
output_file = 'output_resp_int.nii.gz' # Replace with your desired output file name
393+
return bvalues_dict
394+
395+
parser.add_argument("-b", "--bvalue", type=float,
396+
nargs="+",
397+
help="B values (list of of numbers)")
398+
parser.add_argument("-f", "--bvalues-file", metavar="FILE", type=parse_bvalues_file,
399+
help='JSON file containing the b-values')
400+
parser.add_argument("-n", "--noise", type=float, default=0.0005, help="Noise")
401+
parser.add_argument("-m", "--motion", action="store_true", help="Motion flag")
402+
parser.add_argument("-i", "--interleaved", action="store_true", help="Interleaved flag")
403+
args = parser.parse_args()
404+
405+
if args.bvalues_file and args.bvalue:
406+
raise argparse.ArgumentError(None, "Arguments --bvalues-file and --bvalues are mutually exclusive")
407+
408+
bvalues = None
409+
if args.bvalues_file:
410+
bvalues = args.bvalues_file
411+
elif args.bvalue:
412+
bvalues = {"cmd": args.bvalue}
412413
else:
413-
output_file = 'output_resp.nii.gz' # Replace with your desired output file name
414+
bvalues = parse_bvalues_file("b_values.json")
415+
416+
417+
noise = args.noise
418+
motion = args.motion
419+
interleaved = args.interleaved
420+
download_data()
421+
for key, bvalue in bvalues.items():
422+
bvalue = np.array(bvalue)
423+
sig, XCAT, Dim, fim, Dpim, legend = phantom(bvalue, noise, motion=motion, interleaved=interleaved)
424+
# sig = np.flip(sig,axis=0)
425+
# sig = np.flip(sig,axis=1)
426+
res=np.eye(4)
427+
res[2]=2
428+
429+
voxel_selector_fraction = 0.5
430+
D, f, Ds = contrast_curve_calc()
431+
ignore = np.isnan(D)
432+
generic_data = {}
433+
for level, name in legend.items():
434+
if len(ignore) > level and ignore[level]:
435+
continue
436+
selector = XCAT == level
437+
voxels = sig[selector]
438+
if len(voxels) < 1:
439+
continue
440+
signals = np.squeeze(voxels[int(voxels.shape[0] * voxel_selector_fraction)]).tolist()
441+
generic_data[name] = {
442+
'noise': noise,
443+
'D': np.mean(Dim[selector], axis=0),
444+
'f': np.mean(fim[selector], axis=0),
445+
'Dp': np.mean(Dpim[selector], axis=0),
446+
'data': signals
447+
}
448+
generic_data['config'] = {
449+
'bvalues': bvalue.tolist()
450+
}
451+
with open(f'generic_{key}.json', 'w') as f:
452+
json.dump(generic_data, f, indent=4)
453+
454+
nifti_img = nib.Nifti1Image(sig, affine=res) # Replace affine if necessary
455+
# Save the NIfTI image to a file
456+
nifti_img.header.set_data_dtype(np.float64)
457+
if not motion:
458+
output_file = f'output_{key}.nii.gz' # Replace with your desired output file name
459+
elif interleaved:
460+
output_file = f'output_resp_int_{key}.nii.gz' # Replace with your desired output file name
461+
else:
462+
output_file = f'output_resp_{key}.nii.gz' # Replace with your desired output file name
414463

415-
nib.save(nifti_img, output_file)
464+
nib.save(nifti_img, output_file)
416465

417466

418-
nifti_img = nib.Nifti1Image(XCAT, affine=res) # Replace affine if necessary
419-
# Save the NIfTI image to a file
420-
output_file = 'output_xcat.nii.gz' # Replace with your desired output file name
421-
nib.save(nifti_img, output_file)
467+
nifti_img = nib.Nifti1Image(XCAT, affine=res) # Replace affine if necessary
468+
# Save the NIfTI image to a file
469+
output_file = f'output_xcat_{key}.nii.gz' # Replace with your desired output file name
470+
nib.save(nifti_img, output_file)
422471

423-
nifti_img = nib.Nifti1Image(Dim, affine=res) # Replace affine if necessary
424-
# Save the NIfTI image to a file
425-
nifti_img.header.set_data_dtype(np.float64)
426-
output_file = 'D.nii.gz' # Replace with your desired output file name
427-
nib.save(nifti_img, output_file)
472+
nifti_img = nib.Nifti1Image(Dim, affine=res) # Replace affine if necessary
473+
# Save the NIfTI image to a file
474+
nifti_img.header.set_data_dtype(np.float64)
475+
output_file = f'D_{key}.nii.gz' # Replace with your desired output file name
476+
nib.save(nifti_img, output_file)
428477

429-
nifti_img = nib.Nifti1Image(fim, affine=res) # Replace affine if necessary
430-
# Save the NIfTI image to a file
431-
nifti_img.header.set_data_dtype(np.float64)
432-
output_file = 'f.nii.gz' # Replace with your desired output file name
433-
nib.save(nifti_img, output_file)
478+
nifti_img = nib.Nifti1Image(fim, affine=res) # Replace affine if necessary
479+
# Save the NIfTI image to a file
480+
nifti_img.header.set_data_dtype(np.float64)
481+
output_file = f'f_{key}.nii.gz' # Replace with your desired output file name
482+
nib.save(nifti_img, output_file)
434483

435-
nifti_img = nib.Nifti1Image(Dpim, affine=res) # Replace affine if necessary
436-
# Save the NIfTI image to a file
437-
nifti_img.header.set_data_dtype(np.float64)
438-
output_file = 'Dp.nii.gz' # Replace with your desired output file name
439-
nib.save(nifti_img, output_file)
484+
nifti_img = nib.Nifti1Image(Dpim, affine=res) # Replace affine if necessary
485+
# Save the NIfTI image to a file
486+
nifti_img.header.set_data_dtype(np.float64)
487+
output_file = f'Dp_{key}.nii.gz' # Replace with your desired output file name
488+
nib.save(nifti_img, output_file)
440489

441-
np.savetxt('bvals.txt', bvalue)
490+
np.savetxt(f'bvals_{key}.txt', bvalue)

0 commit comments

Comments
 (0)