Skip to content

Commit 3b6bc16

Browse files
authored
Merge pull request #1 from OSIPI/main
Merge main into your base
2 parents 14fe4cb + fd84eff commit 3b6bc16

32 files changed

+2560
-152
lines changed

.github/workflows/unit_test.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,4 +33,4 @@ jobs:
3333
- name: Test with pytest
3434
run: |
3535
pip install pytest pytest-cov
36-
python -m pytest --doctest-modules --junitxml=junit/test-results.xml --cov=com --cov-report=xml --cov-report=html
36+
python -m pytest --doctest-modules --junitxml=junit/test-results.xml --cov=. --cov-report=xml --cov-report=html

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
.idea*
22
.github*
3-
*.nii.gz
43
__pycache__/
54

65

@@ -10,3 +9,4 @@ __pycache__/
109
.cache
1110
nosetests.xml
1211
coverage.xml
12+
*.pyc

doc/code_contributions_record.csv

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
Technique,Category,Subcategory,notes,subfolder,Link to source code,Authors,Institution,function/module,DOI,Tester,test status
2+
IVIM,Fitting,LSQ fitting,,OGC_AmsterdamUMC,TF2.4_IVIM-MRI_CodeCollection/src/original/OGC_AmsterdamUMC/,Oliver Gurney-Champion,Amsterdam UMC,fit_least_squares/fit_least_squares_array,,tbd,
3+
IVIM,Fitting,segmented LSQ fitting,,OGC_AmsterdamUMC,TF2.4_IVIM-MRI_CodeCollection/src/original/OGC_AmsterdamUMC/,Oliver Gurney-Champion,Amsterdam UMC,fit_segmented/fit_segmented_array,,tbd,
4+
Tri-exponential,Fitting,LSQ fitting,,OGC_AmsterdamUMC,TF2.4_IVIM-MRI_CodeCollection/src/original/OGC_AmsterdamUMC/,Oliver Gurney-Champion,Amsterdam UMC,fit_least_squares_tri_exp/fit_least_squares_array_tri_exp,,tbd,
5+
Tri-exponential,Fitting,Segmented LSQ fitting,,OGC_AmsterdamUMC,TF2.4_IVIM-MRI_CodeCollection/src/original/OGC_AmsterdamUMC/,Oliver Gurney-Champion,Amsterdam UMC,fit_segmented_tri_exp/fit_segmented_array_tri_exp,https://doi.org/10.3389/fphys.2022.942495,tbd,
6+
IVIM,Fitting,Bayesian,,OGC_AmsterdamUMC,TF2.4_IVIM-MRI_CodeCollection/src/original/OGC_AmsterdamUMC/,Oliver Gurney-Champion/Sebastiano Barbieri,Amsterdam UMC,fit_bayesian_array,https://doi.org/10.1002/mrm.28852,tbd,
7+
IVIM,Fitting,two-step segmented fit approach,also includes ADC calculation as a separate function,PvH_KB_NKI,TF2.4_IVIM-MRI_CodeCollection/src/original/PvH_KB_NKI/,Petra van Houdt/Stefan Zijlema/Koen Baas,the Netherlands Cancer Institute,DWI_functions_standalone.py,https://doi.org/10.3389/fonc.2021.705964,tbd,
8+
IVIM,Fitting,two-step (segmented) LSQ fitting, cut-off chosen for brain data; option to fit IVIM with inversion recovery or without IR,PV_MUMC,TF2.4_IVIM-MRI_CodeCollection/src/original/PV_MUMC/,Paulien Voorter,Maastricht University Medical Center,two_step_IVIM_fit.py,,tbd,
9+
IVIM,Fitting,bi-exponential NLLS,Supports units in mm2/s and µm2/ms,IAR_LundUniversity,TF2.4_IVIM-MRI_CodeCollection/src/original/IAR_LundUniversity/ivim_fit_method_biexp.py,Ivan A. Rashid,Lund University,IvimModelBiexp,tba,tbd,
10+
IVIM,Fitting,2-step segmented NLLS,First estimates and fixes D before a bi-exponential NLLS fit. Supports units in mm2/s and µm2/ms,IAR_LundUniversity,TF2.4_IVIM-MRI_CodeCollection/src/original/IAR_LundUniversity/ivim_fit_method_segmented_2step.py,Ivan A. Rashid,Lund University,IvimModelSegmented2Step,tba,tbd,
11+
IVIM,Fitting,3-step segmented NLLS,First estimates and fixes D followed by an estimate of D* followed by a bi-exponential NLLS fit. Supports units in mm2/s and µm2/ms,IAR_LundUniversity,TF2.4_IVIM-MRI_CodeCollection/src/original/IAR_LundUniversity/ivim_fit_method_segmented_3step.py,Ivan A. Rashid,Lund University,IvimModelSegmented3Step,tba,tbd,
12+
IVIM,Fitting,2-step segmented NLLS,First estimates and fixes D. Subtracts the diffusion signal and estimated D*. Supports units in mm2/s and µm2/ms,IAR_LundUniversity,TF2.4_IVIM-MRI_CodeCollection/src/original/IAR_LundUniversity/ivim_fit_method_subtracted.py,Ivan A. Rashid,Lund University,IvimModelSubtracted,tba,tbd,
13+
IVIM,Fitting,Variable projection,See referenced article. Supports units in mm2/s and µm2/ms,IAR_LundUniversity,TF2.4_IVIM-MRI_CodeCollection/src/original/IAR_LundUniversity/ivim_fit_method_modified_mix.py,Farooq et al. Modified by Ivan A. Rashid,Lund University,IvimModelVP,https://doi.org/10.1038/srep38927,tbd,
14+
IVIM,Fitting,Variable projection,See referenced article. Supports units in mm2/s and µm2/ms,IAR_LundUniversity,TF2.4_IVIM-MRI_CodeCollection/src/original/IAR_LundUniversity/ivim_fit_method_modified_topopro.py,Fadnavis et al. Modified by Ivan A. Rashid,Lund University,IvimModelTopoPro,https://doi.org/10.3389/fnins.2021.779025,tbd,
15+
IVIM,Fitting,Linear fit,Linear fit for D with extrapolation for f. Supports units in mm2/s and µm2/ms,IAR_LundUniversity,TF2.4_IVIM-MRI_CodeCollection/src/original/IAR_LundUniversity/ivim_fit_method_modified_linear.py,Modified by Ivan A. Rashid,Lund University,IvimModelLinear,tba,tbd,
16+
IVIM,Fitting,sIVIM fit,NLLS of the simplified IVIM model (sIVIM). Supports units in mm2/s and µm2/ms,IAR_LundUniversity,TF2.4_IVIM-MRI_CodeCollection/src/original/IAR_LundUniversity/ivim_fit_method_modified_sivim.py,Modified by Ivan A. Rashid,Lund University,IvimModelsIVIM,tba,tbd,
17+
IVIM,Fitting,Segmented NLLS fitting,MATLAB code,OJ_GU,TF2.4_IVIM-MRI_CodeCollection/src/original/OJ_GU/,Oscar Jalnefjord,University of Gothenburg,IVIM_seg,https://doi.org/10.1007/s10334-018-0697-5,tbd,
18+
IVIM,Fitting,Bayesian,MATLAB code,OJ_GU,TF2.4_IVIM-MRI_CodeCollection/src/original/OJ_GU/,Oscar Jalnefjord,University of Gothenburg,IVIM_bayes,https://doi.org/10.1002/mrm.26783,tbd,
19+
IVIM,Fitting,Linear fit,Linear fit for D and D* and f. Intended to be extremely fast but not always accurate,ETP_SRI,TF2.4_IVIM-MRI_CodeCollection/src/original/ETP_SRI/LinearFitting.py,Eric Peterson,SRI International,,,tbd,

