Source code for mantidimaging.gui.windows.stack_visualiser.presenter
# Copyright (C) 2021 ISIS Rutherford Appleton Laboratory UKRI
# SPDX - License - Identifier: GPL-3.0-or-later
from __future__ import annotations
import numpy as np
import traceback
from enum import IntEnum, auto
from logging import getLogger
from typing import TYPE_CHECKING
from mantidimaging.core.data import ImageStack
from mantidimaging.core.operation_history import const
from mantidimaging.core.utility.sensible_roi import SensibleROI
from mantidimaging.gui.mvp_base import BasePresenter
from .model import SVModel
from ...utility.common import operation_in_progress
from mantidimaging.core.data.dataset import Dataset
if TYPE_CHECKING:
from .view import StackVisualiserView # pragma: no cover
[docs]
class SVNotification(IntEnum):
REFRESH_IMAGE = auto()
TOGGLE_IMAGE_MODE = auto()
SWAP_AXES = auto()
DUPE_STACK = auto()
DUPE_STACK_ROI = auto()
[docs]
class SVParameters(IntEnum):
"""
Stack Visualiser parameters that the Stack Visualiser presenter can retrieve
"""
ROI = 0
[docs]
class SVImageMode(IntEnum):
NORMAL = 0
SUMMED = 1
[docs]
class StackVisualiserPresenter(BasePresenter):
view: StackVisualiserView
def __init__(self, view: StackVisualiserView, images: ImageStack):
super().__init__(view)
self.model = SVModel()
self.images = images
self._current_image_index = 0
self.image_mode: SVImageMode = SVImageMode.NORMAL
self.summed_image = None
[docs]
def notify(self, signal):
try:
if signal == SVNotification.REFRESH_IMAGE:
self.refresh_image()
elif signal == SVNotification.TOGGLE_IMAGE_MODE:
self.toggle_image_mode()
elif signal == SVNotification.SWAP_AXES:
self.create_swapped_axis_stack()
elif signal == SVNotification.DUPE_STACK:
self.dupe_stack()
elif signal == SVNotification.DUPE_STACK_ROI:
self.dupe_stack_roi()
except Exception as e:
self.show_error(e, traceback.format_exc())
getLogger(__name__).exception("Notification handler failed")
[docs]
def delete_data(self):
self.images = None
self.view.cleanup()
self.view = None
[docs]
def refresh_image(self):
if self.image_mode is SVImageMode.SUMMED:
self.view.image = self.summed_image
else:
self.view.set_image(self.images)
[docs]
def get_parameter_value(self, parameter: SVParameters):
"""
Gets a parameter from the stack visualiser for use elsewhere (e.g. operations).
:param parameter: The parameter value to be retrieved
"""
if parameter == SVParameters.ROI:
return self.view.current_roi
else:
raise ValueError("Invalid parameter name has been requested from the Stack "
f"Visualiser, parameter: {parameter}")
[docs]
def toggle_image_mode(self):
if self.image_mode is SVImageMode.NORMAL:
self.image_mode = SVImageMode.SUMMED
else:
self.image_mode = SVImageMode.NORMAL
if self.image_mode is SVImageMode.SUMMED and \
(self.summed_image is None
or self.summed_image.shape != self.images.data.shape[1:]):
self.summed_image = self.model.sum_images(self.images.data)
self.refresh_image()
[docs]
def create_swapped_axis_stack(self):
with operation_in_progress("Creating sinograms, copying data, this may take a while",
"The data is being copied, this may take a while.", self.view):
new_stack = self.images.copy(flip_axes=True)
new_stack.name = self.images.name + "_sino"
new_stack.record_operation(const.OPERATION_NAME_AXES_SWAP, display_name="Axes Swapped")
self.add_sinograms_to_model_and_update_view(new_stack)
[docs]
def dupe_stack(self):
with operation_in_progress("Copying data, this may take a while",
"The data is being copied, this may take a while.", self.view):
new_images = self.images.copy(flip_axes=False)
new_images.name = self.images.name
self.add_new_dataset_to_model_and_update_view(new_images)
[docs]
def dupe_stack_roi(self):
with operation_in_progress("Copying data, this may take a while",
"The data is being copied, this may take a while.", self.view):
new_images = self.images.copy_roi(SensibleROI.from_points(*self.view.image_view.get_roi()))
new_images.name = self.images.name
self.add_new_dataset_to_model_and_update_view(new_images)
[docs]
def add_new_dataset_to_model_and_update_view(self, images: ImageStack):
dataset = Dataset(stacks=[images], name=images.name)
self.view._main_window.presenter.model.add_dataset_to_model(dataset)
self.view._main_window.presenter.update_dataset_tree()
self.view._main_window.presenter.create_dataset_stack_visualisers(dataset)
self.view._main_window.model_changed.emit()
[docs]
def get_num_images(self) -> int:
return self.images.num_projections
[docs]
def find_image_from_angle(self, selected_angle: float) -> int:
selected_angle = np.deg2rad(selected_angle)
for index, angle in enumerate(self.images.projection_angles().value):
if angle >= selected_angle:
return index
return len(self.images.projection_angles().value)
[docs]
def add_sinograms_to_model_and_update_view(self, new_stack: ImageStack):
self.view._main_window.presenter.add_sinograms_to_dataset_and_update_view(new_stack, self.images.id)