Source code for pytomography.metadata.CT.ct_conebeam_flatpanel_metadata
from __future__ import annotations
import torch
import pytomography
from pytomography.metadata import ProjMeta
import numpy as np
[docs]class CTConeBeamFlatPanelProjMeta(ProjMeta):
def __init__(self,
angles,
z_locations,
detector_radius,
beam_radius,
shape,
dr,
COR = None
):
self.detector_radius = detector_radius
self.beam_radius = beam_radius
if COR is None:
self.COR = torch.tensor([0.,0.,0.]).to(pytomography.device).to(pytomography.dtype)
else:
self.COR = torch.tensor([0.,-COR,0.]).to(pytomography.device).to(pytomography.dtype)
self.angles = angles.to(pytomography.device).to(pytomography.dtype)
self.z_locations = z_locations.to(pytomography.device).to(pytomography.dtype)
self.detector_locations = torch.stack([
detector_radius * torch.cos(self.angles),
detector_radius * torch.sin(self.angles),
self.z_locations
], dim=-1)
self.beam_locations = torch.stack([
- beam_radius* torch.cos(self.angles),
- beam_radius*torch.sin(self.angles),
self.z_locations
], dim=-1)
self.detector_orientations = - self.detector_locations / torch.norm(self.detector_locations, dim=-1).unsqueeze(-1)
# Rotation offset
offsetx, offsety = self._get_CORs()
self.detector_locations[:,0] += offsetx
self.detector_locations[:,1] += offsety
self.beam_locations[:,0] += offsetx
self.beam_locations[:,1] += offsety
# Other attributes
self.shape = shape
self.dr = dr
self.N_angles = len(self.detector_locations)
self.s, self.v = self._get_detector_pixel_s_v()
self.DSD = np.abs(beam_radius) + np.abs(detector_radius)
self.DSO = np.abs(beam_radius)
self.DSOs = torch.norm(self.beam_locations, dim=-1)
[docs] def _get_CORs(self):
offsetx = - self.COR[0]*torch.cos(self.angles)+self.COR[1]*torch.sin(self.angles) + self.COR[0]
offsety = - self.COR[0]*torch.sin(self.angles)-self.COR[1]*torch.cos(self.angles) + self.COR[1]
return offsetx, offsety
[docs] def _get_detector_pixel_s_v(self, device=None):
Nx, Ny = self.shape
dx, dy = self.dr
s, v = torch.meshgrid(torch.arange(-Nx/2+0.5, Nx/2+0.5, 1)*dx, torch.arange(-Ny/2+0.5, Ny/2+0.5, 1)*dy, indexing='ij')
if device is not None:
s = s.to(device)
v = v.to(device)
return s, v
[docs] def _get_detector_coordinates(self, idx):
o = self.detector_orientations[idx].cpu() # perp to detector
r = torch.tensor([o[1], -o[0], 0]) # top aligned in axial plane
p = torch.cross(o,r) # other perpendicular direction
center = self.detector_locations[idx]
return (r*self.s.unsqueeze(-1) + p*self.v.unsqueeze(-1) + center.cpu()).to(pytomography.device)