|
9 | 9 | from .base import (SimpleInterface, TraitedSpec, BaseInterfaceInputSpec,
|
10 | 10 | traits, File)
|
11 | 11 |
|
| 12 | + |
| 13 | +class RescaleInputSpec(BaseInterfaceInputSpec): |
| 14 | + in_file = File(exists=True, mandatory=True, |
| 15 | + desc='Skull-stripped image to rescale') |
| 16 | + ref_file = File(exists=True, mandatory=True, |
| 17 | + desc='Skull-stripped reference image') |
| 18 | + invert = traits.Bool(desc='Invert contrast of rescaled image') |
| 19 | + percentile = traits.Range(low=0., high=50., value=0., usedefault=True, |
| 20 | + desc='Percentile to use for reference to allow ' |
| 21 | + 'for outliers - 1 indicates the 1st and ' |
| 22 | + '99th percentiles in the input file will ' |
| 23 | + 'be mapped to the 99th and 1st percentiles ' |
| 24 | + 'in the reference; 0 indicates minima and ' |
| 25 | + 'maxima will be mapped') |
| 26 | + |
| 27 | + |
| 28 | +class RescaleOutputSpec(TraitedSpec): |
| 29 | + out_file = File(exists=True, desc='Rescaled image') |
| 30 | + |
| 31 | + |
| 32 | +class Rescale(SimpleInterface): |
| 33 | + """Rescale an image |
| 34 | +
|
| 35 | + Rescales the non-zero portion of ``in_file`` to match the bounds of the ' |
| 36 | + non-zero portion of ``ref_file``. |
| 37 | + Reference values in the input and reference images are defined by the |
| 38 | + ``percentile`` parameter, and the reference values in each image are |
| 39 | + identified and the remaining values are scaled accordingly. |
| 40 | + In the case of ``percentile == 0``, the reference values are the maxima |
| 41 | + and minima of each image. |
| 42 | + If the ``invert`` parameter is set, the input file is inverted prior to |
| 43 | + rescaling. |
| 44 | +
|
| 45 | + Examples |
| 46 | + -------- |
| 47 | +
|
| 48 | + To use a high-resolution T1w image as a registration target for a T2\* |
| 49 | + image, it may be useful to invert the T1w image and rescale to the T2\* |
| 50 | + range. |
| 51 | + Using the 1st and 99th percentiles may reduce the impact of outlier |
| 52 | + voxels. |
| 53 | +
|
| 54 | + >>> from nipype.interfaces.image import Rescale |
| 55 | + >>> invert_t1w = Reorient(invert=True) |
| 56 | + >>> invert_t1w.inputs.in_file = 'structural.nii' |
| 57 | + >>> invert_t1w.inputs.ref_file = 'functional.nii' |
| 58 | + >>> invert_t1w.inputs.percentile = 1. |
| 59 | + >>> res = invert_t1w.run() # doctest: +SKIP |
| 60 | +
|
| 61 | + """ |
| 62 | + input_spec = RescaleInputSpec |
| 63 | + output_spec = RescaleOutputSpec |
| 64 | + |
| 65 | + def _run_interface(self, runtime): |
| 66 | + img = nb.load(self.inputs.in_file) |
| 67 | + data = img.get_data() |
| 68 | + ref_data = nb.load(self.inputs.ref_file).get_data() |
| 69 | + |
| 70 | + in_mask = data > 0 |
| 71 | + ref_mask = ref_data > 0 |
| 72 | + |
| 73 | + q = [self.inputs.percentile, 100. - self.inputs.percentile] |
| 74 | + in_low, in_high = np.percentile(data[in_mask], q) |
| 75 | + ref_low, ref_high = np.percentile(ref_data[ref_mask], q) |
| 76 | + scale_factor = (ref_high - ref_low) / (in_high - in_low) |
| 77 | + |
| 78 | + signal = in_high - data if self.inputs.invert else data - in_low |
| 79 | + out_data = in_mask * (signal * scale_factor + ref_low) |
| 80 | + |
| 81 | + suffix = '_inv' if self.inputs.invert else '_rescaled' |
| 82 | + out_file = fname_presuffix(self.inputs.in_file, suffix=suffix, |
| 83 | + newpath=runtime.cwd) |
| 84 | + img.__class__(out_data, img.affine, img.header).to_filename(out_file) |
| 85 | + |
| 86 | + self._results['out_file'] = out_file |
| 87 | + return runtime |
| 88 | + |
| 89 | + |
12 | 90 | _axes = ('RL', 'AP', 'SI')
|
13 | 91 | _orientations = tuple(
|
14 | 92 | ''.join((x[i], y[j], z[k]))
|
|
0 commit comments