antspymm 0.9.7__py3-none-any.whl → 1.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- antspymm/__init__.py +6 -0
- antspymm/mm.py +638 -101
- {antspymm-0.9.7.dist-info → antspymm-1.0.0.dist-info}/METADATA +13 -2
- antspymm-1.0.0.dist-info/RECORD +7 -0
- antspymm-0.9.7.dist-info/RECORD +0 -7
- {antspymm-0.9.7.dist-info → antspymm-1.0.0.dist-info}/LICENSE +0 -0
- {antspymm-0.9.7.dist-info → antspymm-1.0.0.dist-info}/WHEEL +0 -0
- {antspymm-0.9.7.dist-info → antspymm-1.0.0.dist-info}/top_level.txt +0 -0
antspymm/__init__.py
CHANGED
@@ -5,6 +5,10 @@ except:
|
|
5
5
|
pass
|
6
6
|
|
7
7
|
from .mm import get_data
|
8
|
+
from .mm import get_dti
|
9
|
+
from .mm import triangular_to_tensor
|
10
|
+
from .mm import dti_numpy_to_image
|
11
|
+
from .mm import transform_and_reorient_dti
|
8
12
|
from .mm import get_models
|
9
13
|
from .mm import nrg_format_path
|
10
14
|
from .mm import highest_quality_repeat
|
@@ -84,3 +88,5 @@ from .mm import novelty_detection_quantile
|
|
84
88
|
from .mm import generate_mm_dataframe
|
85
89
|
from .mm import collect_blind_qc_by_modality
|
86
90
|
from .mm import get_valid_modalities
|
91
|
+
from .mm import study_dataframe_from_matched_dataframe
|
92
|
+
from .mm import merge_wides_to_study_dataframe
|
antspymm/mm.py
CHANGED
@@ -13,6 +13,7 @@ __all__ = ['version',
|
|
13
13
|
'merge_dwi_data',
|
14
14
|
'outlierness_by_modality',
|
15
15
|
'bvec_reorientation',
|
16
|
+
'get_dti',
|
16
17
|
'dti_reg',
|
17
18
|
'mc_reg',
|
18
19
|
'get_data',
|
@@ -78,6 +79,8 @@ __all__ = ['version',
|
|
78
79
|
'novelty_detection_loop',
|
79
80
|
'novelty_detection_quantile',
|
80
81
|
'generate_mm_dataframe',
|
82
|
+
'study_dataframe_from_matched_dataframe',
|
83
|
+
'merge_wides_to_study_dataframe',
|
81
84
|
'wmh']
|
82
85
|
|
83
86
|
from pathlib import Path
|
@@ -419,7 +422,7 @@ def collect_blind_qc_by_modality( modality_path, set_index_to_fn=True ):
|
|
419
422
|
|
420
423
|
def outlierness_by_modality( qcdf, uid='fn', outlier_columns = ['noise', 'snr', 'cnr', 'psnr', 'ssim', 'mi','reflection_err', 'EVR', 'msk_vol'], verbose=False ):
|
421
424
|
"""
|
422
|
-
Calculates outlierness scores for each modality in a dataframe based on given outlier columns using antspyt1w.loop_outlierness() and LOF. LOF appears to be more conservative.
|
425
|
+
Calculates outlierness scores for each modality in a dataframe based on given outlier columns using antspyt1w.loop_outlierness() and LOF. LOF appears to be more conservative. This function will impute missing columns with the mean.
|
423
426
|
|
424
427
|
Args:
|
425
428
|
- qcdf: (Pandas DataFrame) Dataframe containing columns with outlier information for each modality.
|
@@ -450,6 +453,9 @@ def outlierness_by_modality( qcdf, uid='fn', outlier_columns = ['noise', 'snr',
|
|
450
453
|
lof = LocalOutlierFactor()
|
451
454
|
locsel = qcdfout["modality"] == mod
|
452
455
|
rr = qcdfout[locsel][outlier_columns]
|
456
|
+
with pd.option_context('mode.use_inf_as_na', True):
|
457
|
+
for myolcol in outlier_columns:
|
458
|
+
rr[myolcol].fillna(rr[myolcol].mean(), inplace=True)
|
453
459
|
if rr.shape[0] > 1:
|
454
460
|
if verbose:
|
455
461
|
print(mod)
|
@@ -494,6 +500,98 @@ def nrg_format_path( projectID, subjectID, date, modality, imageID, separator='-
|
|
494
500
|
thefilename = str(projectID) + separator + str(subjectID) + separator + str(date) + separator + str(modality) + separator + str(imageID)
|
495
501
|
return os.path.join( thedirectory, thefilename )
|
496
502
|
|
503
|
+
|
504
|
+
def study_dataframe_from_matched_dataframe( matched_dataframe, rootdir, outputdir, verbose=False ):
|
505
|
+
"""
|
506
|
+
converts the output of antspymm.match_modalities dataframe (one row) to that needed for a study-driving dataframe for input to mm_csv
|
507
|
+
|
508
|
+
matched_dataframe : output of antspymm.match_modalities
|
509
|
+
|
510
|
+
rootdir : location for the input data root folder (in e.g. NRG format)
|
511
|
+
|
512
|
+
outputdir : location for the output data
|
513
|
+
|
514
|
+
verbose : boolean
|
515
|
+
"""
|
516
|
+
iext='.nii.gz'
|
517
|
+
from os.path import exists
|
518
|
+
musthavecols = ['projectID', 'subjectID','date','imageID','fn']
|
519
|
+
for k in range(len(musthavecols)):
|
520
|
+
if not musthavecols[k] in matched_dataframe.keys():
|
521
|
+
raise ValueError('matched_dataframe is missing column ' +musthavecols[k] + ' in study_dataframe_from_qc_dataframe' )
|
522
|
+
csvrow=matched_dataframe.dropna(axis=1)
|
523
|
+
pid=str(csvrow['projectID'].iloc[0] )
|
524
|
+
sid=str(csvrow['subjectID'].iloc[0] )
|
525
|
+
dt=str(csvrow['date'].iloc[0])
|
526
|
+
iid=str(csvrow['imageID'].iloc[0])
|
527
|
+
nrgt1fn=os.path.join( rootdir, pid, sid, dt, 'T1w', iid, str(csvrow['fn'].iloc[0]+iext) )
|
528
|
+
if not exists( nrgt1fn ):
|
529
|
+
raise ValueError("T1 " + nrgt1fn + " does not exist in study_dataframe_from_qc_dataframe")
|
530
|
+
flList=[]
|
531
|
+
dtList=[]
|
532
|
+
rsfList=[]
|
533
|
+
nmList=[]
|
534
|
+
if 'flairfn' in csvrow.keys():
|
535
|
+
flid=str(int(csvrow['flairid'].iloc[0]))
|
536
|
+
nrgt2fn=os.path.join( rootdir, pid, sid, dt, 'T2Flair', flid, str(csvrow['flairfn'].iloc[0]+iext) )
|
537
|
+
if exists( nrgt2fn ):
|
538
|
+
flList.append( nrgt2fn )
|
539
|
+
if 'dtfn1' in csvrow.keys():
|
540
|
+
dtid=str(int(csvrow['dtid1'].iloc[0]))
|
541
|
+
dtfn1=glob.glob(os.path.join( rootdir, pid, sid, dt, 'DTI*', dtid, str(csvrow['dtfn1'].iloc[0]+iext) ))[0]
|
542
|
+
if exists( dtfn1 ):
|
543
|
+
dtList.append( dtfn1 )
|
544
|
+
if 'dtfn2' in csvrow.keys():
|
545
|
+
dtid=str(int(csvrow['dtid2'].iloc[0]))
|
546
|
+
dtfn2=glob.glob(os.path.join(rootdir, pid, sid, dt, 'DTI*', dtid, str(csvrow['dtfn2'].iloc[0]+iext) ))[0]
|
547
|
+
if exists( dtfn2 ):
|
548
|
+
dtList.append( dtfn2 )
|
549
|
+
if 'rsffn1' in csvrow.keys():
|
550
|
+
rsid=str(int(csvrow['rsfid1'].iloc[0]))
|
551
|
+
rsfn1=glob.glob(os.path.join( rootdir, pid, sid, dt, 'rsfMRI*', rsid, str(csvrow['rsffn1'].iloc[0]+iext) ))[0]
|
552
|
+
if exists( rsfn1 ):
|
553
|
+
rsfList.append( rsfn1 )
|
554
|
+
if 'rsffn2' in csvrow.keys():
|
555
|
+
rsid=str(int(csvrow['rsfid2'].iloc[0]))
|
556
|
+
rsfn2=glob.glob(os.path.join( rootdir, pid, sid, dt, 'rsfMRI*', rsid, str(csvrow['rsffn2'].iloc[0]+iext) ))[0]
|
557
|
+
if exists( rsfn2 ):
|
558
|
+
rsfList.append( rsfn2 )
|
559
|
+
for j in range(11):
|
560
|
+
keyname="nmfn"+str(j)
|
561
|
+
keynameid="nmid"+str(j)
|
562
|
+
if keyname in csvrow.keys() and keynameid in csvrow.keys():
|
563
|
+
nmid=str(int(csvrow[keynameid].iloc[0]))
|
564
|
+
nmsearchpath=os.path.join( rootdir, pid, sid, dt, 'NM2DMT', nmid, "*"+nmid+iext)
|
565
|
+
nmfn=glob.glob( nmsearchpath )
|
566
|
+
nmfn=nmfn[0]
|
567
|
+
if exists( nmfn ):
|
568
|
+
nmList.append( nmfn )
|
569
|
+
if verbose:
|
570
|
+
print("assembled the image lists mapping to ....")
|
571
|
+
print(nrgt1fn)
|
572
|
+
print("NM")
|
573
|
+
print(nmList)
|
574
|
+
print("FLAIR")
|
575
|
+
print(flList)
|
576
|
+
print("DTI")
|
577
|
+
print(dtList)
|
578
|
+
print("rsfMRI")
|
579
|
+
print(rsfList)
|
580
|
+
studycsv = generate_mm_dataframe(
|
581
|
+
pid,
|
582
|
+
sid,
|
583
|
+
dt,
|
584
|
+
iid, # the T1 id
|
585
|
+
'T1w',
|
586
|
+
rootdir,
|
587
|
+
outputdir,
|
588
|
+
t1_filename=nrgt1fn,
|
589
|
+
flair_filename=flList,
|
590
|
+
dti_filenames=dtList,
|
591
|
+
rsf_filenames=rsfList,
|
592
|
+
nm_filenames=nmList)
|
593
|
+
return studycsv.dropna(axis=1)
|
594
|
+
|
497
595
|
def highest_quality_repeat(mxdfin, idvar, visitvar, qualityvar):
|
498
596
|
"""
|
499
597
|
This function returns a subset of the input dataframe that retains only the rows
|
@@ -652,6 +750,16 @@ def match_modalities( qc_dataframe, unique_identifier='fn', outlier_column='ol_l
|
|
652
750
|
mmdf.iloc[k, mmdf.columns.get_loc("flairfn")] = fldf['fn'][locsel].values[0]
|
653
751
|
mmdf.iloc[k, mmdf.columns.get_loc("flairloop")] = fldf[outlier_column][locsel].values[0]
|
654
752
|
mmdf.iloc[k, mmdf.columns.get_loc("flairlof")] = fldf['ol_lof_decision'][locsel].values[0]
|
753
|
+
elif sum(locsel) > 1:
|
754
|
+
locdf = fldf[locsel]
|
755
|
+
dedupe = locdf[["snr","cnr"]].duplicated()
|
756
|
+
locdf = locdf[~dedupe]
|
757
|
+
if locdf.shape[0] > 1:
|
758
|
+
locdf = locdf.sort_values(outlier_column).iloc[:2]
|
759
|
+
mmdf.iloc[k, mmdf.columns.get_loc("flairid")] = locdf["imageID"].values[0]
|
760
|
+
mmdf.iloc[k, mmdf.columns.get_loc("flairfn")] = locdf["fn"].values[0]
|
761
|
+
mmdf.iloc[k, mmdf.columns.get_loc("flairloop")] = locdf[outlier_column].values[0]
|
762
|
+
mmdf.iloc[k, mmdf.columns.get_loc("flairlof")] = locdf['ol_lof_decision'].values[0]
|
655
763
|
|
656
764
|
if nmdf is not None:
|
657
765
|
locsel = nmdf['subjectIDdate'] == mmdf['subjectIDdate'].iloc[k]
|
@@ -1088,7 +1196,7 @@ def merge_dwi_data( img_LRdwp, bval_LR, bvec_LR, img_RLdwp, bval_RL, bvec_RL ):
|
|
1088
1196
|
img_LRdwp = ants.list_to_ndimage( img_LRdwp, mimg )
|
1089
1197
|
return img_LRdwp, bval_LR, bvec_LR
|
1090
1198
|
|
1091
|
-
def bvec_reorientation( motion_parameters, bvecs ):
|
1199
|
+
def bvec_reorientation( motion_parameters, bvecs, rebase=None ):
|
1092
1200
|
if motion_parameters is None:
|
1093
1201
|
return bvecs
|
1094
1202
|
n = len(motion_parameters)
|
@@ -1129,8 +1237,207 @@ def bvec_reorientation( motion_parameters, bvecs ):
|
|
1129
1237
|
txparam = ants.get_ants_transform_parameters(txparam)[0:9].reshape( [3,3])
|
1130
1238
|
Rinv = inv( txparam )
|
1131
1239
|
bvecs[myidx,:] = np.dot( Rinv, bvecs[myidx,:] )
|
1240
|
+
if rebase is not None:
|
1241
|
+
# FIXME - should combine these operations
|
1242
|
+
bvecs[myidx,:] = np.dot( rebase, bvecs[myidx,:] )
|
1132
1243
|
return bvecs
|
1133
1244
|
|
1245
|
+
def get_dti( reference_image, tensormodel, upper_triangular=True, return_image=False ):
|
1246
|
+
"""
|
1247
|
+
extract DTI data from a dipy tensormodel
|
1248
|
+
|
1249
|
+
reference_image : antsImage defining physical space (3D)
|
1250
|
+
|
1251
|
+
tensormodel : from dipy e.g. the variable myoutx['dtrecon_LR_dewarp']['tensormodel'] if myoutx is produced my joint_dti_recon
|
1252
|
+
|
1253
|
+
upper_triangular: boolean otherwise use lower triangular coding
|
1254
|
+
|
1255
|
+
return_image : boolean return the ANTsImage form of DTI otherwise return an array
|
1256
|
+
|
1257
|
+
Returns
|
1258
|
+
-------
|
1259
|
+
either an ANTsImage (dim=X.Y.Z with 6 component voxels, upper triangular form)
|
1260
|
+
or a 5D NumPy array (dim=X.Y.Z.3.3)
|
1261
|
+
|
1262
|
+
Notes
|
1263
|
+
-----
|
1264
|
+
DiPy returns lower triangular form but ANTs expects upper triangular.
|
1265
|
+
Here, we default to the ANTs standard but could generalize in the future
|
1266
|
+
because not much here depends on ANTs standards of tensor data.
|
1267
|
+
ANTs xx,xy,xz,yy,yz,zz
|
1268
|
+
DiPy Dxx, Dxy, Dyy, Dxz, Dyz, Dzz
|
1269
|
+
|
1270
|
+
"""
|
1271
|
+
# make the DTI - see
|
1272
|
+
# https://dipy.org/documentation/1.7.0/examples_built/07_reconstruction/reconst_dti/#sphx-glr-examples-built-07-reconstruction-reconst-dti-py
|
1273
|
+
# By default, in DIPY, values are ordered as (Dxx, Dxy, Dyy, Dxz, Dyz, Dzz)
|
1274
|
+
# in ANTs - we have: [xx,xy,xz,yy,yz,zz]
|
1275
|
+
reoind = np.array([0,1,3,2,4,5]) # arrays are faster than lists
|
1276
|
+
import dipy.reconst.dti as dti
|
1277
|
+
dtiut = dti.lower_triangular(tensormodel.quadratic_form)
|
1278
|
+
it = np.ndindex( reference_image.shape )
|
1279
|
+
yyind=2
|
1280
|
+
xzind=3
|
1281
|
+
if upper_triangular:
|
1282
|
+
yyind=3
|
1283
|
+
xzind=2
|
1284
|
+
for i in it: # convert to upper triangular
|
1285
|
+
dtiut[i] = dtiut[i][ reoind ] # do we care if this is doing extra work?
|
1286
|
+
if return_image:
|
1287
|
+
dtiAnts = ants.from_numpy(dtiut,has_components=True)
|
1288
|
+
ants.copy_image_info( reference_image, dtiAnts )
|
1289
|
+
return dtiAnts
|
1290
|
+
# copy these data into a tensor
|
1291
|
+
dtinp = np.zeros(reference_image.shape + (3,3), dtype=float)
|
1292
|
+
dtix = np.zeros((3,3), dtype=float)
|
1293
|
+
it = np.ndindex( reference_image.shape )
|
1294
|
+
for i in it:
|
1295
|
+
dtivec = dtiut[i] # in ANTs - we have: [xx,xy,xz,yy,yz,zz]
|
1296
|
+
dtix[0,0]=dtivec[0]
|
1297
|
+
dtix[1,1]=dtivec[yyind] # 2 for LT
|
1298
|
+
dtix[2,2]=dtivec[5]
|
1299
|
+
dtix[0,1]=dtix[1,0]=dtivec[1]
|
1300
|
+
dtix[0,2]=dtix[2,0]=dtivec[xzind] # 3 for LT
|
1301
|
+
dtix[1,2]=dtix[2,1]=dtivec[4]
|
1302
|
+
dtinp[i]=dtix
|
1303
|
+
return dtinp
|
1304
|
+
|
1305
|
+
def triangular_to_tensor( image, upper_triangular=True ):
|
1306
|
+
"""
|
1307
|
+
convert triangular tensor image to a full tensor form (in numpy)
|
1308
|
+
|
1309
|
+
image : antsImage holding dti in either upper or lower triangular format
|
1310
|
+
|
1311
|
+
upper_triangular: boolean
|
1312
|
+
|
1313
|
+
Note
|
1314
|
+
--------
|
1315
|
+
see get_dti function for more details
|
1316
|
+
"""
|
1317
|
+
reoind = np.array([0,1,3,2,4,5]) # arrays are faster than lists
|
1318
|
+
it = np.ndindex( image.shape )
|
1319
|
+
yyind=2
|
1320
|
+
xzind=3
|
1321
|
+
if upper_triangular:
|
1322
|
+
yyind=3
|
1323
|
+
xzind=2
|
1324
|
+
# copy these data into a tensor
|
1325
|
+
dtinp = np.zeros(image.shape + (3,3), dtype=float)
|
1326
|
+
dtix = np.zeros((3,3), dtype=float)
|
1327
|
+
it = np.ndindex( image.shape )
|
1328
|
+
dtiut = image.numpy()
|
1329
|
+
for i in it:
|
1330
|
+
dtivec = dtiut[i] # in ANTs - we have: [xx,xy,xz,yy,yz,zz]
|
1331
|
+
dtix[0,0]=dtivec[0]
|
1332
|
+
dtix[1,1]=dtivec[yyind] # 2 for LT
|
1333
|
+
dtix[2,2]=dtivec[5]
|
1334
|
+
dtix[0,1]=dtix[1,0]=dtivec[1]
|
1335
|
+
dtix[0,2]=dtix[2,0]=dtivec[xzind] # 3 for LT
|
1336
|
+
dtix[1,2]=dtix[2,1]=dtivec[4]
|
1337
|
+
dtinp[i]=dtix
|
1338
|
+
return dtinp
|
1339
|
+
|
1340
|
+
|
1341
|
+
def dti_numpy_to_image( reference_image, tensorarray, upper_triangular=True):
|
1342
|
+
"""
|
1343
|
+
convert numpy DTI data to antsImage
|
1344
|
+
|
1345
|
+
reference_image : antsImage defining physical space (3D)
|
1346
|
+
|
1347
|
+
tensorarray : numpy array X,Y,Z,3,3 shape
|
1348
|
+
|
1349
|
+
upper_triangular: boolean otherwise use lower triangular coding
|
1350
|
+
|
1351
|
+
Returns
|
1352
|
+
-------
|
1353
|
+
ANTsImage
|
1354
|
+
|
1355
|
+
Notes
|
1356
|
+
-----
|
1357
|
+
DiPy returns lower triangular form but ANTs expects upper triangular.
|
1358
|
+
Here, we default to the ANTs standard but could generalize in the future
|
1359
|
+
because not much here depends on ANTs standards of tensor data.
|
1360
|
+
ANTs xx,xy,xz,yy,yz,zz
|
1361
|
+
DiPy Dxx, Dxy, Dyy, Dxz, Dyz, Dzz
|
1362
|
+
|
1363
|
+
"""
|
1364
|
+
dtiut = np.zeros(reference_image.shape + (6,), dtype=float)
|
1365
|
+
dtivec = np.zeros(6, dtype=float)
|
1366
|
+
it = np.ndindex( reference_image.shape )
|
1367
|
+
yyind=2
|
1368
|
+
xzind=3
|
1369
|
+
if upper_triangular:
|
1370
|
+
yyind=3
|
1371
|
+
xzind=2
|
1372
|
+
for i in it:
|
1373
|
+
dtix = tensorarray[i] # in ANTs - we have: [xx,xy,xz,yy,yz,zz]
|
1374
|
+
dtivec[0]=dtix[0,0]
|
1375
|
+
dtivec[yyind]=dtix[1,1] # 2 for LT
|
1376
|
+
dtivec[5]=dtix[2,2]
|
1377
|
+
dtivec[1]=dtix[0,1]
|
1378
|
+
dtivec[xzind]=dtix[2,0] # 3 for LT
|
1379
|
+
dtivec[4]=dtix[1,2]
|
1380
|
+
dtiut[i]=dtivec
|
1381
|
+
dtiAnts = ants.from_numpy( dtiut, has_components=True )
|
1382
|
+
ants.copy_image_info( reference_image, dtiAnts )
|
1383
|
+
return dtiAnts
|
1384
|
+
|
1385
|
+
def transform_and_reorient_dti( fixed, moving_dti, composite_transform, py_based=True, verbose=False, **kwargs):
|
1386
|
+
"""
|
1387
|
+
apply a transform to DTI in the style of ants.apply_transforms. this function
|
1388
|
+
expects a pre-computed composite transform which it will use to reorient
|
1389
|
+
the DTI using preservation of principle directions.
|
1390
|
+
|
1391
|
+
fixed : antsImage reference space
|
1392
|
+
|
1393
|
+
moving_dti : antsImage DTI in upper triangular format
|
1394
|
+
|
1395
|
+
composite_transform : should be a composition of all transforms to be applied stored on disk ( a filename ) ... might change this in the future.
|
1396
|
+
|
1397
|
+
py_based : boolean
|
1398
|
+
|
1399
|
+
verbose : boolean
|
1400
|
+
|
1401
|
+
**kwargs : passed to ants.apply_transforms
|
1402
|
+
|
1403
|
+
"""
|
1404
|
+
if moving_dti.dimension != 3:
|
1405
|
+
raise ValueError('moving image should have 3 dimensions')
|
1406
|
+
if moving_dti.components != 6:
|
1407
|
+
raise ValueError('moving image should have 6 components')
|
1408
|
+
# now apply the transform to the template
|
1409
|
+
# 1. transform the tensor components
|
1410
|
+
dtsplit = moving_dti.split_channels()
|
1411
|
+
dtiw = []
|
1412
|
+
for k in range(len(dtsplit)):
|
1413
|
+
dtiw.append( ants.apply_transforms( fixed, dtsplit[k], composite_transform ) )
|
1414
|
+
dtiw=ants.merge_channels(dtiw)
|
1415
|
+
if verbose:
|
1416
|
+
print("reorient tensors locally: compose and get reo image")
|
1417
|
+
locrot = ants.deformation_gradient( ants.image_read(composite_transform),
|
1418
|
+
to_rotation = True, py_based=py_based )
|
1419
|
+
rebaser = np.dot( np.transpose( fixed.direction ), moving_dti.direction )
|
1420
|
+
if verbose:
|
1421
|
+
print("convert UT to full tensor")
|
1422
|
+
dtiw2tensor = triangular_to_tensor( dtiw )
|
1423
|
+
if verbose:
|
1424
|
+
print("rebase them to new space via iterator")
|
1425
|
+
it = np.ndindex( fixed.shape )
|
1426
|
+
for i in it:
|
1427
|
+
# direction * dt * direction.transpose();
|
1428
|
+
mmm = dtiw2tensor[i]
|
1429
|
+
# transform rebase
|
1430
|
+
locrotx = np.reshape( locrot[i], [3,3] )
|
1431
|
+
mmm = np.dot( mmm, np.transpose( locrotx ) )
|
1432
|
+
mmm = np.dot( locrotx, mmm )
|
1433
|
+
# physical space rebase
|
1434
|
+
mmm = np.dot( mmm, np.transpose( rebaser ) )
|
1435
|
+
mmm = np.dot( rebaser, mmm )
|
1436
|
+
dtiw2tensor[i] = mmm
|
1437
|
+
if verbose:
|
1438
|
+
print("done with rebasing")
|
1439
|
+
return dti_numpy_to_image( fixed, dtiw2tensor )
|
1440
|
+
|
1134
1441
|
|
1135
1442
|
def dti_reg(
|
1136
1443
|
image,
|
@@ -1344,7 +1651,9 @@ def dti_reg(
|
|
1344
1651
|
if verbose:
|
1345
1652
|
print("Reorient bvecs")
|
1346
1653
|
if bvecs is not None:
|
1347
|
-
|
1654
|
+
# direction = target->GetDirection().GetTranspose() * img_mov->GetDirection().GetVnlMatrix();
|
1655
|
+
rebase = np.dot( np.transpose( avg_b0.direction ), ab0.direction )
|
1656
|
+
bvecs = bvec_reorientation( motion_parameters, bvecs, rebase )
|
1348
1657
|
|
1349
1658
|
if remove_it:
|
1350
1659
|
import shutil
|
@@ -1525,7 +1834,7 @@ def mc_reg(
|
|
1525
1834
|
}
|
1526
1835
|
|
1527
1836
|
|
1528
|
-
def get_data( name=None, force_download=False, version=
|
1837
|
+
def get_data( name=None, force_download=False, version=13, target_extension='.csv' ):
|
1529
1838
|
"""
|
1530
1839
|
Get ANTsPyMM data filename
|
1531
1840
|
|
@@ -2316,7 +2625,10 @@ def dipy_dti_recon(
|
|
2316
2625
|
RGB = ants.merge_channels( [RGB0,RGB1,RGB2] )
|
2317
2626
|
return tenfit, FA, MD1, RGB
|
2318
2627
|
|
2319
|
-
|
2628
|
+
import numpy as np
|
2629
|
+
if abs(np.linalg.norm(bvecs)-1) > 0.009 and False:
|
2630
|
+
bvecs=bvecs/np.linalg.norm(bvecs, axis=1)
|
2631
|
+
gtab = gradient_table(bvals, bvecs, atol=0.1 )
|
2320
2632
|
tenfit, FA, MD1, RGB = justthefit( gtab, fit_method, image, maskdil )
|
2321
2633
|
if verbose:
|
2322
2634
|
print("recon dti.TensorModel done",flush=True)
|
@@ -2446,7 +2758,7 @@ def joint_dti_recon(
|
|
2446
2758
|
|
2447
2759
|
t1w : antsimage t1w neuroimage (brain-extracted)
|
2448
2760
|
|
2449
|
-
brain_mask : mask for the DWI - just 3D
|
2761
|
+
brain_mask : mask for the DWI - just 3D - provided brain mask should be in reference_B0 space
|
2450
2762
|
|
2451
2763
|
motion_correct : None Rigid or SyN
|
2452
2764
|
|
@@ -2483,11 +2795,11 @@ def joint_dti_recon(
|
|
2483
2795
|
return( img )
|
2484
2796
|
|
2485
2797
|
img_LR = fix_dwi_shape( img_LR, bval_LR, bvec_LR )
|
2486
|
-
if denoise
|
2798
|
+
if denoise :
|
2487
2799
|
img_LR = mc_denoise( img_LR )
|
2488
2800
|
if img_RL is not None:
|
2489
2801
|
img_RL = fix_dwi_shape( img_RL, bval_RL, bvec_RL )
|
2490
|
-
if denoise
|
2802
|
+
if denoise :
|
2491
2803
|
img_RL = mc_denoise( img_RL )
|
2492
2804
|
|
2493
2805
|
if brain_mask is not None:
|
@@ -2608,7 +2920,9 @@ def joint_dti_recon(
|
|
2608
2920
|
fa_SNR = mask_snr( reconFA, bgmask, fgmask, bias_correct=False )
|
2609
2921
|
fa_evr = antspyt1w.patch_eigenvalue_ratio( reconFA, 512, [16,16,16], evdepth = 0.9, mask=recon_LR_dewarp['dwi_mask'] )
|
2610
2922
|
|
2923
|
+
dti_itself = get_dti( reconFA, recon_LR_dewarp['tensormodel'], return_image=True )
|
2611
2924
|
return {
|
2925
|
+
'dti': dti_itself,
|
2612
2926
|
'recon_fa':reconFA,
|
2613
2927
|
'recon_fa_summary':df_FA_JHU_ORRL_bfwide,
|
2614
2928
|
'recon_md':reconMD,
|
@@ -2850,7 +3164,10 @@ def dwi_deterministic_tracking(
|
|
2850
3164
|
affine = dwi_img.affine
|
2851
3165
|
if isinstance( bvals, str ) or isinstance( bvecs, str ):
|
2852
3166
|
bvals, bvecs = read_bvals_bvecs(bvals, bvecs)
|
2853
|
-
|
3167
|
+
import numpy as np
|
3168
|
+
if abs(np.linalg.norm(bvecs)-1) > 0.009 and False:
|
3169
|
+
bvecs=bvecs/np.linalg.norm(bvecs, axis=1 )
|
3170
|
+
gtab = gradient_table(bvals, bvecs, atol=0.1 )
|
2854
3171
|
if mask is None:
|
2855
3172
|
mask = ants.threshold_image( fa, fa_thresh, 2.0 ).iMath("GetLargestComponent")
|
2856
3173
|
dwi_data = dwi_img.get_fdata()
|
@@ -3018,7 +3335,10 @@ def dwi_closest_peak_tracking(
|
|
3018
3335
|
affine = dwi_img.affine
|
3019
3336
|
if isinstance( bvals, str ) or isinstance( bvecs, str ):
|
3020
3337
|
bvals, bvecs = read_bvals_bvecs(bvals, bvecs)
|
3021
|
-
|
3338
|
+
import numpy as np
|
3339
|
+
if abs(np.linalg.norm(bvecs)-1) > 0.009 and False:
|
3340
|
+
bvecs=bvecs/np.linalg.norm(bvecs, axis=1)
|
3341
|
+
gtab = gradient_table(bvals, bvecs, atol=0.1 )
|
3022
3342
|
if mask is None:
|
3023
3343
|
mask = ants.threshold_image( fa, fa_thresh, 2.0 ).iMath("GetLargestComponent")
|
3024
3344
|
dwi_data = dwi_img.get_fdata()
|
@@ -4003,15 +4323,18 @@ def resting_state_fmri_networks( fmri, fmri_template, t1, t1segmentation,
|
|
4003
4323
|
netname = re.sub( "-", "", netname )
|
4004
4324
|
ww = np.where( powers_areal_mni_itk['SystemName'] == networks[mynet] )[0]
|
4005
4325
|
dfnImg = ants.make_points_image(pts2bold.iloc[ww,:3].values, bmask, radius=1).threshold_image( 1, 1e9 )
|
4006
|
-
|
4007
|
-
|
4008
|
-
|
4009
|
-
|
4010
|
-
|
4011
|
-
|
4012
|
-
|
4013
|
-
|
4014
|
-
|
4326
|
+
if dfnImg.max() >= 1:
|
4327
|
+
dfnmat = ants.timeseries_to_matrix( simg, ants.threshold_image( dfnImg, 1, dfnImg.max() ) )
|
4328
|
+
dfnmat = ants.bandpass_filter_matrix( dfnmat, tr = tr, lowf=f[0], highf=f[1] )
|
4329
|
+
dfnmat = ants.regress_components( dfnmat, nuisance )
|
4330
|
+
dfnsignal = dfnmat.mean( axis = 1 )
|
4331
|
+
gmmatDFNCorr = np.zeros( gmmat.shape[1] )
|
4332
|
+
for k in range( gmmat.shape[1] ):
|
4333
|
+
gmmatDFNCorr[ k ] = pearsonr( dfnsignal, gmmat[:,k] )[0]
|
4334
|
+
corrImg = ants.make_image( gmseg, gmmatDFNCorr )
|
4335
|
+
outdict[ netname ] = corrImg
|
4336
|
+
else:
|
4337
|
+
outdict[ netname ] = None
|
4015
4338
|
ct = ct + 1
|
4016
4339
|
|
4017
4340
|
A = np.zeros( ( len( numofnets ) , len( numofnets ) ) )
|
@@ -4105,11 +4428,15 @@ def write_bvals_bvecs(bvals, bvecs, prefix ):
|
|
4105
4428
|
N = len(bvals)
|
4106
4429
|
fname = prefix + '.bval'
|
4107
4430
|
fmt = _VAL_FMT * N + '\n'
|
4108
|
-
open(fname, 'wt')
|
4431
|
+
myfile = open(fname, 'wt')
|
4432
|
+
myfile.write(fmt % bvals)
|
4433
|
+
myfile.close()
|
4109
4434
|
fname = prefix + '.bvec'
|
4110
4435
|
bvf = open(fname, 'wt')
|
4111
4436
|
for dim_vals in bvecs.T:
|
4112
4437
|
bvf.write(fmt % tuple(dim_vals))
|
4438
|
+
bvf.close()
|
4439
|
+
|
4113
4440
|
|
4114
4441
|
def crop_mcimage( x, mask, padder=None ):
|
4115
4442
|
"""
|
@@ -4152,6 +4479,8 @@ def mm(
|
|
4152
4479
|
do_tractography = False,
|
4153
4480
|
do_kk = False,
|
4154
4481
|
do_normalization = None,
|
4482
|
+
group_template = None,
|
4483
|
+
group_transform = None,
|
4155
4484
|
target_range = [0,1],
|
4156
4485
|
dti_motion_correct = 'Rigid',
|
4157
4486
|
dti_denoise = False,
|
@@ -4190,6 +4519,10 @@ def mm(
|
|
4190
4519
|
|
4191
4520
|
do_normalization : template transformation if available
|
4192
4521
|
|
4522
|
+
group_template : optional reference template corresponding to the group_transform
|
4523
|
+
|
4524
|
+
group_transform : optional transforms corresponding to the group_template
|
4525
|
+
|
4193
4526
|
target_range : 2-element tuple
|
4194
4527
|
a tuple or array defining the (min, max) of the input image
|
4195
4528
|
(e.g., [-127.5, 127.5] or [0,1]). Output images will be scaled back to original
|
@@ -4225,6 +4558,9 @@ def mm(
|
|
4225
4558
|
JHU_atlas = mm_read( JHU_atlasfn ) # Read in JHU atlas
|
4226
4559
|
JHU_labels = mm_read( JHU_labelsfn ) # Read in JHU labels
|
4227
4560
|
template = mm_read( templatefn ) # Read in template
|
4561
|
+
if group_template is None:
|
4562
|
+
group_template = template
|
4563
|
+
group_transform = do_normalization['fwdtransforms']
|
4228
4564
|
#####################
|
4229
4565
|
# T1 hierarchical #
|
4230
4566
|
#####################
|
@@ -4248,6 +4584,7 @@ def mm(
|
|
4248
4584
|
normalization_dict = {
|
4249
4585
|
'kk_norm': None,
|
4250
4586
|
'NM_norm' : None,
|
4587
|
+
'DTI_norm': None,
|
4251
4588
|
'FA_norm' : None,
|
4252
4589
|
'MD_norm' : None,
|
4253
4590
|
'alff_norm' : None,
|
@@ -4454,24 +4791,32 @@ def mm(
|
|
4454
4791
|
# t1reg = ants.registration( template, hier['brain_n4_dnz'], "antsRegistrationSyNQuickRepro[s]")
|
4455
4792
|
t1reg = do_normalization
|
4456
4793
|
if do_kk:
|
4457
|
-
normalization_dict['kk_norm'] = ants.apply_transforms(
|
4794
|
+
normalization_dict['kk_norm'] = ants.apply_transforms( group_template, output_dict['kk']['thickness_image'], group_transform )
|
4458
4795
|
if output_dict['DTI'] is not None:
|
4459
4796
|
mydti = output_dict['DTI']
|
4460
4797
|
dtirig = ants.registration( hier['brain_n4_dnz'], mydti['recon_fa'], 'Rigid' )
|
4461
|
-
normalization_dict['MD_norm'] = ants.apply_transforms(
|
4462
|
-
normalization_dict['FA_norm'] = ants.apply_transforms(
|
4798
|
+
normalization_dict['MD_norm'] = ants.apply_transforms( group_template, mydti['recon_md'],group_transform+dtirig['fwdtransforms'] )
|
4799
|
+
normalization_dict['FA_norm'] = ants.apply_transforms( group_template, mydti['recon_fa'],group_transform+dtirig['fwdtransforms'] )
|
4800
|
+
output_directory = tempfile.mkdtemp()
|
4801
|
+
comptx = ants.apply_transforms( group_template, group_template,
|
4802
|
+
group_transform+dtirig['fwdtransforms'],
|
4803
|
+
compose = output_directory + '/xxx' )
|
4804
|
+
normalization_dict['DTI_norm'] = transform_and_reorient_dti(
|
4805
|
+
group_template, mydti['dti'], comptx, py_based=True, verbose=True )
|
4806
|
+
import shutil
|
4807
|
+
shutil.rmtree(output_directory, ignore_errors=True )
|
4463
4808
|
if output_dict['rsf'] is not None:
|
4464
4809
|
rsfpro = output_dict['rsf']
|
4465
4810
|
rsfrig = ants.registration( hier['brain_n4_dnz'], rsfpro['meanBold'], 'Rigid' )
|
4466
4811
|
for netid in mynets:
|
4467
4812
|
rsfkey = netid + "_norm"
|
4468
4813
|
normalization_dict[rsfkey] = ants.apply_transforms(
|
4469
|
-
|
4470
|
-
|
4814
|
+
group_template, rsfpro[netid],
|
4815
|
+
group_transform+rsfrig['fwdtransforms'] )
|
4471
4816
|
if nm_image_list is not None:
|
4472
4817
|
nmpro = output_dict['NM']
|
4473
4818
|
nmrig = nmpro['t1_to_NM_transform'] # this is an inverse tx
|
4474
|
-
normalization_dict['NM_norm'] = ants.apply_transforms(
|
4819
|
+
normalization_dict['NM_norm'] = ants.apply_transforms( group_template, nmpro['NM_avg'], group_transform+nmrig,
|
4475
4820
|
whichtoinvert=[False,False,True])
|
4476
4821
|
|
4477
4822
|
if verbose:
|
@@ -4479,7 +4824,7 @@ def mm(
|
|
4479
4824
|
return output_dict, normalization_dict
|
4480
4825
|
|
4481
4826
|
|
4482
|
-
def write_mm( output_prefix, mm, mm_norm=None, t1wide=None, separator='_' ):
|
4827
|
+
def write_mm( output_prefix, mm, mm_norm=None, t1wide=None, separator='_', verbose=False ):
|
4483
4828
|
"""
|
4484
4829
|
write the tabular and normalization output of the mm function
|
4485
4830
|
|
@@ -4496,6 +4841,8 @@ def write_mm( output_prefix, mm, mm_norm=None, t1wide=None, separator='_' ):
|
|
4496
4841
|
|
4497
4842
|
separator : string or character separator for filenames
|
4498
4843
|
|
4844
|
+
verbose : boolean
|
4845
|
+
|
4499
4846
|
Returns
|
4500
4847
|
---------
|
4501
4848
|
|
@@ -4529,6 +4876,7 @@ def write_mm( output_prefix, mm, mm_norm=None, t1wide=None, separator='_' ):
|
|
4529
4876
|
if mm['DTI'] is not None:
|
4530
4877
|
mydti = mm['DTI']
|
4531
4878
|
myop = output_prefix + separator
|
4879
|
+
ants.image_write( mydti['dti'], myop + 'dti.nii.gz' )
|
4532
4880
|
write_bvals_bvecs( mydti['bval_LR'], mydti['bvec_LR'], myop + 'reoriented' )
|
4533
4881
|
image_write_with_thumbnail( mydti['dwi_LR_dewarped'], myop + 'dwi.nii.gz' )
|
4534
4882
|
image_write_with_thumbnail( mydti['dtrecon_LR_dewarp']['RGB'] , myop + 'DTIRGB.nii.gz' )
|
@@ -4639,6 +4987,8 @@ def write_mm( output_prefix, mm, mm_norm=None, t1wide=None, separator='_' ):
|
|
4639
4987
|
mm_wide['dti_FD_mean'] = mm_wide['dti_FD_max'] = 'NA'
|
4640
4988
|
mmwidefn = output_prefix + separator + 'mmwide.csv'
|
4641
4989
|
mm_wide.to_csv( mmwidefn )
|
4990
|
+
if verbose:
|
4991
|
+
print( output_prefix + " write_mm done." )
|
4642
4992
|
return
|
4643
4993
|
|
4644
4994
|
|
@@ -4781,7 +5131,8 @@ def mm_nrg(
|
|
4781
5131
|
'fwdtransforms': [ regout+'1Warp.nii.gz', regout+'0GenericAffine.mat'],
|
4782
5132
|
'invtransforms': [ regout+'0GenericAffine.mat', regout+'1InverseWarp.nii.gz'] }
|
4783
5133
|
if verbose:
|
4784
|
-
print( "REGISTRATION EXISTENCE
|
5134
|
+
print( "-<REGISTRATION EXISTENCE>-: \n" +
|
5135
|
+
"NAMING: " + regout+'0GenericAffine.mat' + " \n " +
|
4785
5136
|
str(exists( templateTx['fwdtransforms'][0])) + " " +
|
4786
5137
|
str(exists( templateTx['fwdtransforms'][1])) + " " +
|
4787
5138
|
str(exists( templateTx['invtransforms'][0])) + " " +
|
@@ -5133,14 +5484,14 @@ def mm_nrg(
|
|
5133
5484
|
mydti = tabPro['DTI']
|
5134
5485
|
if visualize:
|
5135
5486
|
maxslice = np.min( [21, mydti['recon_fa'] ] )
|
5136
|
-
ants.plot( mydti['recon_fa'], axis=2, nslices=maxslice, ncol=7, crop=True, title='FA
|
5487
|
+
ants.plot( mydti['recon_fa'], axis=2, nslices=maxslice, ncol=7, crop=True, title='FA', filename=mymm+mysep+"FAbetter.png" )
|
5137
5488
|
ants.plot( mydti['recon_fa'], mydti['jhu_labels'], axis=2, nslices=maxslice, ncol=7, crop=True, title='FA + JHU', filename=mymm+mysep+"FAJHU.png" )
|
5138
5489
|
ants.plot( mydti['recon_md'], axis=2, nslices=maxslice, ncol=7, crop=True, title='MD', filename=mymm+mysep+"MD.png" )
|
5139
5490
|
if dowrite:
|
5140
|
-
write_mm( output_prefix=mymm, mm=tabPro, mm_norm=normPro, t1wide=t1wide, separator=mysep )
|
5491
|
+
write_mm( output_prefix=mymm, mm=tabPro, mm_norm=normPro, t1wide=t1wide, separator=mysep, verbose=True )
|
5141
5492
|
for mykey in normPro.keys():
|
5142
5493
|
if normPro[mykey] is not None:
|
5143
|
-
if visualize:
|
5494
|
+
if visualize and normPro[mykey].components == 1:
|
5144
5495
|
ants.plot( template, normPro[mykey], axis=2, nslices=21, ncol=7, crop=True, title=mykey, filename=mymm+mysep+mykey+".png" )
|
5145
5496
|
if overmodX == nrg_modality_list[ len( nrg_modality_list ) - 1 ]:
|
5146
5497
|
return
|
@@ -5158,9 +5509,13 @@ def mm_csv(
|
|
5158
5509
|
srmodel_T1 = False, # optional - will add a great deal of time
|
5159
5510
|
srmodel_NM = False, # optional - will add a great deal of time
|
5160
5511
|
srmodel_DTI = False, # optional - will add a great deal of time
|
5161
|
-
dti_motion_correct = '
|
5162
|
-
dti_denoise =
|
5163
|
-
nrg_modality_list = None
|
5512
|
+
dti_motion_correct = 'SyN',
|
5513
|
+
dti_denoise = True,
|
5514
|
+
nrg_modality_list = None,
|
5515
|
+
normalization_template = None,
|
5516
|
+
normalization_template_output = None,
|
5517
|
+
normalization_template_transform_type = "antsRegistrationSyNRepro[s]",
|
5518
|
+
normalization_template_spacing=None
|
5164
5519
|
):
|
5165
5520
|
"""
|
5166
5521
|
too dangerous to document ... use with care.
|
@@ -5220,6 +5575,17 @@ def mm_csv(
|
|
5220
5575
|
|
5221
5576
|
nrg_modality_list : optional; defaults to None; use to focus on a given modality
|
5222
5577
|
|
5578
|
+
normalization_template : optional; defaults to None; if present, all images will
|
5579
|
+
be deformed into this space and the deformation will be stored with an extension
|
5580
|
+
related to this variable. this should be a brain extracted T1w image.
|
5581
|
+
|
5582
|
+
normalization_template_output : optional string; defaults to None; naming for the
|
5583
|
+
normalization_template outputs which will be in the T1w directory.
|
5584
|
+
|
5585
|
+
normalization_template_transform_type : optional string transform type passed to ants.registration
|
5586
|
+
|
5587
|
+
normalization_template_spacing : 3-tuple controlling the resolution at which registration is computed
|
5588
|
+
|
5223
5589
|
Returns
|
5224
5590
|
---------
|
5225
5591
|
|
@@ -5305,7 +5671,6 @@ def mm_csv(
|
|
5305
5671
|
iid2=iid+"_"+t1iid
|
5306
5672
|
myoutputPrefix = outputdir + "/" + projid + "/" + sid + "/" + dtid + "/" + locmod + '/' + iid + "/" + projid + mysep + sid + mysep + dtid + mysep + locmod + mysep + iid2
|
5307
5673
|
if verbose:
|
5308
|
-
print("VERBOSE in docsamson")
|
5309
5674
|
print( locmod )
|
5310
5675
|
print( myimgsInput )
|
5311
5676
|
print( myoutputPrefix )
|
@@ -5323,22 +5688,30 @@ def mm_csv(
|
|
5323
5688
|
t1 = mm_read( t1fn, modality='T1w' )
|
5324
5689
|
hierfn = outputdir + "/" + projid + "/" + sid + "/" + dtid + "/" + "T1wHierarchical" + '/' + iid + "/" + projid + mysep + sid + mysep + dtid + mysep + "T1wHierarchical" + mysep + iid + mysep
|
5325
5690
|
hierfnSR = outputdir + "/" + projid + "/" + sid + "/" + dtid + "/" + "T1wHierarchicalSR" + '/' + iid + "/" + projid + mysep + sid + mysep + dtid + mysep + "T1wHierarchicalSR" + mysep + iid + mysep
|
5326
|
-
hierfntest = hierfn + '
|
5691
|
+
hierfntest = hierfn + 'cerebellum.csv'
|
5327
5692
|
if verbose:
|
5328
5693
|
print( hierfntest )
|
5329
|
-
regout = hierfn + "syn"
|
5694
|
+
regout = re.sub("T1wHierarchical","T1w",hierfn) + "syn"
|
5330
5695
|
templateTx = {
|
5331
5696
|
'fwdtransforms': [ regout+'1Warp.nii.gz', regout+'0GenericAffine.mat'],
|
5332
5697
|
'invtransforms': [ regout+'0GenericAffine.mat', regout+'1InverseWarp.nii.gz'] }
|
5698
|
+
groupTx = None
|
5699
|
+
if normalization_template_output is not None:
|
5700
|
+
normout = re.sub("T1wHierarchical","T1w",hierfn) + normalization_template_output
|
5701
|
+
templateNormTx = {
|
5702
|
+
'fwdtransforms': [ normout+'1Warp.nii.gz', normout+'0GenericAffine.mat'],
|
5703
|
+
'invtransforms': [ normout+'0GenericAffine.mat', normout+'1InverseWarp.nii.gz'] }
|
5704
|
+
groupTx = templateNormTx['fwdtransforms']
|
5333
5705
|
if verbose:
|
5334
|
-
print( "REGISTRATION EXISTENCE
|
5706
|
+
print( "-<REGISTRATION EXISTENCE>-: \n" +
|
5707
|
+
"NAMING: " + regout+'0GenericAffine.mat' + " \n " +
|
5335
5708
|
str(exists( templateTx['fwdtransforms'][0])) + " " +
|
5336
5709
|
str(exists( templateTx['fwdtransforms'][1])) + " " +
|
5337
5710
|
str(exists( templateTx['invtransforms'][0])) + " " +
|
5338
5711
|
str(exists( templateTx['invtransforms'][1])) )
|
5339
5712
|
if verbose:
|
5340
5713
|
print( hierfntest )
|
5341
|
-
hierexists = exists( hierfntest )
|
5714
|
+
hierexists = exists( hierfntest ) and exists( templateTx['fwdtransforms'][0]) and exists( templateTx['fwdtransforms'][1]) and exists( templateTx['invtransforms'][0]) and exists( templateTx['invtransforms'][1])
|
5342
5715
|
hier = None
|
5343
5716
|
if not hierexists and not testloop:
|
5344
5717
|
subjectpropath = os.path.dirname( hierfn )
|
@@ -5392,6 +5765,43 @@ def mm_csv(
|
|
5392
5765
|
if not testloop:
|
5393
5766
|
t1imgbrn = hier['brain_n4_dnz']
|
5394
5767
|
t1atropos = hier['dkt_parc']['tissue_segmentation']
|
5768
|
+
|
5769
|
+
if not exists( regout + "logjacobian.nii.gz" ) or not exists( regout+'1Warp.nii.gz' ):
|
5770
|
+
if verbose:
|
5771
|
+
print('start t1 registration')
|
5772
|
+
ex_path = os.path.expanduser( "~/.antspyt1w/" )
|
5773
|
+
templatefn = ex_path + 'CIT168_T1w_700um_pad_adni.nii.gz'
|
5774
|
+
template = mm_read( templatefn )
|
5775
|
+
template = ants.resample_image( template, [1,1,1], use_voxels=False )
|
5776
|
+
t1reg = ants.registration( template,
|
5777
|
+
hier['brain_n4_dnz'],
|
5778
|
+
"antsRegistrationSyNQuickRepro[s]", outprefix = regout, verbose=False )
|
5779
|
+
myjac = ants.create_jacobian_determinant_image( template,
|
5780
|
+
t1reg['fwdtransforms'][0], do_log=True, geom=True )
|
5781
|
+
image_write_with_thumbnail( myjac, regout + "logjacobian.nii.gz", thumb=False )
|
5782
|
+
if visualize:
|
5783
|
+
ants.plot( ants.iMath(t1reg['warpedmovout'],"Normalize"), axis=2, nslices=21, ncol=7, crop=True, title='warped to template', filename=regout+"totemplate.png" )
|
5784
|
+
ants.plot( ants.iMath(myjac,"Normalize"), axis=2, nslices=21, ncol=7, crop=True, title='jacobian', filename=regout+"jacobian.png" )
|
5785
|
+
|
5786
|
+
if normalization_template_output is not None and normalization_template is not None:
|
5787
|
+
if verbose:
|
5788
|
+
print("begin group template registration")
|
5789
|
+
if not exists( normout+'0GenericAffine.mat' ):
|
5790
|
+
if normalization_template_spacing is not None:
|
5791
|
+
normalization_template_rr=ants.resample_image(normalization_template,normalization_template_spacing)
|
5792
|
+
else:
|
5793
|
+
normalization_template_rr=normalization_template
|
5794
|
+
greg = ants.registration(
|
5795
|
+
normalization_template_rr,
|
5796
|
+
hier['brain_n4_dnz'],
|
5797
|
+
normalization_template_transform_type,
|
5798
|
+
outprefix = normout, verbose=False )
|
5799
|
+
if verbose:
|
5800
|
+
print("end group template registration")
|
5801
|
+
else:
|
5802
|
+
if verbose:
|
5803
|
+
print("group template registration already done")
|
5804
|
+
|
5395
5805
|
# loop over modalities and then unique image IDs
|
5396
5806
|
# we treat NM in a "special" way -- aggregating repeats
|
5397
5807
|
# other modalities (beyond T1) are treated individually
|
@@ -5456,6 +5866,8 @@ def mm_csv(
|
|
5456
5866
|
do_tractography=False,
|
5457
5867
|
do_kk=False,
|
5458
5868
|
do_normalization=templateTx,
|
5869
|
+
group_template = normalization_template,
|
5870
|
+
group_transform = groupTx,
|
5459
5871
|
test_run=test_run,
|
5460
5872
|
verbose=True )
|
5461
5873
|
if not test_run:
|
@@ -5495,21 +5907,6 @@ def mm_csv(
|
|
5495
5907
|
img = mm_read( myimg )
|
5496
5908
|
ishapelen = len( img.shape )
|
5497
5909
|
if mymod == 'T1w' and ishapelen == 3: # for a real run, set to True
|
5498
|
-
if not exists( regout + "logjacobian.nii.gz" ) or not exists( regout+'1Warp.nii.gz' ):
|
5499
|
-
if verbose:
|
5500
|
-
print('start t1 registration')
|
5501
|
-
ex_path = os.path.expanduser( "~/.antspyt1w/" )
|
5502
|
-
templatefn = ex_path + 'CIT168_T1w_700um_pad_adni.nii.gz'
|
5503
|
-
template = mm_read( templatefn )
|
5504
|
-
template = ants.resample_image( template, [1,1,1], use_voxels=False )
|
5505
|
-
t1reg = ants.registration( template, hier['brain_n4_dnz'],
|
5506
|
-
"antsRegistrationSyNQuickRepro[s]", outprefix = regout, verbose=False )
|
5507
|
-
myjac = ants.create_jacobian_determinant_image( template,
|
5508
|
-
t1reg['fwdtransforms'][0], do_log=True, geom=True )
|
5509
|
-
image_write_with_thumbnail( myjac, regout + "logjacobian.nii.gz", thumb=False )
|
5510
|
-
if visualize:
|
5511
|
-
ants.plot( ants.iMath(t1reg['warpedmovout'],"Normalize"), axis=2, nslices=21, ncol=7, crop=True, title='warped to template', filename=regout+"totemplate.png" )
|
5512
|
-
ants.plot( ants.iMath(myjac,"Normalize"), axis=2, nslices=21, ncol=7, crop=True, title='jacobian', filename=regout+"jacobian.png" )
|
5513
5910
|
if not exists( mymm + mysep + "kk_norm.nii.gz" ):
|
5514
5911
|
dowrite=True
|
5515
5912
|
if verbose:
|
@@ -5519,6 +5916,8 @@ def mm_csv(
|
|
5519
5916
|
do_tractography=False,
|
5520
5917
|
do_kk=True,
|
5521
5918
|
do_normalization=templateTx,
|
5919
|
+
group_template = normalization_template,
|
5920
|
+
group_transform = groupTx,
|
5522
5921
|
test_run=test_run,
|
5523
5922
|
verbose=True )
|
5524
5923
|
if visualize:
|
@@ -5534,6 +5933,8 @@ def mm_csv(
|
|
5534
5933
|
do_tractography=False,
|
5535
5934
|
do_kk=False,
|
5536
5935
|
do_normalization=templateTx,
|
5936
|
+
group_template = normalization_template,
|
5937
|
+
group_transform = groupTx,
|
5537
5938
|
test_run=test_run,
|
5538
5939
|
verbose=True )
|
5539
5940
|
if visualize:
|
@@ -5556,6 +5957,8 @@ def mm_csv(
|
|
5556
5957
|
do_tractography=False,
|
5557
5958
|
do_kk=False,
|
5558
5959
|
do_normalization=templateTx,
|
5960
|
+
group_template = normalization_template,
|
5961
|
+
group_transform = groupTx,
|
5559
5962
|
test_run=test_run,
|
5560
5963
|
verbose=True )
|
5561
5964
|
if tabPro['rsf'] is not None and visualize:
|
@@ -5571,12 +5974,12 @@ def mm_csv(
|
|
5571
5974
|
ants.plot( tabPro['rsf']['meanBold'], tabPro['rsf']['FrontoparietalTaskControl'],
|
5572
5975
|
axis=2, nslices=maxslice, ncol=7, crop=True, title='FrontoparietalTaskControl', filename=mymm+mysep+"boldFrontoparietalTaskControl.png" )
|
5573
5976
|
if ( mymod == 'DTI_LR' or mymod == 'DTI_RL' or mymod == 'DTI' ) and ishapelen == 4:
|
5574
|
-
dowrite=True
|
5575
5977
|
bvalfn = re.sub( '.nii.gz', '.bval' , myimg )
|
5576
5978
|
bvecfn = re.sub( '.nii.gz', '.bvec' , myimg )
|
5577
5979
|
imgList = [ img ]
|
5578
5980
|
bvalfnList = [ bvalfn ]
|
5579
5981
|
bvecfnList = [ bvecfn ]
|
5982
|
+
missing_dti_data=False # bval, bvec or images
|
5580
5983
|
if len( myimgsr ) > 1: # find DTI_RL
|
5581
5984
|
dtilrfn = myimgsr[myimgcount+1]
|
5582
5985
|
if exists( dtilrfn ):
|
@@ -5589,44 +5992,50 @@ def mm_csv(
|
|
5589
5992
|
# check existence of all files expected ...
|
5590
5993
|
for dtiex in bvalfnList+bvecfnList+myimgsr:
|
5591
5994
|
if not exists(dtiex):
|
5592
|
-
|
5593
|
-
|
5594
|
-
|
5595
|
-
|
5596
|
-
|
5597
|
-
|
5598
|
-
|
5599
|
-
|
5600
|
-
|
5601
|
-
|
5602
|
-
|
5603
|
-
if
|
5604
|
-
|
5605
|
-
|
5606
|
-
|
5607
|
-
|
5608
|
-
|
5609
|
-
|
5610
|
-
|
5611
|
-
|
5612
|
-
|
5613
|
-
|
5614
|
-
|
5615
|
-
|
5616
|
-
|
5617
|
-
|
5618
|
-
|
5619
|
-
|
5620
|
-
|
5621
|
-
|
5622
|
-
|
5623
|
-
|
5624
|
-
|
5625
|
-
|
5995
|
+
print('mm_csv: missing dti data ' + dtiex )
|
5996
|
+
missing_dti_data=True
|
5997
|
+
dowrite=False
|
5998
|
+
if not missing_dti_data:
|
5999
|
+
dowrite=True
|
6000
|
+
srmodel_DTI_mdl=None
|
6001
|
+
if srmodel_DTI is not False:
|
6002
|
+
temp = ants.get_spacing(img)
|
6003
|
+
dtspc=[temp[0],temp[1],temp[2]]
|
6004
|
+
bestup = siq.optimize_upsampling_shape( dtspc, modality='DTI' )
|
6005
|
+
mdlfn = ex_pathmm + "siq_default_sisr_" + bestup + "_1chan_featvggL6_best_mdl.h5"
|
6006
|
+
if isinstance( srmodel_DTI, str ):
|
6007
|
+
srmodel_DTI = re.sub( "bestup", bestup, srmodel_DTI )
|
6008
|
+
mdlfn = os.path.join( ex_pathmm, srmodel_DTI )
|
6009
|
+
if exists( mdlfn ):
|
6010
|
+
if verbose:
|
6011
|
+
print(mdlfn)
|
6012
|
+
srmodel_DTI_mdl = tf.keras.models.load_model( mdlfn, compile=False )
|
6013
|
+
else:
|
6014
|
+
print(mdlfn + " does not exist - wont use SR")
|
6015
|
+
tabPro, normPro = mm( t1, hier,
|
6016
|
+
dw_image=imgList,
|
6017
|
+
bvals = bvalfnList,
|
6018
|
+
bvecs = bvecfnList,
|
6019
|
+
srmodel=srmodel_DTI_mdl,
|
6020
|
+
do_tractography=not test_run,
|
6021
|
+
do_kk=False,
|
6022
|
+
do_normalization=templateTx,
|
6023
|
+
group_template = normalization_template,
|
6024
|
+
group_transform = groupTx,
|
6025
|
+
dti_motion_correct = dti_motion_correct,
|
6026
|
+
dti_denoise = dti_denoise,
|
6027
|
+
test_run=test_run,
|
6028
|
+
verbose=True )
|
6029
|
+
mydti = tabPro['DTI']
|
6030
|
+
if visualize:
|
6031
|
+
maxslice = np.min( [21, mydti['recon_fa'] ] )
|
6032
|
+
ants.plot( mydti['recon_fa'], axis=2, nslices=maxslice, ncol=7, crop=True, title='FA (supposed to be better)', filename=mymm+mysep+"FAbetter.png" )
|
6033
|
+
ants.plot( mydti['recon_fa'], mydti['jhu_labels'], axis=2, nslices=maxslice, ncol=7, crop=True, title='FA + JHU', filename=mymm+mysep+"FAJHU.png" )
|
6034
|
+
ants.plot( mydti['recon_md'], axis=2, nslices=maxslice, ncol=7, crop=True, title='MD', filename=mymm+mysep+"MD.png" )
|
5626
6035
|
if dowrite:
|
5627
6036
|
write_mm( output_prefix=mymm, mm=tabPro, mm_norm=normPro, t1wide=t1wide, separator=mysep )
|
5628
6037
|
for mykey in normPro.keys():
|
5629
|
-
if normPro[mykey] is not None:
|
6038
|
+
if normPro[mykey] is not None and normPro[mykey].components == 1:
|
5630
6039
|
if visualize:
|
5631
6040
|
ants.plot( template, normPro[mykey], axis=2, nslices=21, ncol=7, crop=True, title=mykey, filename=mymm+mysep+mykey+".png" )
|
5632
6041
|
if overmodX == nrg_modality_list[ len( nrg_modality_list ) - 1 ]:
|
@@ -6030,6 +6439,110 @@ def read_mm_csv( x, is_t1=False, colprefix=None, separator='-', verbose=False ):
|
|
6030
6439
|
xdf.columns=colprefix + xdf.columns
|
6031
6440
|
return pd.concat( [df,xdf], axis=1 )
|
6032
6441
|
|
6442
|
+
def merge_wides_to_study_dataframe( sdf, processing_dir, separator='-', sid_is_int=True, id_is_int=True, date_is_int=True, report_missing=False,
|
6443
|
+
progress=False, verbose=False ):
|
6444
|
+
"""
|
6445
|
+
extend a study data frame with wide outputs
|
6446
|
+
|
6447
|
+
sdf : the input study dataframe
|
6448
|
+
|
6449
|
+
processing_dir: the directory location of the processed data
|
6450
|
+
|
6451
|
+
separator : string usually '-' or '_'
|
6452
|
+
|
6453
|
+
sid_is_int : boolean set to True to cast unique subject ids to int; can be useful if they are inadvertently stored as float by pandas
|
6454
|
+
|
6455
|
+
date_is_int : boolean set to True to cast date to int; can be useful if they are inadvertently stored as float by pandas
|
6456
|
+
|
6457
|
+
id_is_int : boolean set to True to cast unique image ids to int; can be useful if they are inadvertently stored as float by pandas
|
6458
|
+
|
6459
|
+
report_missing : boolean combined with verbose will report missing modalities
|
6460
|
+
|
6461
|
+
progress : integer reports percent progress modulo progress value
|
6462
|
+
|
6463
|
+
verbose : boolean
|
6464
|
+
"""
|
6465
|
+
from os.path import exists
|
6466
|
+
musthavecols = ['projectID', 'subjectID','date','imageID','fn']
|
6467
|
+
for k in range(len(musthavecols)):
|
6468
|
+
if not musthavecols[k] in sdf.keys():
|
6469
|
+
raise ValueError('sdf is missing column ' +musthavecols[k] + ' in merge_wides_to_study_dataframe' )
|
6470
|
+
possible_iids = [ 'imageID', 'imageID', 'imageID', 'flairid', 'dtid1', 'dtid2', 'rsfid1', 'rsfid2', 'nmid1', 'nmid2', 'nmid3', 'nmid4', 'nmid5', 'nmid6', 'nmid7', 'nmid8', 'nmid9', 'nmid10' ]
|
6471
|
+
modality_ids = [ 'T1wHierarchical', 'T1wHierarchicalSR', 'T1w', 'T2Flair', 'DTI', 'DTI', 'rsfMRI', 'rsfMRI', 'NM2DMT', 'NM2DMT', 'NM2DMT', 'NM2DMT', 'NM2DMT', 'NM2DMT', 'NM2DMT', 'NM2DMT', 'NM2DMT', 'NM2DMT']
|
6472
|
+
alldf=pd.DataFrame()
|
6473
|
+
for myk in sdf.index:
|
6474
|
+
if progress > 0 and int(myk) % int(progress) == 0:
|
6475
|
+
print( str( round( myk/sdf.shape[0]*100.0)) + "%...", end='', flush=True)
|
6476
|
+
if verbose:
|
6477
|
+
print( "DOROW " + str(myk) + ' of ' + str( sdf.shape[0] ) )
|
6478
|
+
csvrow = sdf.loc[sdf.index == myk].dropna(axis=1)
|
6479
|
+
ct=-1
|
6480
|
+
for iidkey in possible_iids:
|
6481
|
+
ct=ct+1
|
6482
|
+
mod_name = modality_ids[ct]
|
6483
|
+
if iidkey in csvrow.keys():
|
6484
|
+
if id_is_int:
|
6485
|
+
iid = str( int( csvrow[iidkey].iloc[0] ) )
|
6486
|
+
else:
|
6487
|
+
iid = str( csvrow[iidkey].iloc[0] )
|
6488
|
+
if verbose:
|
6489
|
+
print( "iidkey " + iidkey + " modality " + mod_name + ' iid '+ iid )
|
6490
|
+
pid=str(csvrow['projectID'].iloc[0] )
|
6491
|
+
if sid_is_int:
|
6492
|
+
sid=str(int(csvrow['subjectID'].iloc[0] ))
|
6493
|
+
else:
|
6494
|
+
sid=str(csvrow['subjectID'].iloc[0] )
|
6495
|
+
if date_is_int:
|
6496
|
+
dt=str(int(csvrow['date'].iloc[0]))
|
6497
|
+
else:
|
6498
|
+
dt=str(csvrow['date'].iloc[0])
|
6499
|
+
if id_is_int:
|
6500
|
+
t1iid=str(int(csvrow['imageID'].iloc[0]))
|
6501
|
+
else:
|
6502
|
+
t1iid=str(csvrow['imageID'].iloc[0])
|
6503
|
+
if t1iid != iid:
|
6504
|
+
iidj=iid+"_"+t1iid
|
6505
|
+
else:
|
6506
|
+
iidj=iid
|
6507
|
+
rootid = pid +separator+ sid +separator+dt+separator+mod_name+separator+iidj
|
6508
|
+
myext = rootid +separator+'mmwide.csv'
|
6509
|
+
nrgwidefn=os.path.join( processing_dir, pid, sid, dt, mod_name, iid, myext )
|
6510
|
+
moddersub = mod_name
|
6511
|
+
is_t1=False
|
6512
|
+
if mod_name == 'T1wHierarchical':
|
6513
|
+
is_t1=True
|
6514
|
+
moddersub='T1Hier'
|
6515
|
+
elif mod_name == 'T1wHierarchicalSR':
|
6516
|
+
is_t1=True
|
6517
|
+
moddersub='T1HSR'
|
6518
|
+
if exists( nrgwidefn ):
|
6519
|
+
if verbose:
|
6520
|
+
print( nrgwidefn + " exists")
|
6521
|
+
mm=read_mm_csv( nrgwidefn, colprefix=moddersub+'_', is_t1=is_t1, separator=separator, verbose=verbose )
|
6522
|
+
if mm is not None:
|
6523
|
+
if mod_name == 'T1wHierarchical':
|
6524
|
+
a=list( csvrow.keys() )
|
6525
|
+
b=list( mm.keys() )
|
6526
|
+
abintersect=list(set(b).intersection( set(a) ) )
|
6527
|
+
if len( abintersect ) > 0 :
|
6528
|
+
for qq in abintersect:
|
6529
|
+
mm.pop( qq )
|
6530
|
+
mm.index=csvrow.index
|
6531
|
+
uidname = mod_name + '_mmwide_filename'
|
6532
|
+
mm[ uidname ] = rootid
|
6533
|
+
csvrow=pd.concat( [csvrow,mm], axis=1 )
|
6534
|
+
else:
|
6535
|
+
if verbose and report_missing:
|
6536
|
+
print( nrgwidefn + " absent")
|
6537
|
+
if alldf.shape[0] == 0:
|
6538
|
+
alldf = csvrow.copy()
|
6539
|
+
alldf = alldf.loc[:,~alldf.columns.duplicated()]
|
6540
|
+
else:
|
6541
|
+
csvrow=csvrow.loc[:,~csvrow.columns.duplicated()]
|
6542
|
+
alldf = alldf.loc[:,~alldf.columns.duplicated()]
|
6543
|
+
alldf = pd.concat( [alldf, csvrow], axis=0, ignore_index=True)
|
6544
|
+
return alldf
|
6545
|
+
|
6033
6546
|
def assemble_modality_specific_dataframes( mm_wide_csvs, hierdfin, nrg_modality, separator='-', progress=None, verbose=False ):
|
6034
6547
|
moddersub = re.sub( "[*]","",nrg_modality)
|
6035
6548
|
nmdf=pd.DataFrame()
|
@@ -6136,7 +6649,7 @@ def boot_wmh( flair, t1, t1seg, mmfromconvexhull = 0.0, strict=True,
|
|
6136
6649
|
if prior_probability is not None:
|
6137
6650
|
augprob_prior = flair * 0.0
|
6138
6651
|
for n in range(n_simulations):
|
6139
|
-
augflair, tx, itx = augment_image( flair, 5 )
|
6652
|
+
augflair, tx, itx = augment_image( ants.iMath(flair,"Normalize"), 5, 0.01 )
|
6140
6653
|
locwmh = wmh( augflair, t1, t1seg, mmfromconvexhull = mmfromconvexhull,
|
6141
6654
|
strict=strict, probability_mask=None, prior_probability=prior_probability )
|
6142
6655
|
if verbose:
|
@@ -6581,7 +7094,7 @@ def blind_image_assessment(
|
|
6581
7094
|
viz_filename=None,
|
6582
7095
|
title=False,
|
6583
7096
|
pull_rank=False,
|
6584
|
-
resample=
|
7097
|
+
resample=None,
|
6585
7098
|
verbose=False
|
6586
7099
|
):
|
6587
7100
|
"""
|
@@ -6638,7 +7151,7 @@ def blind_image_assessment(
|
|
6638
7151
|
json_name = re.sub(".nii.gz",".json",image_filename)
|
6639
7152
|
if exists( json_name ):
|
6640
7153
|
with open(json_name, 'r') as fcc_file:
|
6641
|
-
mymeta = json.load(fcc_file)
|
7154
|
+
mymeta = json.load(fcc_file, strict=False)
|
6642
7155
|
if verbose:
|
6643
7156
|
print(json.dumps(mymeta, indent=4))
|
6644
7157
|
mystem=Path( image ).stem
|
@@ -6681,16 +7194,30 @@ def blind_image_assessment(
|
|
6681
7194
|
else:
|
6682
7195
|
image_compare = ants.image_clone( image_b0 )
|
6683
7196
|
image = ants.iMath( image, 'TruncateIntensity',0.01,0.995)
|
7197
|
+
minspc = np.min(ants.get_spacing(image))
|
7198
|
+
maxspc = np.max(ants.get_spacing(image))
|
6684
7199
|
if resample is not None:
|
6685
7200
|
if resample == 'min':
|
6686
|
-
|
7201
|
+
if minspc < 1e-12:
|
7202
|
+
minspc = np.max(ants.get_spacing(image))
|
7203
|
+
newspc = np.repeat( minspc, 3 )
|
6687
7204
|
elif resample == 'max':
|
6688
|
-
newspc = np.repeat(
|
7205
|
+
newspc = np.repeat( maxspc, 3 )
|
6689
7206
|
else:
|
6690
7207
|
newspc = np.repeat( resample, 3 )
|
6691
7208
|
image = ants.resample_image( image, newspc )
|
6692
7209
|
image_compare = ants.resample_image( image_compare, newspc )
|
7210
|
+
else:
|
7211
|
+
# check for spc close to zero
|
7212
|
+
spc = list(ants.get_spacing(image))
|
7213
|
+
for spck in range(len(spc)):
|
7214
|
+
if spc[spck] < 1e-12:
|
7215
|
+
spc[spck]=1
|
7216
|
+
ants.set_spacing( image, spc )
|
7217
|
+
ants.set_spacing( image_compare, spc )
|
6693
7218
|
# if "NM2DMT" in image_filename or "FIXME" in image_filename or "SPECT" in image_filename or "UNKNOWN" in image_filename:
|
7219
|
+
minspc = np.min(ants.get_spacing(image))
|
7220
|
+
maxspc = np.max(ants.get_spacing(image))
|
6694
7221
|
msk = ants.threshold_image( ants.iMath(image,'Normalize'), 0.15, 1.0 )
|
6695
7222
|
# else:
|
6696
7223
|
# msk = ants.get_mask( image )
|
@@ -6727,8 +7254,17 @@ def blind_image_assessment(
|
|
6727
7254
|
imagereflect = ants.reflect_image(image, axis=0)
|
6728
7255
|
asym_err = ( image - imagereflect ).abs().mean()
|
6729
7256
|
# estimate noise by center cropping, denoizing and taking magnitude of difference
|
6730
|
-
|
6731
|
-
|
7257
|
+
nocrop=False
|
7258
|
+
if image.dimension == 3:
|
7259
|
+
if image.shape[2] == 1:
|
7260
|
+
nocrop=True
|
7261
|
+
if maxspc/minspc > 10:
|
7262
|
+
nocrop=True
|
7263
|
+
if nocrop:
|
7264
|
+
mycc = ants.image_clone( image )
|
7265
|
+
else:
|
7266
|
+
mycc = antspyt1w.special_crop( image,
|
7267
|
+
ants.get_center_of_mass( msk *0 + 1 ), patch_shape )
|
6732
7268
|
myccd = ants.denoise_image( mycc, p=2,r=2,noise_model='Gaussian' )
|
6733
7269
|
noizlevel = ( mycc - myccd ).abs().mean()
|
6734
7270
|
# ants.plot_ortho( image, crop=False, filename=viz_filename, flat=True, xyz_lines=False, orient_labels=False, xyz_pad=0 )
|
@@ -6745,7 +7281,10 @@ def blind_image_assessment(
|
|
6745
7281
|
cnrref = ( fgmean - bgmean ) / bgstd
|
6746
7282
|
psnrref = antspynet.psnr( image_compare, image )
|
6747
7283
|
ssimref = antspynet.ssim( image_compare, image )
|
6748
|
-
|
7284
|
+
if nocrop:
|
7285
|
+
mymi = math.inf
|
7286
|
+
else:
|
7287
|
+
mymi = ants.image_mutual_information( image_compare, image )
|
6749
7288
|
mriseries='NA'
|
6750
7289
|
mrimfg='NA'
|
6751
7290
|
mrimodel='NA'
|
@@ -6794,9 +7333,7 @@ def average_blind_qc_by_modality(qc_full,verbose=False):
|
|
6794
7333
|
uid = qc_full['fn'] + "_" + qc_full['modality'].astype(str)
|
6795
7334
|
to_average = uid.unique()
|
6796
7335
|
# Define column indices
|
6797
|
-
contcols = ['noise', 'snr', 'cnr', 'psnr', 'ssim', 'mi',
|
6798
|
-
'reflection_err', 'EVR', 'msk_vol', 'spc0', 'spc1', 'spc2', 'dimx',
|
6799
|
-
'dimy', 'dimz', 'slice']
|
7336
|
+
contcols = ['noise', 'snr', 'cnr', 'psnr', 'ssim', 'mi','reflection_err', 'EVR', 'msk_vol', 'spc0', 'spc1', 'spc2', 'org0','org1','org2', 'dimx', 'dimy', 'dimz', 'slice']
|
6800
7337
|
ocols = ['fn','modality', 'mriseries', 'mrimfg', 'mrimodel']
|
6801
7338
|
# restrict to columns we "know"
|
6802
7339
|
qc_full = qc_full[ocols+contcols]
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: antspymm
|
3
|
-
Version: 0.
|
3
|
+
Version: 1.0.0
|
4
4
|
Summary: multi-channel/time-series medical image processing with antspyx
|
5
5
|
Home-page: https://github.com/stnava/ANTsPyMM
|
6
6
|
Author: Avants, Gosselin, Tustison, Reardon
|
@@ -11,7 +11,7 @@ License-File: LICENSE
|
|
11
11
|
Requires-Dist: h5py (>=2.10.0)
|
12
12
|
Requires-Dist: numpy (>=1.19.4)
|
13
13
|
Requires-Dist: pandas (>=1.0.1)
|
14
|
-
Requires-Dist: antspyx (>=0.
|
14
|
+
Requires-Dist: antspyx (>=0.4.1)
|
15
15
|
Requires-Dist: antspyt1w (>=0.2.3)
|
16
16
|
Requires-Dist: pathlib
|
17
17
|
Requires-Dist: dipy
|
@@ -91,6 +91,17 @@ will all modalities will take around 2 hours on an average laptop.
|
|
91
91
|
|
92
92
|
documentation of functions [here](http://htmlpreview.github.io/?https://github.com/stnava/ANTsPyMM/blob/main/docs/antspymm/mm.html).
|
93
93
|
|
94
|
+
|
95
|
+
achieved through four steps (recommended approach):
|
96
|
+
|
97
|
+
1. organize data in NRG format
|
98
|
+
|
99
|
+
2. perform blind QC
|
100
|
+
|
101
|
+
3. compute outlierness per modality and select optimally matched modalities ( steps 3.1 and 3.2 )
|
102
|
+
|
103
|
+
4. run the main antspymm function
|
104
|
+
|
94
105
|
# first time setup
|
95
106
|
|
96
107
|
```python
|
@@ -0,0 +1,7 @@
|
|
1
|
+
antspymm/__init__.py,sha256=BTNN_iisXoz2on4gVcAQWFB_qJYDM-yqZOJU1xho9sw,2931
|
2
|
+
antspymm/mm.py,sha256=UMAxi91xK-rFUQT6StQIAkLKyphGMpM_Jy0pFGiY_8E,308235
|
3
|
+
antspymm-1.0.0.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
4
|
+
antspymm-1.0.0.dist-info/METADATA,sha256=RjWizo9kiWyCCLDYjdP2LLDlcqDT0zmqU6Q8H4x8Zh8,10717
|
5
|
+
antspymm-1.0.0.dist-info/WHEEL,sha256=2wepM1nk4DS4eFpYrW1TTqPcoGNfHhhO_i5m4cOimbo,92
|
6
|
+
antspymm-1.0.0.dist-info/top_level.txt,sha256=iyD1sRhCKzfwKRJLq5ZUeV9xsv1cGQl8Ejp6QwXM1Zg,9
|
7
|
+
antspymm-1.0.0.dist-info/RECORD,,
|
antspymm-0.9.7.dist-info/RECORD
DELETED
@@ -1,7 +0,0 @@
|
|
1
|
-
antspymm/__init__.py,sha256=81mPpK_dfpuD0bVTpTr1U5oxOA4dvUqcShgxo0herXc,2690
|
2
|
-
antspymm/mm.py,sha256=6ETAYzaAw1-MznWTS6JN693OJshqa2AV6whPdLBoKDY,285326
|
3
|
-
antspymm-0.9.7.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
4
|
-
antspymm-0.9.7.dist-info/METADATA,sha256=roFi7QJkXiLyAgdcPTsW8HgXKLlk2cuUAdkpTGAHPTM,10476
|
5
|
-
antspymm-0.9.7.dist-info/WHEEL,sha256=2wepM1nk4DS4eFpYrW1TTqPcoGNfHhhO_i5m4cOimbo,92
|
6
|
-
antspymm-0.9.7.dist-info/top_level.txt,sha256=iyD1sRhCKzfwKRJLq5ZUeV9xsv1cGQl8Ejp6QwXM1Zg,9
|
7
|
-
antspymm-0.9.7.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|