Source code for mantidimaging.gui.dialogs.cor_inspection.model
# Copyright (C) 2023 ISIS Rutherford Appleton Laboratory UKRI
# SPDX - License - Identifier: GPL-3.0-or-later
from __future__ import annotations
from dataclasses import replace
from logging import getLogger
from typing import Union
from mantidimaging.core.data import ImageStack
from mantidimaging.core.reconstruct import get_reconstructor_for
from mantidimaging.core.utility.data_containers import ScalarCoR, ReconstructionParameters
from .types import ImageType
LOG = getLogger(__name__)
INIT_ITERS_CENTRE_VALUE = 100
INIT_ITERS_STEP = 50
[docs]
class CORInspectionDialogModel(object):
def __init__(self, images: ImageStack, slice_idx: int, initial_cor: ScalarCoR,
recon_params: ReconstructionParameters, iters_mode: bool):
self.image_width = images.width
self.sino = images.sino(slice_idx)
# Initial parameters
if iters_mode:
self.centre_value: Union[int, float] = INIT_ITERS_CENTRE_VALUE
self.step = INIT_ITERS_STEP
self.initial_cor = initial_cor
self._recon_preview = self._recon_iters_preview
self._divide_step = self._divide_iters_step
else:
self.centre_value = initial_cor.value
self.step = self.image_width * 0.05
self._recon_preview = self._recon_cor_preview
self._divide_step = self._divide_cor_step
# Cache projection angles
self.proj_angles = images.projection_angles(recon_params.max_projection_angle)
self.recon_params = recon_params
self.reconstructor = get_reconstructor_for(recon_params.algorithm)
def _divide_iters_step(self):
self.step = self.step // 2
def _divide_cor_step(self):
self.step /= 2
[docs]
def adjust(self, image):
"""
Adjusts the rotation centre/number of iterations and step after an image is selected as the
optimal of an iteration.
"""
if image == ImageType.LESS:
self.centre_value -= self.step
elif image == ImageType.MORE:
self.centre_value += self.step
elif image == ImageType.CURRENT:
self._divide_step()
[docs]
def cor(self, image):
"""
Gets the rotation centre for a given image in the current iteration.
"""
if image == ImageType.LESS:
return max(self.cor_extents[0], self.centre_value - self.step)
elif image == ImageType.CURRENT:
return self.centre_value
elif image == ImageType.MORE:
return min(self.cor_extents[1], self.centre_value + self.step)
[docs]
def iterations(self, image):
if image == ImageType.LESS:
return max(1, self.centre_value - self.step)
elif image == ImageType.CURRENT:
return self.centre_value
elif image == ImageType.MORE:
return self.centre_value + self.step
def _recon_cor_preview(self, image):
cor = ScalarCoR(self.cor(image))
return self.reconstructor.single_sino(self.sino, cor, self.proj_angles, self.recon_params)
def _recon_iters_preview(self, image):
iters = self.iterations(image)
new_params = replace(self.recon_params, num_iter=iters)
return self.reconstructor.single_sino(self.sino, self.initial_cor, self.proj_angles, new_params)
[docs]
def recon_preview(self, image):
return self._recon_preview(image)
@property
def cor_extents(self):
return 0, self.sino.shape[1] - 1