Source code for mantidimaging.core.utility.data_containers

# Copyright (C) 2022 ISIS Rutherford Appleton Laboratory UKRI
# SPDX - License - Identifier: GPL-3.0-or-later
"""
Containers for data. They don't do much apart from storing the data,
and optionally provide helpful operations.

The biggest benefit is explicitly marking what the value represents (e.g. Degrees),
and helps the type hints to tell you that you might be passing the wrong value (e.g. ScalarCoR to a VectorCoR),
while they're both Float underneath and the value can be used, it just will produce nonsense.
"""
from collections import namedtuple
from dataclasses import dataclass
from typing import List, Optional

import numpy


[docs] @dataclass class SingleValue: __slots__ = 'value' value: float def __init__(self, value: float): assert isinstance(value, float), f"Value is not float. Actual type:{type(value)}" self.value = value def __str__(self): return f"{self.value}" def __eq__(self, other): if isinstance(other, SingleValue): return self.value == other.value else: return self == other def __abs__(self): return abs(self.value) def __sub__(self, other: 'SingleValue'): assert isinstance(other, SingleValue), "Can only compare against other `SingleValue`s" return self.value - other.value
[docs] @dataclass class ScalarCoR(SingleValue): __slots__ = 'value' value: float
[docs] def to_vec(self, detector_width): return VectorCoR(detector_width / 2 - self.value)
[docs] @dataclass class VectorCoR(SingleValue): __slots__ = 'value' value: float
[docs] def to_scalar(self, detector_width): return ScalarCoR(detector_width / 2 + self.value)
[docs] @dataclass class Degrees(SingleValue): __slots__ = 'value' value: float def __str__(self): return f"{self.value}°"
[docs] @dataclass class Slope(SingleValue): __slots__ = 'value' value: float
[docs] @dataclass class ProjectionAngles(SingleValue): __slots__ = 'value' value: numpy.ndarray
[docs] @dataclass class Counts(SingleValue): __slots__ = 'value' value: numpy.ndarray
[docs] @dataclass class Micron(SingleValue): __slots__ = 'value' value: int
[docs] @dataclass class ReconstructionParameters: algorithm: str filter_name: str num_iter: int = 1 cor: Optional[ScalarCoR] = None tilt: Optional[Degrees] = None pixel_size: float = 0.0 alpha: float = 0.0 max_projection_angle: float = 360.0 beam_hardening_coefs: Optional[List[float]] = None
[docs] def to_dict(self) -> dict: return { 'algorithm': self.algorithm, 'filter_name': self.filter_name, 'num_iter': self.num_iter, 'cor': str(self.cor), 'tilt': str(self.tilt), 'pixel_size': self.pixel_size, 'alpha': self.alpha }
Indices = namedtuple('Indices', ['start', 'end', 'step'])
[docs] @dataclass class ImageParameters: input_path: str format: str prefix: str indices: Optional[Indices] = None log_file: Optional[str] = None
[docs] class LoadingParameters: sample: ImageParameters flat_before: Optional[ImageParameters] = None flat_after: Optional[ImageParameters] = None dark_before: Optional[ImageParameters] = None dark_after: Optional[ImageParameters] = None proj_180deg: Optional[ImageParameters] = None pixel_size: int name: str dtype: str sinograms: bool