@@ -1205,3 +1205,103 @@ def calc_moments(timeseries_file, moment):
1205
1205
m3 = stats .moment (timeseries , moment , axis = 0 )
1206
1206
zero = (m2 == 0 )
1207
1207
return np .where (zero , 0 , m3 / m2 ** (moment / 2.0 ))
1208
+
1209
+
1210
+ class NormalizeMapsInputSpec (TraitedSpec ):
1211
+ in_files = InputMultiPath (File (exists = True , mandatory = True ,
1212
+ desc = 'The tpms to be normalized' ) )
1213
+ in_mask = File (exists = True , mandatory = False ,
1214
+ desc = 'Masked voxels must sum up 1.0, 0.0 otherwise.' )
1215
+
1216
+ class NormalizeMapsOutputSpec (TraitedSpec ):
1217
+ out_files = OutputMultiPath (File (exists = True ),
1218
+ desc = "normalized maps" )
1219
+
1220
+
1221
+ class NormalizeMaps (BaseInterface ):
1222
+ """ Returns the input tissue probability maps (tpms, aka volume fractions)
1223
+ normalized to sum up 1.0 at each voxel within the mask.
1224
+
1225
+ Example
1226
+ -------
1227
+
1228
+ >>> import nipype.algorithms.misc as misc
1229
+ >>> normalize = misc.NormalizeMaps()
1230
+ >>> normalize.inputs.in_files = [ 'csf.nii', 'wm.nii', 'gm.nii' ]
1231
+ >>> normalize.inputs.in_mask = [ 'brain.nii' ]
1232
+ >>> normalize.run() # doctest: +SKIP
1233
+ """
1234
+ input_spec = NormalizeMapsInputSpec
1235
+ output_spec = NormalizeMapsOutputSpec
1236
+
1237
+ def _run_interface (self , runtime ):
1238
+ mask = None
1239
+
1240
+ if isdefined ( self .inputs .in_mask ):
1241
+ mask = self .inputs .in_mask
1242
+
1243
+ self ._out_filenames = normalize_tpms ( self .inputs .in_files , mask )
1244
+ return runtime
1245
+
1246
+ def _list_outputs (self ):
1247
+ outputs = self .output_spec ().get ()
1248
+ outputs ['out_files' ] = self ._out_filenames
1249
+ return outputs
1250
+
1251
+
1252
+ def normalize_tpms ( in_files , in_mask = None , out_files = [] ):
1253
+ """ Returns the input tissue probability maps (tpms, aka volume fractions)
1254
+ normalized to sum up 1.0 at each voxel within the mask.
1255
+ """
1256
+ import nibabel as nib
1257
+ import numpy as np
1258
+ import os .path as op
1259
+
1260
+ in_files = np .atleast_1d ( in_files ).tolist ()
1261
+
1262
+ if len ( out_files )!= len (in_files ):
1263
+ for i ,finname in enumerate ( in_files ):
1264
+ fname ,fext = op .splitext ( op .basename ( finname ) )
1265
+ if fext == '.gz' :
1266
+ fname ,fext2 = op .splitext ( fname )
1267
+ fext = fext2 + fext
1268
+
1269
+ out_file = op .abspath ( fname + '_norm' + fext )
1270
+ out_files += [ out_file ]
1271
+
1272
+ imgs = [ nib .load (fim ) for fim in in_files ]
1273
+
1274
+ if len (in_files )== 1 :
1275
+ img_data = imgs [0 ].get_data ()
1276
+ img_data [img_data > 0.0 ] = 1.0
1277
+ hdr = imgs [0 ].get_header ().copy ()
1278
+ hdr ['data_type' ]= 16
1279
+ hdr .set_data_dtype ( 'float32' )
1280
+ nib .save ( nib .Nifti1Image ( img_data .astype (np .float32 ), imgs [0 ].get_affine (), hdr ), out_files [0 ] )
1281
+ return out_files [0 ]
1282
+
1283
+ img_data = np .array ( [ im .get_data () for im in imgs ] ).astype ( 'f32' )
1284
+ #img_data[img_data>1.0] = 1.0
1285
+ img_data [img_data < 0.0 ] = 0.0
1286
+ weights = np .sum ( img_data , axis = 0 )
1287
+
1288
+ msk = np .ones_like ( imgs [0 ].get_data () )
1289
+ msk [ weights <= 0 ] = 0
1290
+
1291
+ if not in_mask is None :
1292
+ msk = nib .load ( in_mask ).get_data ()
1293
+ msk [ msk <= 0 ] = 0
1294
+ msk [ msk > 0 ] = 1
1295
+
1296
+ msk = np .ma .masked_equal ( msk , 0 )
1297
+
1298
+
1299
+ for i ,out_file in enumerate ( out_files ):
1300
+ data = np .ma .masked_equal ( img_data [i ], 0 )
1301
+ probmap = data / weights
1302
+ hdr = imgs [i ].get_header ().copy ()
1303
+ hdr ['data_type' ]= 16
1304
+ hdr .set_data_dtype ( 'float32' )
1305
+ nib .save ( nib .Nifti1Image ( probmap .astype (np .float32 ), imgs [i ].get_affine (), hdr ), out_file )
1306
+
1307
+ return out_files
0 commit comments