Source code for mantidimaging.core.operations.rescale.rescale

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

from functools import partial
from typing import Any, Dict

import numpy as np
from numpy import float32, nanmax, nanmin, ndarray, uint16
from PyQt5.QtWidgets import QComboBox, QDoubleSpinBox

from mantidimaging.core.data import Images
from mantidimaging.core.operations.base_filter import BaseFilter
from mantidimaging.gui.utility.qt_helpers import Type
from mantidimaging.gui.windows.operations import FiltersWindowView


[docs] class RescaleFilter(BaseFilter): """Rescales the image data to a new [0, maximum output] range. Intended to be used on: Any When: Automatically used when saving as unsigned integer image formats, to avoid clipping negative values """ filter_name = 'Rescale'
[docs] @staticmethod def filter_func(images: Images, min_input: float = 0.0, max_input: float = 10000.0, max_output: float = 256.0, progress=None, data_type=None) -> Images: np.clip(images.data, min_input, max_input, out=images.data) # offset - it removes any negative values so that they don't overflow when in uint16 range images.data -= nanmin(images.data) data_max = nanmax(images.data) # slope images.data *= (max_output / data_max) if data_type is not None: if data_type == uint16 and not images.dtype == uint16: images.data = images.data.astype(uint16) elif data_type == float32 and not images.dtype == float32: images.data = images.data.astype(float32) return images
[docs] @staticmethod def filter_single_image(image: ndarray, min_input: float, max_input: float, max_output: float, data_type=float32) -> np.ndarray: np.clip(image, min_input, max_input, out=image) image -= min_input data_max = nanmax(image) image *= (max_output / data_max) if data_type == float32: return image.astype(float32) elif data_type == uint16: return image.astype(uint16) else: raise ValueError("Only float32 and int16 data types are supported by single image rescale")
[docs] @staticmethod def register_gui(form, on_change, view: FiltersWindowView) -> Dict[str, Any]: from mantidimaging.gui.utility import add_property_to_form _, min_input_widget = add_property_to_form('Min input', Type.FLOAT, form=form, on_change=on_change, valid_values=(-2147483647, 2147483647), tooltip="Minimum value of the data that will be used.\n" "Anything below this will be clipped to 0") min_input_widget.setDecimals(8) _, max_input_widget = add_property_to_form('Max input', Type.FLOAT, form=form, on_change=on_change, default_value=5.0, valid_values=(-2147483647, 2147483647), tooltip="Maximum value of the data that will be used.\n" "Anything above it will be clipped to 0") max_input_widget.setDecimals(8) _, max_output_widget = add_property_to_form('Max output', Type.FLOAT, form=form, on_change=on_change, default_value=65535.0, valid_values=(1, 2147483647), tooltip="Maximum value of the OUTPUT images. They will \n" "be rescaled to range [0, MAX OUTPUT]") max_output_widget.setDecimals(8) _, preset_widget = add_property_to_form('Preset', Type.CHOICE, form=form, on_change=on_change, valid_values=["Use values from above", "int8", "int16", "int32"], tooltip="Provides pre-set ranges to rescale to.") return { 'min_input_widget': min_input_widget, 'max_input_widget': max_input_widget, 'max_output_widget': max_output_widget, 'preset_widget': preset_widget }
[docs] @staticmethod def execute_wrapper( # type: ignore min_input_widget: QDoubleSpinBox, max_input_widget: QDoubleSpinBox, max_output_widget: QDoubleSpinBox, preset_widget: QComboBox) -> partial: min_input = min_input_widget.value() max_input = max_input_widget.value() max_output = max_output_widget.value() if preset_widget.currentText() == "int8": max_output = 255.0 elif preset_widget.currentText() == "int16": max_output = 65535.0 elif preset_widget.currentText() == "int32": max_output = 2147483647.0 return partial(RescaleFilter.filter_func, min_input=min_input, max_input=max_input, max_output=max_output)
[docs] @staticmethod def validate_execute_kwargs(kwargs: Dict[str, Any]) -> bool: return True