Source code for pytomography.metadata.CT.ct_gen3_metadata

from __future__ import annotations
import torch
from pytomography.metadata import ProjMeta

[docs]class CTGen3ProjMeta(ProjMeta): def __init__( self, source_phis: torch.Tensor, source_rhos: torch.Tensor, source_zs: torch.Tensor, source_phi_offsets: torch.Tensor, source_rho_offsets: torch.Tensor, source_z_offsets: torch.Tensor, detector_centers_col_idx: float, detector_centers_row_idx: float, col_det_spacing: float, row_det_spacing: float, DSD: float, shape: tuple ) -> None: r"""Metadata for 3rd generation clinical CT scanners. For more information, see the DICOM-CT-PD user manual in the PyTomography tutorial files. Currently only supports cylindrical detectors. Args: source_phis (torch.Tensor): Angle of detectors in cylindrical coordinates source_rhos (torch.Tensor): Radius of detectors in cylindrical coordinates source_zs (torch.Tensor): Z coordinate of detectors (cylindrical coordinates) source_phi_offsets (torch.Tensor): :math:`\phi` offset if flying focal spot used source_rho_offsets (torch.Tensor): :math:`\rho` offset if flying focal spot used source_z_offsets (torch.Tensor): :math:`z` offset if flying focal spot used detector_centers_col_idx (float): Detector element (in column) that aligns with detectors focal center and isocenter detector_centers_row_idx (float): Detector element (in row) that aligns with detectors focal center and isocenter col_det_spacing (float): Spacing between columns of detector data (in mm) row_det_spacing (float): Spacing between rows of detector data (in mm) DSD (float): Distance between focal spot and detector center. shape (tuple): Shape of projection data """ self.source_phis = source_phis self.source_rhos = source_rhos self.source_zs = source_zs # make (0,0,0) at center self.source_zs -= self.source_zs.mean() self.source_phi_offsets = source_phi_offsets self.source_z_offsets = source_z_offsets self.source_rho_offsets = source_rho_offsets self.detector_centers_col_idx = detector_centers_col_idx self.detector_centers_row_idx = detector_centers_row_idx self.col_det_spacing = col_det_spacing self.row_det_spacing = row_det_spacing self.N_angles = len(self.source_phis) self.DSD = DSD self.shape = shape # Reorient for DICOM system self.source_zs = - self.source_zs self.source_z_offsets = - self.source_z_offsets self.source_phis -= torch.pi/2 # Compute things that are required self.source_focal_centers = torch.stack([ self.source_rhos*torch.cos(self.source_phis), self.source_rhos*torch.sin(self.source_phis), self.source_zs ], dim=-1) self.source_focal_spots = torch.stack([ (self.source_rhos+self.source_rho_offsets)*torch.cos((self.source_phis+self.source_phi_offsets)), (self.source_rhos+self.source_rho_offsets)*torch.sin((self.source_phis+self.source_phi_offsets)), self.source_zs + self.source_z_offsets ], dim=-1) phis_det = (torch.arange(1,shape[0]+1) - detector_centers_col_idx[0]) * col_det_spacing zs_det = (torch.arange(1,shape[1]+1) - detector_centers_row_idx[0]) * row_det_spacing #zs_det = torch.flip(zs_det, dims=(0,)) self.phis_det, self.zs_det = torch.meshgrid(phis_det, zs_det, indexing='ij')
[docs] def get_detector_coordinates(self, idxs: torch.Tensor[int]) -> torch.Tensor: """Obtain detector coordinates and the angles corresponding to idxs Args: idxs (torch.Tensor[int]): Angle indices Returns: torch.Tensor: Detector coordinates (in XYZ) at all angle indices. """ return torch.stack([ -self.DSD*torch.cos(self.source_phis[idxs][:,None,None] + self.phis_det[None]), -self.DSD*torch.sin(self.source_phis[idxs][:,None,None] + self.phis_det[None]), 0*self.source_zs[idxs][:,None,None] + self.zs_det[None] ], dim=-1) + self.source_focal_centers[idxs,None,None]