Source code for pytomography.io.SPECT.shared

from __future__ import annotations
from collections.abc import Sequence
import torch
from torch.nn.functional import avg_pool2d, avg_pool3d
from pytomography.metadata.SPECT import SPECTObjectMeta, SPECTProjMeta

[docs]def subsample_projections( projections: torch.Tensor, N_pixel: int, N_angle: int, N_angle_start: int = 0 ) -> torch.Tensor: """Subsamples SPECT projections by averaging over N_pixel x N_pixel pixel regions and by removing certain angles Args: projections (torch.Tensor): Projections to subsample N_pixel (int): Pixel reduction factor (1 means no reduction) N_angle (int): Angle reduction factor (1 means no reduction) N_angle_start (int): Angle index to start at. Defaults to 0. Returns: torch.Tensor: Subsampled projections """ result = avg_pool2d(projections.unsqueeze(0), N_pixel).squeeze() * N_pixel**2 return result[N_angle_start::N_angle]
[docs]def subsample_metadata( object_meta: SPECTObjectMeta, proj_meta: SPECTProjMeta, N_pixel: int = 1, N_angle: int = 1, N_angle_start: int = 0 ): """Subsample SPECT metadata with the specified pixel and angle reduction factors Args: object_meta (SPECTObjectMeta): Original object metadata proj_meta (SPECTProjMeta): Original projection metadata N_pixel (int): Pixel reduction factor (1 means no reduction). Defaults to 1. N_angle (int): Angle reduction factor (1 means no reduction). Defaults to 1. N_angle_start (int): Angle index to start at. Defaults to 0. Returns: Sequence: Modified object metadata, modified projection metadata """ object_meta.dr = tuple([N_pixel*dri for dri in object_meta.dr]) object_meta.shape = tuple([int(s/N_pixel) for s in object_meta.shape]) object_meta.compute_padded_shape() object_meta.dx*=N_pixel object_meta.dy*=N_pixel object_meta.dz*=N_pixel proj_meta.dr = tuple([N_pixel*dri for dri in proj_meta.dr]) proj_meta.shape = (int(proj_meta.shape[0]/N_angle), int(proj_meta.shape[1]/N_pixel), int(proj_meta.shape[2]/N_pixel)) proj_meta.compute_padded_shape() proj_meta.radii = proj_meta.radii[N_angle_start::N_angle] proj_meta.angles = proj_meta.angles[N_angle_start::N_angle] proj_meta.num_projections = int(proj_meta.num_projections/N_angle) return object_meta, proj_meta
[docs]def subsample_projections_and_modify_metadata( object_meta: SPECTObjectMeta, proj_meta: SPECTProjMeta, projections: torch.Tensor, N_pixel: int = 1, N_angle: int = 1, N_angle_start: int = 0 ) -> Sequence[SPECTObjectMeta, SPECTProjMeta, torch.Tensor]: """Subsamples SPECT projection and modifies metadata accordingly Args: object_meta (ObjectMeta): Object metadata proj_meta (SPECTProjMeta): Projection metadata projections (torch.Tensor): Projections to subsample N_pixel (int): Pixel reduction factor (1 means no reduction). Defaults to 1. N_angle (int): Angle reduction factor (1 means no reduction). Defaults to 1. N_angle_start (int): Angle index to start at. Defaults to 0. Returns: Sequence: Modified object metadata, modified projection metadata, subsampled projections """ object_meta, proj_meta = subsample_metadata(object_meta, proj_meta, N_pixel, N_angle, N_angle_start) projections_processed = [] for projections_batch in projections: projections_batch = projections_batch projections_batch = subsample_projections(projections_batch, N_pixel, N_angle, N_angle_start) projections_processed.append(projections_batch) projections_processed = torch.stack(projections_processed, dim=0) return object_meta, proj_meta, projections_processed
[docs]def subsample_amap(amap: torch.Tensor, N: int) -> torch.Tensor: """Subsamples 3D attenuation map by averaging over N x N x N regions Args: amap (torch.Tensor): Original attenuation map N (int): Factor to reduce by Returns: torch.Tensor: Subsampled attenuation map """ return avg_pool3d(amap.unsqueeze(0).unsqueeze(0), N).squeeze()