Source code for mantidimaging.gui.windows.image_load_dialog.presenter

# Copyright (C) 2022 ISIS Rutherford Appleton Laboratory UKRI
# SPDX - License - Identifier: GPL-3.0-or-later

import os
import traceback
from logging import getLogger
from pathlib import Path
from typing import TYPE_CHECKING, Optional, NamedTuple, Dict

from mantidimaging.core.io.loader import load_log
from mantidimaging.core.io.loader.loader import read_in_file_information, FileInformation
from mantidimaging.core.io.utility import get_file_extension, get_prefix, find_images, find_log, find_180deg_proj
from mantidimaging.core.utility.data_containers import LoadingParameters, ImageParameters
from mantidimaging.gui.windows.image_load_dialog.field import Field

if TYPE_CHECKING:
    from mantidimaging.gui.windows.image_load_dialog import ImageLoadDialog  # pragma: no cover

logger = getLogger(__name__)


[docs] class TypeInfo(NamedTuple): name: str suffix: str mode: str
FILE_TYPES: Dict[str, TypeInfo] = { "Sample": TypeInfo("Sample", "", "sample"), "Flat Before": TypeInfo("Flat", "Before", "images"), "Flat After": TypeInfo("Flat", "After", "images"), "Dark Before": TypeInfo("Dark", "Before", "images"), "Dark After": TypeInfo("Dark", "After", "images"), "180 degree": TypeInfo("180 degree", "", "180"), "Sample Log": TypeInfo("Sample Log", "", "log"), "Flat Before Log": TypeInfo("Flat Before Log", "", "log"), "Flat After Log": TypeInfo("Flat After Log", "", "log"), }
[docs] class LoadPresenter: view: 'ImageLoadDialog' def __init__(self, view: 'ImageLoadDialog'): self.view = view self.image_format = '' self.single_mem = 0 self.last_file_info: Optional[FileInformation] = None self.dtype = '32'
[docs] def do_update_field(self, field: Field): if field.file_info.mode == "sample": self.do_update_sample() elif field.file_info.mode == "images": self.do_update_flat_or_dark(field) elif field.file_info.name == "Sample Log": self.do_update_sample_log(field) elif field.file_info.mode in ["log", "180"]: self.do_update_single_file(field)
[docs] def do_update_sample(self): """ Updates the memory usage and the indices in the dialog. """ selected_file = self.view.select_file("Sample") if not selected_file: self.view.ok_button.setEnabled(False) return False self.view.sample.path = selected_file self.view.sample.widget.setExpanded(True) sample_filename = self.view.sample.file() self.image_format = get_file_extension(sample_filename) filename = self.view.sample.path_text() dirname = self.view.sample.directory() try: self.last_file_info = read_in_file_information(dirname, in_prefix=get_prefix(filename), in_format=self.image_format) except Exception as e: getLogger(__name__).error(f"Failed to read file {sample_filename} {e}") self.view.show_error("Failed to read this file. See log for details.", traceback.format_exc()) self.last_file_info = None return sample_dirname = Path(dirname) for file_info_name, file_info in FILE_TYPES.items(): if file_info.mode == "images": field = self.view.fields[file_info_name] images = find_images(sample_dirname, file_info.name, suffix=file_info.suffix, look_without_suffix="Before" in file_info_name, image_format=self.image_format, logger=logger) field.set_images(images) elif file_info.mode == "180": field = self.view.fields[file_info_name] field.path = find_180deg_proj(sample_dirname, self.image_format, logger) try: self.set_sample_log(self.view.fields["Sample Log"], sample_dirname, self.view.sample.directory(), self.last_file_info.filenames) except RuntimeError as err: self.view.show_error(str(err), traceback.format_exc()) self.view.fields["Sample Log"].use = False for pos in ["Before", "After"]: self.view.fields[f"Flat {pos} Log"].path = find_log(sample_dirname, self.view.fields[f"Flat {pos}"].directory(), logger) self.view.fields[f"Flat {pos} Log"].use = False self.view.images_are_sinograms.setChecked(self.last_file_info.sinograms) self.view.sample.update_indices(self.last_file_info.shape[0]) self.view.sample.update_shape(self.last_file_info.shape[1:]) self.view.enable_preview_all_buttons() self.view.ok_button.setEnabled(True)
[docs] def do_update_flat_or_dark(self, field: Field): name = field.file_info.name suffix = field.file_info.suffix selected_file = self.view.select_file(name) if not selected_file: return selected_dir = Path(os.path.dirname(selected_file)) images = find_images(selected_dir, name, suffix, image_format=self.image_format, logger=logger) if not images: base_name = os.path.basename(selected_file).rpartition("_")[0] images = find_images(selected_dir, base_name, "", image_format=self.image_format, logger=logger) field.set_images(images)
[docs] def get_parameters(self) -> LoadingParameters: lp = LoadingParameters() for image_group in [k for k, v in FILE_TYPES.items() if v.mode in ["images", "sample"]]: image_field = self.view.fields[image_group] if not image_field.use.isChecked() or image_field.path_text() == "": continue params = ImageParameters(input_path=image_field.directory(), format=self.image_format, prefix=get_prefix(image_field.path_text())) if image_group == "Sample": params.indices = image_field.indices if image_group + " Log" in self.view.fields: log_field = self.view.fields[image_group + " Log"] if log_field.use.isChecked(): params.log_file = log_field.path_text() lp.set(image_group, params) field_180 = self.view.fields["180 degree"] if field_180.use.isChecked() and field_180.path_text() != "": lp.proj_180deg = ImageParameters(input_path=field_180.directory(), prefix=os.path.splitext(field_180.path_text())[0], format=self.image_format) lp.name = self.view.sample.file() lp.pixel_size = self.view.pixelSize.value() lp.dtype = self.view.pixel_bit_depth.currentText() lp.sinograms = self.view.images_are_sinograms.isChecked() lp.pixel_size = self.view.pixelSize.value() return lp
def _update_field_action(self, field: Field, file_name): if file_name is not None: field.path = file_name field.use = True # type: ignore
[docs] def do_update_single_file(self, field: Field): name = field.file_info.name is_image_file = field.file_info.mode in ["image", "180"] file_name = self.view.select_file(name, is_image_file) if file_name is None: return self._update_field_action(field, file_name)
[docs] def do_update_sample_log(self, field: Field): name = field.file_info.name if self.last_file_info is None: raise RuntimeError("Please select sample data to be loaded first!") file_name = self.view.select_file(name, False) # this is set when the user selects sample data self.ensure_sample_log_consistency(field, file_name, self.last_file_info.filenames)
[docs] def ensure_sample_log_consistency(self, field: Field, file_name, image_filenames): if file_name is None or file_name == "": return log = load_log(file_name) log.raise_if_angle_missing(image_filenames) self._update_field_action(field, file_name)
[docs] def set_sample_log(self, sample_log: Field, sample_dirname, log_name, image_filenames): sample_log_filepath = find_log(sample_dirname, log_name, logger) self.ensure_sample_log_consistency(sample_log, sample_log_filepath, image_filenames) sample_log.path = sample_log_filepath