Source code for niworkflows.interfaces.reportlets.segmentation

# emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: nil -*-
# vi: set ft=python sts=4 ts=4 sw=4 et:
#
# Copyright 2021 The NiPreps Developers <nipreps@gmail.com>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# We support and encourage derived works from this project, please read
# about our expectations at
#
#     https://www.nipreps.org/community/licensing/
#
"""ReportCapableInterfaces for segmentation tools."""

import os

from nipype.interfaces import freesurfer, fsl
from nipype.interfaces.base import File, isdefined
from nipype.interfaces.mixins import reporting

from ... import NIWORKFLOWS_LOG
from . import base as nrb


class _FASTInputSpecRPT(nrb._SVGReportCapableInputSpec, fsl.preprocess.FASTInputSpec):
    pass


class _FASTOutputSpecRPT(reporting.ReportCapableOutputSpec, fsl.preprocess.FASTOutputSpec):
    pass


[docs] class FASTRPT(nrb.SegmentationRC, fsl.FAST): input_spec = _FASTInputSpecRPT output_spec = _FASTOutputSpecRPT def _run_interface(self, runtime): if self.generate_report: self.inputs.segments = True return super()._run_interface(runtime) def _post_run_hook(self, runtime): """generates a report showing nine slices, three per axis, of an arbitrary volume of `in_files`, with the resulting segmentation overlaid""" self._anat_file = self.inputs.in_files[0] outputs = self.aggregate_outputs(runtime=runtime) self._mask_file = outputs.tissue_class_map # We are skipping the CSF class because with combination with others # it only shows the skullstriping mask self._seg_files = outputs.tissue_class_files[1:] self._masked = False NIWORKFLOWS_LOG.info( 'Generating report for FAST (in_files %s, ' 'segmentation %s, individual tissue classes %s).', self.inputs.in_files, outputs.tissue_class_map, outputs.tissue_class_files, ) return super()._post_run_hook(runtime)
class _ReconAllInputSpecRPT( nrb._SVGReportCapableInputSpec, freesurfer.preprocess.ReconAllInputSpec ): pass class _ReconAllOutputSpecRPT( reporting.ReportCapableOutputSpec, freesurfer.preprocess.ReconAllOutputSpec ): pass
[docs] class ReconAllRPT(nrb.SurfaceSegmentationRC, freesurfer.preprocess.ReconAll): input_spec = _ReconAllInputSpecRPT output_spec = _ReconAllOutputSpecRPT def _post_run_hook(self, runtime): """generates a report showing nine slices, three per axis, of an arbitrary volume of `in_files`, with the resulting segmentation overlaid""" outputs = self.aggregate_outputs(runtime=runtime) self._anat_file = os.path.join( outputs.subjects_dir, outputs.subject_id, 'mri', 'brain.mgz' ) self._contour = os.path.join(outputs.subjects_dir, outputs.subject_id, 'mri', 'ribbon.mgz') self._masked = False NIWORKFLOWS_LOG.info('Generating report for ReconAll (subject %s)', outputs.subject_id) return super()._post_run_hook(runtime)
class _MELODICInputSpecRPT(nrb._SVGReportCapableInputSpec, fsl.model.MELODICInputSpec): out_report = File( 'melodic_reportlet.svg', usedefault=True, desc='Filename for the visual report generated by Nipype.', ) report_mask = File( desc='Mask used to draw the outline on the reportlet. ' 'If not set the mask will be derived from the data.' ) class _MELODICOutputSpecRPT(reporting.ReportCapableOutputSpec, fsl.model.MELODICOutputSpec): pass
[docs] class MELODICRPT(fsl.MELODIC): input_spec = _MELODICInputSpecRPT output_spec = _MELODICOutputSpecRPT _out_report = None def __init__(self, generate_report=False, **kwargs): super().__init__(**kwargs) self.generate_report = generate_report def _post_run_hook(self, runtime): # Run _post_run_hook of super class runtime = super()._post_run_hook(runtime) # leave early if there's nothing to do if not self.generate_report: return runtime NIWORKFLOWS_LOG.info('Generating report for MELODIC.') _melodic_dir = runtime.cwd if isdefined(self.inputs.out_dir): _melodic_dir = self.inputs.out_dir self._melodic_dir = os.path.abspath(_melodic_dir) self._out_report = self.inputs.out_report if not os.path.isabs(self._out_report): self._out_report = os.path.abspath(os.path.join(runtime.cwd, self._out_report)) mix = os.path.join(self._melodic_dir, 'melodic_mix') if not os.path.exists(mix): NIWORKFLOWS_LOG.warning("MELODIC outputs not found, assuming it didn't converge.") self._out_report = self._out_report.replace('.svg', '.html') snippet = '<h4>MELODIC did not converge, no output</h4>' with open(self._out_report, 'w') as fobj: fobj.write(snippet) return runtime self._generate_report() return runtime def _list_outputs(self): try: outputs = super()._list_outputs() except NotImplementedError: outputs = {} if self._out_report is not None: outputs['out_report'] = self._out_report return outputs def _generate_report(self): from niworkflows.viz.utils import plot_melodic_components plot_melodic_components( melodic_dir=self._melodic_dir, in_file=self.inputs.in_files[0], tr=self.inputs.tr_sec, out_file=self._out_report, compress=self.inputs.compress_report, report_mask=self.inputs.report_mask, )
class _ICA_AROMAInputSpecRPT(nrb._SVGReportCapableInputSpec, fsl.aroma.ICA_AROMAInputSpec): out_report = File( 'ica_aroma_reportlet.svg', usedefault=True, desc='Filename for the visual report generated by Nipype.', ) report_mask = File( desc='Mask used to draw the outline on the reportlet. ' 'If not set the mask will be derived from the data.' ) class _ICA_AROMAOutputSpecRPT(reporting.ReportCapableOutputSpec, fsl.aroma.ICA_AROMAOutputSpec): pass
[docs] class ICA_AROMARPT(reporting.ReportCapableInterface, fsl.ICA_AROMA): input_spec = _ICA_AROMAInputSpecRPT output_spec = _ICA_AROMAOutputSpecRPT def _generate_report(self): from niworkflows.viz.utils import plot_melodic_components plot_melodic_components( melodic_dir=self.inputs.melodic_dir, in_file=self.inputs.in_file, out_file=self.inputs.out_report, compress=self.inputs.compress_report, report_mask=self.inputs.report_mask, noise_components_file=self._noise_components_file, ) def _post_run_hook(self, runtime): outputs = self.aggregate_outputs(runtime=runtime) self._noise_components_file = os.path.join(outputs.out_dir, 'classified_motion_ICs.txt') NIWORKFLOWS_LOG.info('Generating report for ICA AROMA') return super()._post_run_hook(runtime)