Last Time — PyTomography 0.8.0 documentation

Skip to main content
`Ctrl`+`K`

    [18]:

    import numpy as np
    import matplotlib.pyplot as plt
    import torch
    from torchvision.transforms.functional import rotate
    from pytomography.utils import rotate_detector_z
    device = torch.device("cuda" if torch.cuda.is_available() else "cpu")

# Last Time

We implemented \(g=Hf\) on an object \(f\) and for the case of a system matrix \(H\) that doesn’t model any phenomena

    [3]:

    x = torch.linspace(-1,1,128)
    xv, yv, zv = torch.meshgrid(x,x,x, indexing='ij')
    obj = (xv**2 + 0.9*zv**2 < 0.5) * (torch.abs(yv)<0.8)
    obj = obj.to(torch.float).unsqueeze(dim=0)

    angles = np.arange(0,360.,3)
    image = torch.zeros((1,len(angles),128,128))
    for i,angle in enumerate(angles):
        object_i = rotate_detector_z(obj,angle)
        image[:,i] = object_i.sum(axis=1)

    [4]:

    plt.pcolormesh(image[0,:,:,64].T)
    plt.xlabel('Angle')
    plt.ylabel('r')

    [4]:

    Text(0, 0.5, 'r')

# This Time

We’ll talk about how to model \(\hat{f} = H^T g\) for the same operator \(H\). This time, we’ll start by creating an empty object. I claim that the following implements back projection from a single angle:

    [22]:

    image[:,0].unsqueeze(dim=1).shape

    [22]:

    torch.Size([1, 1, 128, 128])

    [23]:

    bp_single_angle = torch.ones([1, 128, 128, 128]) * image[:,0].unsqueeze(dim=1)

Example: If forward projection is

\[\begin{split}\begin{bmatrix} 1&1&1&0&0&0 \\ 0&0&0&1&1&1 \end{bmatrix} \begin{bmatrix} 2 \\ 3 \\ 1 \\ 4 \\ 5 \\ 6 \end{bmatrix} = \begin{bmatrix} 6 \\ 15 \end{bmatrix}\end{split}\]

then back projection is

\[\begin{split}\begin{bmatrix} 1&0 \\ 1&0 \\1&0 \\ 0&1 \\ 0&1\\ 0&1\end{bmatrix} \begin{bmatrix} 6 \\ 15 \end{bmatrix} = \begin{bmatrix} 6 \\ 6 \\ 6 \\ 15 \\ 15 \\ 15 \end{bmatrix}\end{split}\]

So there is an element of duplication going on.

Nopw I need to back project for each angle, and rotate the coordinate system back to the original object coordinate axes, and add everything together

    [24]:

    obj_bp = torch.zeros([1, 128, 128, 128])
    for i,angle in enumerate(angles):
        bp_single_angle = torch.ones([1, 128, 128, 128]) * image[:,i].unsqueeze(dim=1)
        bp_single_angle = rotate_detector_z(bp_single_angle, angle, negative=True)
        obj_bp += bp_single_angle

Just like we did for `obj` in tutorial 1, we’ll look at different projections for `obj_bp`

    [25]:

    fig, _ = plt.subplots(1,3,figsize=(10,3))
    plt.subplot(131)
    plt.pcolormesh(x,x,obj_bp[0].sum(axis=0).T, cmap='Greys_r')
    plt.xlabel('y')
    plt.ylabel('z')
    plt.title('Coronal')
    plt.subplot(132)
    plt.pcolormesh(x,x,obj_bp[0].sum(axis=1).T, cmap='Greys_r')
    plt.xlabel('x')
    plt.ylabel('z')
    plt.title('Sagittal')
    plt.subplot(133)
    plt.pcolormesh(obj_bp[0].sum(axis=2).T, cmap='Greys_r')
    plt.xlabel('x')
    plt.ylabel('y')
    plt.title('Axial')
    fig.tight_layout()

Clearly theres some blurring going on: \(H^T g\) does not give the original object \(f\) (if it did, then our job would be easy, and there’d be no need for reconstruction algorithms).