|
| 1 | +# -*- coding: utf-8 -*- |
| 2 | +# emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: nil -*- |
| 3 | +# vi: set ft=python sts=4 ts=4 sw=4 et: |
| 4 | +"""This module provides interfaces for workbench surface commands""" |
| 5 | +from __future__ import (print_function, division, unicode_literals, |
| 6 | + absolute_import) |
| 7 | +import os |
| 8 | + |
| 9 | +from ..base import (TraitedSpec, File, traits, CommandLineInputSpec) |
| 10 | +from .base import WBCommand |
| 11 | +from ... import logging |
| 12 | + |
| 13 | +iflogger = logging.getLogger('interface') |
| 14 | + |
| 15 | + |
| 16 | +class MetricResampleInputSpec(CommandLineInputSpec): |
| 17 | + in_file = File( |
| 18 | + exists=True, |
| 19 | + mandatory=True, |
| 20 | + argstr="%s", |
| 21 | + position=0, |
| 22 | + desc="The metric file to resample") |
| 23 | + current_sphere = File( |
| 24 | + exists=True, |
| 25 | + mandatory=True, |
| 26 | + argstr="%s", |
| 27 | + position=1, |
| 28 | + desc="A sphere surface with the mesh that the metric is currently on") |
| 29 | + new_sphere = File( |
| 30 | + exists=True, |
| 31 | + mandatory=True, |
| 32 | + argstr="%s", |
| 33 | + position=2, |
| 34 | + desc="A sphere surface that is in register with <current-sphere> and" |
| 35 | + " has the desired output mesh") |
| 36 | + method = traits.Enum( |
| 37 | + "ADAP_BARY_AREA", |
| 38 | + "BARYCENTRIC", |
| 39 | + argstr="%s", |
| 40 | + mandatory=True, |
| 41 | + position=3, |
| 42 | + desc="The method name - ADAP_BARY_AREA method is recommended for" |
| 43 | + " ordinary metric data, because it should use all data while" |
| 44 | + " downsampling, unlike BARYCENTRIC. If ADAP_BARY_AREA is used," |
| 45 | + " exactly one of area_surfs or area_metrics must be specified") |
| 46 | + out_file = File( |
| 47 | + name_source=["new_sphere"], |
| 48 | + name_template="%s.out", |
| 49 | + keep_extension=True, |
| 50 | + argstr="%s", |
| 51 | + position=4, |
| 52 | + desc="The output metric") |
| 53 | + area_surfs = traits.Bool( |
| 54 | + position=5, |
| 55 | + argstr="-area-surfs", |
| 56 | + xor=["area_metrics"], |
| 57 | + desc="Specify surfaces to do vertex area correction based on") |
| 58 | + area_metrics = traits.Bool( |
| 59 | + position=5, |
| 60 | + argstr="-area-metrics", |
| 61 | + xor=["area_surfs"], |
| 62 | + desc="Specify vertex area metrics to do area correction based on") |
| 63 | + current_area = File( |
| 64 | + exists=True, |
| 65 | + position=6, |
| 66 | + argstr="%s", |
| 67 | + desc="A relevant anatomical surface with <current-sphere> mesh OR" |
| 68 | + " a metric file with vertex areas for <current-sphere> mesh") |
| 69 | + new_area = File( |
| 70 | + exists=True, |
| 71 | + position=7, |
| 72 | + argstr="%s", |
| 73 | + desc="A relevant anatomical surface with <current-sphere> mesh OR" |
| 74 | + " a metric file with vertex areas for <current-sphere> mesh") |
| 75 | + roi_metric = File( |
| 76 | + exists=True, |
| 77 | + position=8, |
| 78 | + argstr="-current-roi %s", |
| 79 | + desc="Input roi on the current mesh used to exclude non-data vertices") |
| 80 | + valid_roi_out = traits.Bool( |
| 81 | + position=9, |
| 82 | + argstr="-valid-roi-out", |
| 83 | + desc="Output the ROI of vertices that got data from valid source vertices") |
| 84 | + largest = traits.Bool( |
| 85 | + position=10, |
| 86 | + argstr="-largest", |
| 87 | + desc="Use only the value of the vertex with the largest weight") |
| 88 | + |
| 89 | + |
| 90 | +class MetricResampleOutputSpec(TraitedSpec): |
| 91 | + out_file = File(exists=True, desc="the output metric") |
| 92 | + roi_file = File(desc="ROI of vertices that got data from valid source vertices") |
| 93 | + |
| 94 | + |
| 95 | +class MetricResample(WBCommand): |
| 96 | + """ |
| 97 | + Resample a metric file to a different mesh |
| 98 | +
|
| 99 | + Resamples a metric file, given two spherical surfaces that are in |
| 100 | + register. If ``ADAP_BARY_AREA`` is used, exactly one of -area-surfs or |
| 101 | + ``-area-metrics`` must be specified. |
| 102 | +
|
| 103 | + The ``ADAP_BARY_AREA`` method is recommended for ordinary metric data, |
| 104 | + because it should use all data while downsampling, unlike ``BARYCENTRIC``. |
| 105 | + The recommended areas option for most data is individual midthicknesses |
| 106 | + for individual data, and averaged vertex area metrics from individual |
| 107 | + midthicknesses for group average data. |
| 108 | +
|
| 109 | + The ``-current-roi`` option only masks the input, the output may be slightly |
| 110 | + dilated in comparison, consider using ``-metric-mask`` on the output when |
| 111 | + using ``-current-roi``. |
| 112 | +
|
| 113 | + The ``-largest option`` results in nearest vertex behavior when used with |
| 114 | + ``BARYCENTRIC``. When resampling a binary metric, consider thresholding at |
| 115 | + 0.5 after resampling rather than using ``-largest``. |
| 116 | +
|
| 117 | + >>> from nipype.interfaces.workbench import MetricResample |
| 118 | + >>> metres = MetricResample() |
| 119 | + >>> metres.inputs.in_file = 'sub-01_task-rest_bold_space-fsaverage5.L.func.gii' |
| 120 | + >>> metres.inputs.method = 'ADAP_BARY_AREA' |
| 121 | + >>> metres.inputs.current_sphere = 'fsaverage5_std_sphere.L.10k_fsavg_L.surf.gii' |
| 122 | + >>> metres.inputs.new_sphere = 'fs_LR-deformed_to-fsaverage.L.sphere.32k_fs_LR.surf.gii' |
| 123 | + >>> metres.inputs.area_metrics = True |
| 124 | + >>> metres.inputs.current_area = 'fsaverage5.L.midthickness_va_avg.10k_fsavg_L.shape.gii' |
| 125 | + >>> metres.inputs.new_area = 'fs_LR.L.midthickness_va_avg.32k_fs_LR.shape.gii' |
| 126 | + >>> metres.cmdline |
| 127 | + 'wb_command -metric-resample sub-01_task-rest_bold_space-fsaverage5.L.func.gii \ |
| 128 | + fsaverage5_std_sphere.L.10k_fsavg_L.surf.gii \ |
| 129 | + fs_LR-deformed_to-fsaverage.L.sphere.32k_fs_LR.surf.gii \ |
| 130 | + ADAP_BARY_AREA fs_LR-deformed_to-fsaverage.L.sphere.32k_fs_LR.surf.out \ |
| 131 | + -area-metrics fsaverage5.L.midthickness_va_avg.10k_fsavg_L.shape.gii \ |
| 132 | + fs_LR.L.midthickness_va_avg.32k_fs_LR.shape.gii' |
| 133 | + """ |
| 134 | + input_spec = MetricResampleInputSpec |
| 135 | + output_spec = MetricResampleOutputSpec |
| 136 | + _cmd = 'wb_command -metric-resample' |
| 137 | + |
| 138 | + def _format_arg(self, opt, spec, val): |
| 139 | + if opt in ['current_area', 'new_area']: |
| 140 | + if not self.inputs.area_surfs and not self.inputs.area_metrics: |
| 141 | + raise ValueError("{} was set but neither area_surfs or" |
| 142 | + " area_metrics were set".format(opt)) |
| 143 | + if opt == "method": |
| 144 | + if (val == "ADAP_BARY_AREA" and |
| 145 | + not self.inputs.area_surfs and |
| 146 | + not self.inputs.area_metrics): |
| 147 | + raise ValueError("Exactly one of area_surfs or area_metrics" |
| 148 | + " must be specified") |
| 149 | + if opt == "valid_roi_out" and val: |
| 150 | + # generate a filename and add it to argstr |
| 151 | + roi_out = self._gen_filename(self.inputs.in_file, suffix='_roi') |
| 152 | + iflogger.info("Setting roi output file as", roi_out) |
| 153 | + spec.argstr += " " + roi_out |
| 154 | + return super(MetricResample, self)._format_arg(opt, spec, val) |
| 155 | + |
| 156 | + def _list_outputs(self): |
| 157 | + outputs = super(MetricResample, self)._list_outputs() |
| 158 | + if self.inputs.valid_roi_out: |
| 159 | + roi_file = self._gen_filename(self.inputs.in_file, suffix='_roi') |
| 160 | + outputs['roi_file'] = os.path.abspath(roi_file) |
| 161 | + return outputs |
0 commit comments