Source code for blissoda.tomo.utils
import logging
from enum import IntEnum
from typing import Tuple
import numpy as np
from blissoda.bliss_globals import current_session
from blissoda.import_utils import unavailable_class
from blissoda.import_utils import unavailable_function
from blissoda.import_utils import unavailable_module
try:
from bliss.physics import units
from flint.viewers.custom_image.client import ImageView
from tomo.globals import get_active_tomo_config
except ImportError as ex:
units = unavailable_module(ex)
get_active_tomo_config = unavailable_function(ex)
ImageView = unavailable_class(ex)
logger = logging.getLogger(__name__)
[docs]
def calculate_CoR_estimate(
pixel_size_mm: float,
translation_y_mm: float,
detector_width: int,
offset_mm: float,
) -> float:
"""
Estimate the center of rotation for tomographic reconstruction.
"""
# The -0.5 accounts for pixel-center coordinate convention used by the reconstruction algorithm
default_center = detector_width / 2 - 0.5
# This tells us how many pixels the center of rotation has shifted
pixel_shift = (translation_y_mm - offset_mm) / pixel_size_mm
return default_center + pixel_shift
[docs]
def calculate_relative_CoR_estimate(
pixel_size_mm: float,
translation_y_mm: float,
offset_mm: float,
) -> float:
"""
Estimate the relative center of rotation for tomographic reconstruction.
"""
# This tells us how many pixels the center of rotation has shifted
pixel_shift = (translation_y_mm - offset_mm) / pixel_size_mm
return pixel_shift
[docs]
class ImageKey(IntEnum):
PROJECTION = 0
DARK_FIELD = 2
FLAT_FIELD = 1
INVALID = 3
[docs]
def compute_axes(image: np.ndarray) -> Tuple[np.ndarray, np.ndarray]:
"""
Compute physical axes from sample config; fallback to pixel indices.
Converts pixel_size (um) to axis units defined by cfg.sample_x_axis.unit
and cfg.sample_y_axis.unit.
Parameters
----------
image : np.ndarray
The image array (for shape information)
Returns
-------
tuple of np.ndarray
x_axis and y_axis arrays in physical units
"""
tomo_config = get_active_tomo_config()
pixel_size_um = tomo_config.detectors.active_detector.sample_pixel_size
# Determine units for x and y axes
unit_x = getattr(tomo_config.sample_x_axis, "unit", "mm")
unit_y = getattr(tomo_config.sample_y_axis, "unit", "mm")
# Conversion factors from micrometers to axis units
conv = {"um": 1.0, "mm": 1e-3}
if unit_x not in conv:
logger.warning("Unknown unit '%s' for sample_x_axis, assuming 'mm'", unit_x)
if unit_y not in conv:
logger.warning("Unknown unit '%s' for sample_y_axis, assuming 'mm'", unit_y)
# Convert pixel size to axis units
ps_x = pixel_size_um * conv.get(unit_x, 0.001)
ps_y = pixel_size_um * conv.get(unit_y, 0.001)
rows, cols = image.shape[-2:]
# Center positions are already in axis units
cx = tomo_config.sample_x_axis.position
cy = tomo_config.sample_y_axis.position
half_w = (cols * ps_x) / 2
half_h = (rows * ps_y) / 2
x_axis = np.linspace(cx - half_w, cx + half_w, cols)
y_axis = np.linspace(cy - half_h, cy + half_h, rows)
return x_axis, y_axis
[docs]
def apply_labels(widget: ImageView) -> None:
"""
Apply axis labels from tomo config.
Parameters
----------
widget : ImageView
The plot widget
"""
tomo_config = get_active_tomo_config()
widget.xlabel = tomo_config.sample_y.name
widget.ylabel = tomo_config.sample_x.name