phantoms/MR_XCAT_qMRI/sim_ivim_sig.py

Lines changed: 119 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import numpy as np
22
from scipy.io import loadmat
33
import nibabel as nib
4+
import json
45

56
##########
67
# code written by Oliver J Gurney-Champion
@@ -21,8 +22,8 @@ def phantom(bvalue, noise, TR=3000, TE=40, motion=False, rician=False, interleav
2122
XCAT = mat_data['IMG']
2223
XCAT = XCAT[0:-1:2,0:-1:2,10:160:4]
2324

24-
tissue_included, D, f, Ds = contrast_curve_calc()
25-
S, Dim, fim, Dpim = XCAT_to_MR_DCE(XCAT, TR, TE, bvalue, tissue_included, D, f, Ds)
25+
D, f, Ds = contrast_curve_calc()
26+
S, Dim, fim, Dpim, legend = XCAT_to_MR_DCE(XCAT, TR, TE, bvalue, D, f, Ds)
2627
if state == 1:
2728
Dim_out = Dim
2829
fim_out = fim
@@ -72,16 +73,15 @@ def phantom(bvalue, noise, TR=3000, TE=40, motion=False, rician=False, interleav
7273
state2 = state2+1
7374
else:
7475
S=np.squeeze(totsig)
75-
return S, XCAT, Dim_out, fim_out, Dpim_out
76+
return S, XCAT, Dim_out, fim_out, Dpim_out, legend
7677

7778

7879
def ivim(bvalues,D,f,Ds):
7980
return (1-f) * np.exp(-D * bvalues) + f * np.exp(-Ds * bvalues)
8081

8182
def contrast_curve_calc():
82-
tissue_included = np.array([1, 2, 3, 4, 5, 6, 7, 8, 13, 17, 18, 20, 22, 23, 24, 25, 26, 30, 36, 37, 40, 41, 42, 43, 50, 73])
8383

84-
D = np.zeros(74)
84+
D = np.full(74, np.nan)
8585
D[1] = 2.4e-3 # 1 Myocardium LV : Delattre et al. doi: 10.1097/RLI.0b013e31826ef901
8686
D[2] = 2.4e-3 # 2 myocardium RV: Delattre et al. doi: 10.1097/RLI.0b013e31826ef901
8787
D[3] = 2e-3 # 3 myocardium la
@@ -109,7 +109,7 @@ def contrast_curve_calc():
109109
D[50] = 3e-3 # 50 pericardium
110110
D[73] = 1.8e-3 # 73 Pancreatic tumor (advanced state, from literature)
111111

112-
f = np.zeros(74)
112+
f = np.full(74, np.nan)
113113
f[1] = 0.15 # 1 Myocardium LV : Delattre et al. doi: 10.1097/RLI.0b013e31826ef901
114114
f[2] = 0.15 # 2 myocardium RV : Delattre et al. doi: 10.1097/RLI.0b013e31826ef901
115115
f[3] = 0.07 # 3 myocardium la
@@ -137,7 +137,7 @@ def contrast_curve_calc():
137137
f[50] = 0.07 # 50 pericardium
138138
f[73] = 0.37 # 73 Pancreatic tumor (advanced state, from literature)
139139

140-
Ds = np.zeros(74)
140+
Ds = np.full(74, np.nan)
141141
Ds[1] = 0.08 # 1 Myocardium LV: Delattre et al. doi: 10.1097/RLI.0b013e31826ef901
142142
Ds[2] = 0.08 # 2 myocardium RV: Delattre et al. doi: 10.1097/RLI.0b013e31826ef901
143143
Ds[3] = 0.07 # 3 myocardium la
@@ -166,10 +166,10 @@ def contrast_curve_calc():
166166
Ds[73] = 0.01 # 73 Pancreatic tumor (advanced state, from literature)
167167
# Return values
168168

169-
return tissue_included, D, f, Ds
169+
return D, f, Ds
170170

171171

172-
def XCAT_to_MR_DCE(XCAT, TR, TE, bvalue, tissue_included, D, f, Ds, b0=3, ivim_cont = True):
172+
def XCAT_to_MR_DCE(XCAT, TR, TE, bvalue, D, f, Ds, b0=3, ivim_cont = True):
173173
###########################################################################################
174174
# This script converts XCAT tissue values to MR contrast based on the SSFP signal equation.
175175
# Christopher W. Roy 2018-12-04 # fetal.xcmr@gmail.com
@@ -180,78 +180,81 @@ def XCAT_to_MR_DCE(XCAT, TR, TE, bvalue, tissue_included, D, f, Ds, b0=3, ivim_c
180180
# Stanisz GJ, Odrobina EE, Pun J, Escaravage M, Graham SJ, Bronskill MJ, Henkelman RM. T1, T2 relaxation and magnetization transfer in tissue at 3T. Magnetic resonance in medicine. 2005;54:507�12.
181181
# Portnoy S, Osmond M, Zhu MY, Seed M, Sled JG, Macgowan CK. Relaxation properties of human umbilical cord blood at 1.5 Tesla. Magnetic Resonance in Medicine. 2016;00:1�13.
182182
# https://www.itis.ethz.ch/virtual-population/tissue-properties/XCATbase/relaxation-times/ #Tissue legend:
183-
# 1 Myocardium LV
184-
# 2 myocardium RV #
185-
# 3 myocardium la
186-
# 4 myocardium ra # 5 Blood LV
187-
#6 Blood RV
188-
#7 Blood LA
189-
#8 Blood RA
190-
#9 body
191-
#10 muscle
192-
#11 Brain
193-
#12 Sinus
194-
#13 Liver
195-
#14 gall bladder
196-
#15 Right Lung
197-
#16 Left Lung
198-
#17 esophagus
199-
#18 esophagus cont
200-
#19 laryngopharynx
201-
#20 st wall
202-
#21 Stomach Contents
203-
#22 pancreas
204-
#23 Right kydney cortex
205-
#24 right kidney medulla
206-
#25 Left kidney cortex
207-
#26 left kidney medulla
208-
#27 adrenal
209-
#28 Right Renal Pelvis
210-
#29 Left Renal Pelvis
211-
#30 spleen
212-
#31 Ribs
213-
#32 Cortical Bone
214-
#33 Spine
215-
#34 spinal cord
216-
#35 Bone Marrow
217-
#36 Artery
218-
#37 Vein
219-
#38 bladder
220-
#39 prostate
221-
#40 asc lower intestine
222-
#41 trans lower intestine
223-
#42 desc lower intestine
224-
#43 small intestine
225-
#44 rectum
226-
#45 seminal vescile
227-
#46 vas deference
228-
#47 testicles
229-
#48 epididymus
230-
#49 ejac duct
231-
#50 pericardium
232-
#51 Cartilage
233-
#52 Intestine Cavity
234-
#53 ureter
235-
#54 urethra
236-
#55 Lymph
237-
#56 lymph abnormal
238-
#57 trach bronch
239-
#58 Airway
240-
#59 uterus
241-
#60 vagina
242-
#61 right ovary
243-
#62 left ovary
244-
#63 FAllopian tubes
245-
#64 Parathyroid
246-
#65 Thyroid
247-
#66 Thymus
248-
#67 salivary
249-
#68 Pituitary
250-
#69 Eye
251-
#70 eye lens
252-
#71 lesion
253-
#72 Fat
254-
# 73 Pancreas tumor ##############################################################################
183+
legend = {
184+
1: 'Myocardium LV',
185+
2: 'myocardium RV', #
186+
3: 'myocardium la',
187+
4: 'myocardium ra', # 5 Blood LV
188+
6: 'Blood RV',
189+
7: 'Blood LA',
190+
8: 'Blood RA',
191+
9: 'body',
192+
10: 'muscle',
193+
11: 'Brain',
194+
12: 'Sinus',
195+
13: 'Liver',
196+
14: 'gall bladder',
197+
15: 'Right Lung',
198+
16: 'Left Lung',
199+
17: 'esophagus',
200+
18: 'esophagus cont',
201+
19: 'laryngopharynx',
202+
20: 'st wall',
203+
21: 'Stomach Contents',
204+
22: 'pancreas',
205+
23: 'Right kydney cortex',
206+
24: 'right kidney medulla',
207+
25: 'Left kidney cortex',
208+
26: 'left kidney medulla',
209+
27: 'adrenal',
210+
28: 'Right Renal Pelvis',
211+
29: 'Left Renal Pelvis',
212+
30: 'spleen',
213+
31: 'Ribs',
214+
32: 'Cortical Bone',
215+
33: 'Spine',
216+
34: 'spinal cord',
217+
35: 'Bone Marrow',
218+
36: 'Artery',
219+
37: 'Vein',
220+
38: 'bladder',
221+
39: 'prostate',
222+
40: 'asc lower intestine',
223+
41: 'trans lower intestine',
224+
42: 'desc lower intestine',
225+
43: 'small intestine',
226+
44: 'rectum',
227+
45: 'seminal vescile',
228+
46: 'vas deference',
229+
47: 'testicles',
230+
48: 'epididymus',
231+
49: 'ejac duct',
232+
50: 'pericardium',
233+
51: 'Cartilage',
234+
52: 'Intestine Cavity',
235+
53: 'ureter',
236+
54: 'urethra',
237+
55: 'Lymph',
238+
56: 'lymph abnormal',
239+
57: 'trach bronch',
240+
58: 'Airway',
241+
59: 'uterus',
242+
60: 'vagina',
243+
61: 'right ovary',
244+
62: 'left ovary',
245+
63: 'FAllopian tubes',
246+
64: 'Parathyroid',
247+
65: 'Thyroid',
248+
66: 'Thymus',
249+
67: 'salivary',
250+
68: 'Pituitary',
251+
69: 'Eye',
252+
70: 'eye lens',
253+
71: 'lesion',
254+
72: 'Fat',
255+
73: 'Pancreas tumor',
256+
}
257+
###############################################################################
255258
np.random.seed(42)
256259
Tissue = np.zeros((74, 4))
257260
Tissue[1] = [1030, 40, 1471, 47]
@@ -343,7 +346,7 @@ def XCAT_to_MR_DCE(XCAT, TR, TE, bvalue, tissue_included, D, f, Ds, b0=3, ivim_c
343346
T1 = Tissue[iTissue, 2]
344347
T2 = Tissue[iTissue, 3]
345348

346-
if ivim_cont and iTissue in tissue_included:
349+
if ivim_cont and not np.isnan([D[iTissue], f[iTissue], Ds[iTissue]]).any():
347350
# note we are assuming blood fraction has the same T1 as tissue fraction here for simplicity. Can be changed in future.
348351
Dtemp=D[iTissue]
349352
ftemp=f[iTissue]
@@ -352,28 +355,53 @@ def XCAT_to_MR_DCE(XCAT, TR, TE, bvalue, tissue_included, D, f, Ds, b0=3, ivim_c
352355
Dtemp=5e-4+np.random.rand(1)*3e-3
353356
ftemp=np.random.rand(1)*0.5
354357
Dstemp=5e-3+np.random.rand(1)*1e-1
355-
#S0 = np.zeros(len(bvalue))
356358
S0 = ivim(bvalue,Dtemp,ftemp,Dstemp)
357359
if T1 > 0 or T2 > 0:
358-
MR = MR + np.tile(np.expand_dims(XCAT == iTissue,3),len(S0)) * S0 * (1 - 2 * np.exp(-(TR - TE / 2) / T1) + np.exp(-TR / T1)) * np.exp(
359-
-TE / T2)
360+
MR = MR + np.tile(np.expand_dims(XCAT == iTissue,3),len(S0)) * S0 * (1 - 2 * np.exp(-(TR - TE / 2) / T1) + np.exp(-TR / T1)) * np.exp(-TE / T2)
360361
Dim = Dim + (XCAT == iTissue) * Dtemp
361362
fim = fim + (XCAT == iTissue) * ftemp
362363
Dpim = Dpim + (XCAT == iTissue) * Dstemp
363-
return MR, Dim, fim, Dpim
364+
return MR, Dim, fim, Dpim, legend
364365

365366
if __name__ == '__main__':
366367
bvalue = np.array([0., 1, 2, 5, 10, 20, 30, 50, 75, 100, 150, 250, 350, 400, 550, 700, 850, 1000])
367-
noise = 0.005
368+
noise = 0.0005
368369
motion = False
369-
sig, XCAT, Dim,fim,Dpim = phantom(bvalue, noise,motion=motion,interleaved=False)
370-
sig = sig * 50000
371-
sig = np.flip(sig,axis=0)
372-
sig = np.flip(sig,axis=1)
370+
sig, XCAT, Dim, fim, Dpim, legend = phantom(bvalue, noise, motion=motion, interleaved=False)
371+
# sig = np.flip(sig,axis=0)
372+
# sig = np.flip(sig,axis=1)
373373
res=np.eye(4)
374374
res[2]=2
375+
376+
voxel_selector_fraction = 0.5
377+
D, f, Ds = contrast_curve_calc()
378+
ignore = np.isnan(D)
379+
generic_data = {}
380+
for level, name in legend.items():
381+
if len(ignore) > level and ignore[level]:
382+
continue
383+
selector = XCAT == level
384+
voxels = sig[selector]
385+
if len(voxels) < 1:
386+
continue
387+
signals = np.squeeze(voxels[int(voxels.shape[0] * voxel_selector_fraction)]).tolist()
388+
generic_data[name] = {
389+
'noise': noise,
390+
'D': np.mean(Dim[selector], axis=0),
391+
'f': np.mean(fim[selector], axis=0),
392+
'Dp': np.mean(Dpim[selector], axis=0),
393+
'data': signals
394+
}
395+
generic_data['config'] = {
396+
'bvalues': bvalue.tolist()
397+
}
398+
with open('generic.json', 'w') as f:
399+
json.dump(generic_data, f, indent=4)
400+
401+
375402
nifti_img = nib.Nifti1Image(sig, affine=res) # Replace affine if necessary
376403
# Save the NIfTI image to a file
404+
nifti_img.header.set_data_dtype(np.float64)
377405
if motion:
378406
output_file = 'output_resp_int.nii.gz' # Replace with your desired output file name
379407
else:

src/original/ETP_SRI/LinearFitting.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
import numpy as np
22
import numpy.polynomial.polynomial as poly
33

4-
from utils.data_simulation.GenerateData import GenerateData
5-
6-
4+
from utilities.data_simulation.GenerateData import GenerateData
75

86
class LinearFit:
97
"""
@@ -17,6 +15,9 @@ def __init__(self, linear_cutoff=500):
1715
The b-value after which it can be assumed that the perfusion value is negligible
1816
"""
1917
self.linear_cutoff = linear_cutoff
18+
19+
def accepted_dimensions(self):
20+
return (1, 1)
2021

2122
def linear_fit(self, bvalues, signal, weighting=None, stats=False):
2223
"""
@@ -33,6 +34,8 @@ def linear_fit(self, bvalues, signal, weighting=None, stats=False):
3334
stats : boolean
3435
If true, return the polyfit statistics
3536
"""
37+
bvalues = np.asarray(bvalues)
38+
signal = np.asarray(signal)
3639
assert bvalues.size == signal.size, "Signal and b-values don't have the same number of values"
3740
if stats:
3841
D, stats = poly.polyfit(np.asarray(bvalues), signal, 1, full=True, w=weighting)

src/original/IAR_LundUniversity/ivim_fit_method_modified_topopro.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
class IvimModelTopoPro(ReconstModel):
1010

11-
def __init__(self, gtab, bounds=[[0,1], [0.005, 0.1], [1e-5, 0.004]], \
11+
def __init__(self, gtab, bounds=[[0, 0.005, 1e-5], [1, 0.1, 0.004]], \
1212
rescale_units=False, shgo_iters=5, rescale_results_to_mm2_s=False):
1313
r""" Initialize an IvimModelTP class.
1414
This particular script was modified as the DIPY version has stringent

0 commit comments

Comments
 (0)