Source code for mantidimaging.core.reconstruct.tomopy_recon
# Copyright (C) 2024 ISIS Rutherford Appleton Laboratory UKRI
# SPDX - License - Identifier: GPL-3.0-or-later
from __future__ import annotations
from logging import getLogger
from typing import TYPE_CHECKING
import numpy as np
from mantidimaging.core.data import ImageStack
from mantidimaging.core.reconstruct.base_recon import BaseRecon
from mantidimaging.core.utility.optional_imports import safe_import
from mantidimaging.core.utility.progress_reporting import Progress
if TYPE_CHECKING:
from mantidimaging.core.utility.data_containers import ProjectionAngles, ReconstructionParameters, ScalarCoR
LOG = getLogger(__name__)
tomopy = safe_import('tomopy')
[docs]
class TomopyRecon(BaseRecon):
[docs]
@staticmethod
def find_cor(images: ImageStack, slice_idx: int, start_cor: float, recon_params: ReconstructionParameters) -> float:
sino = np.maximum(images.sinograms[slice_idx:slice_idx + 1], 1e-6)
sino = BaseRecon.prepare_sinogram(sino, recon_params)
return tomopy.find_center(sino,
images.projection_angles(recon_params.max_projection_angle).value,
ind=0,
init=start_cor,
sinogram_order=True)
[docs]
@staticmethod
def single_sino(sino: np.ndarray,
cor: ScalarCoR,
proj_angles: ProjectionAngles,
recon_params: ReconstructionParameters,
progress: Progress | None = None) -> np.ndarray:
sino = BaseRecon.prepare_sinogram(sino, recon_params)
volume = tomopy.recon(tomo=[sino],
sinogram_order=True,
theta=proj_angles.value,
center=cor.value,
algorithm=recon_params.algorithm,
filter_name=recon_params.filter_name)
return volume[0]
[docs]
@staticmethod
def full(images: ImageStack,
cors: list[ScalarCoR],
recon_params: ReconstructionParameters,
progress: Progress | None = None):
"""
Performs a volume reconstruction using sample data provided as sinograms.
:param images: Array of sinogram images
:param cors: Array of centre of rotation values
:param proj_angles: Array of projection angles
:param recon_params: Reconstruction Parameters
:param progress: Optional progress reporter
:return: 3D image data for reconstructed volume
"""
progress = Progress.ensure_instance(progress, task_name='TomoPy reconstruction')
import multiprocessing
ncores = multiprocessing.cpu_count()
kwargs = {
'ncore': ncores,
'tomo': BaseRecon.prepare_sinogram(images.data, recon_params),
'sinogram_order': images._is_sinograms,
'theta': images.projection_angles(recon_params.max_projection_angle).value,
'center': [cor.value for cor in cors],
'algorithm': recon_params.algorithm,
'filter_name': recon_params.filter_name
}
with progress:
volume = tomopy.recon(**kwargs)
LOG.info(f'Reconstructed 3D volume with shape: {volume.shape}')
return ImageStack(volume)
[docs]
@staticmethod
def allowed_filters() -> list[str]:
return ["ramlak", 'shepp', 'cosine', 'hann', 'hamming', 'parzen', 'butterworth']
[docs]
def allowed_recon_kwargs() -> dict:
# only gridrec is used from tomopy
return {'gridrec': ['num_gridx', 'num_gridy', 'filter_name', 'filter_par']}