7
7
8
8
import os
9
9
from ...external .due import BibTeX
10
- from ...utils .filemanip import split_filename , copyfile , which
10
+ from ...utils .filemanip import split_filename , copyfile , which , fname_presuffix
11
11
from ..base import TraitedSpec , File , traits , InputMultiPath , OutputMultiPath , isdefined
12
12
from .base import ANTSCommand , ANTSCommandInputSpec
13
13
@@ -274,18 +274,20 @@ class N4BiasFieldCorrectionInputSpec(ANTSCommandInputSpec):
274
274
argstr = '--input-image %s' ,
275
275
mandatory = True ,
276
276
desc = ('input for bias correction. Negative values or values close to '
277
- 'zero should be processed prior to correction' ))
277
+ 'zero should be processed prior to correction' ))
278
278
mask_image = File (
279
279
argstr = '--mask-image %s' ,
280
280
desc = ('image to specify region to perform final bias correction in' ))
281
281
weight_image = File (
282
282
argstr = '--weight-image %s' ,
283
283
desc = ('image for relative weighting (e.g. probability map of the white '
284
- 'matter) of voxels during the B-spline fitting. ' ))
284
+ 'matter) of voxels during the B-spline fitting. ' ))
285
285
output_image = traits .Str (
286
286
argstr = '--output %s' ,
287
287
desc = 'output file name' ,
288
- genfile = True ,
288
+ name_source = ['input_image' ],
289
+ name_template = '%s_corrected' ,
290
+ keep_extension = True ,
289
291
hash_files = False )
290
292
bspline_fitting_distance = traits .Float (argstr = "--bspline-fitting %s" )
291
293
bspline_order = traits .Int (requires = ['bspline_fitting_distance' ])
@@ -306,6 +308,14 @@ class N4BiasFieldCorrectionInputSpec(ANTSCommandInputSpec):
306
308
usedefault = True ,
307
309
desc = 'copy headers of the original image into the '
308
310
'output (corrected) file' )
311
+ rescale_intensities = traits .Bool (
312
+ False , usedefault = True , argstr = '-r' ,
313
+ desc = """\
314
+ At each iteration, a new intensity mapping is calculated and applied but there
315
+ is nothing which constrains the new intensity range to be within certain values.
316
+ The result is that the range can "drift" from the original at each iteration.
317
+ This option rescales to the [min,max] range of the original image intensities
318
+ within the user-specified mask.""" )
309
319
310
320
311
321
class N4BiasFieldCorrectionOutputSpec (TraitedSpec ):
@@ -314,7 +324,10 @@ class N4BiasFieldCorrectionOutputSpec(TraitedSpec):
314
324
315
325
316
326
class N4BiasFieldCorrection (ANTSCommand ):
317
- """N4 is a variant of the popular N3 (nonparameteric nonuniform normalization)
327
+ """
328
+ Bias field correction.
329
+
330
+ N4 is a variant of the popular N3 (nonparameteric nonuniform normalization)
318
331
retrospective bias correction algorithm. Based on the assumption that the
319
332
corruption of the low frequency bias field can be modeled as a convolution of
320
333
the intensity histogram by a Gaussian, the basic algorithmic protocol is to
@@ -373,28 +386,9 @@ class N4BiasFieldCorrection(ANTSCommand):
373
386
input_spec = N4BiasFieldCorrectionInputSpec
374
387
output_spec = N4BiasFieldCorrectionOutputSpec
375
388
376
- def _gen_filename (self , name ):
377
- if name == 'output_image' :
378
- output = self .inputs .output_image
379
- if not isdefined (output ):
380
- _ , name , ext = split_filename (self .inputs .input_image )
381
- output = name + '_corrected' + ext
382
- return output
383
-
384
- if name == 'bias_image' :
385
- output = self .inputs .bias_image
386
- if not isdefined (output ):
387
- _ , name , ext = split_filename (self .inputs .input_image )
388
- output = name + '_bias' + ext
389
- return output
390
- return None
391
-
392
389
def _format_arg (self , name , trait_spec , value ):
393
- if ((name == 'output_image' ) and
394
- (self .inputs .save_bias or isdefined (self .inputs .bias_image ))):
395
- bias_image = self ._gen_filename ('bias_image' )
396
- output = self ._gen_filename ('output_image' )
397
- newval = '[ %s, %s ]' % (output , bias_image )
390
+ if name == 'output_image' and getattr (self , '_out_bias_file' , None ):
391
+ newval = '[ %s, %s ]' % (value , getattr (self , '_out_bias_file' ))
398
392
return trait_spec .argstr % newval
399
393
400
394
if name == 'bspline_fitting_distance' :
@@ -418,34 +412,40 @@ def _format_arg(self, name, trait_spec, value):
418
412
name , trait_spec , value )
419
413
420
414
def _parse_inputs (self , skip = None ):
421
- if skip is None :
422
- skip = []
423
- skip += ['save_bias' , 'bias_image' ]
415
+ skip = (skip or []) + ['save_bias' , 'bias_image' ]
416
+ if self .inputs .save_bias or isdefined (self .inputs .bias_image ):
417
+ bias_image = self .inputs .bias_image
418
+ if not isdefined (bias_image ):
419
+ bias_image = fname_presuffix (os .path .basename (self .inputs .input_image ),
420
+ suffix = '_bias' )
421
+ setattr (self , '_out_bias_file' , bias_image )
422
+ else :
423
+ try :
424
+ delattr (self , '_out_bias_file' )
425
+ except AttributeError :
426
+ pass
424
427
return super (N4BiasFieldCorrection , self )._parse_inputs (skip = skip )
425
428
426
429
def _list_outputs (self ):
427
- outputs = self ._outputs ().get ()
428
- outputs ['output_image' ] = os .path .abspath (
429
- self ._gen_filename ('output_image' ))
430
-
431
- if self .inputs .save_bias or isdefined (self .inputs .bias_image ):
432
- outputs ['bias_image' ] = os .path .abspath (
433
- self ._gen_filename ('bias_image' ))
430
+ outputs = super (N4BiasFieldCorrection , self )._list_outputs ()
431
+ bias_image = getattr (self , '_out_bias_file' , None )
432
+ if bias_image :
433
+ outputs ['bias_image' ] = bias_image
434
434
return outputs
435
435
436
436
def _run_interface (self , runtime , correct_return_codes = (0 , )):
437
437
runtime = super (N4BiasFieldCorrection , self )._run_interface (
438
438
runtime , correct_return_codes )
439
439
440
440
if self .inputs .copy_header and runtime .returncode in correct_return_codes :
441
- self ._copy_header (self ._gen_filename ( ' output_image' ) )
442
- if self . inputs . save_bias or isdefined ( self . inputs . bias_image ):
443
- self ._copy_header (self . _gen_filename ( 'bias_image ' ))
441
+ self ._copy_header (self .inputs . output_image )
442
+ if getattr ( self , '_out_bias_file' , None ):
443
+ self ._copy_header (getattr ( self , '_out_bias_file ' ))
444
444
445
445
return runtime
446
446
447
447
def _copy_header (self , fname ):
448
- """Copy header from input image to an output image"""
448
+ """Copy header from input image to an output image. """
449
449
import nibabel as nb
450
450
in_img = nb .load (self .inputs .input_image )
451
451
out_img = nb .load (fname , mmap = False )
0 commit comments