-
Notifications
You must be signed in to change notification settings - Fork 106
/
Copy pathconjugate_gradient_tomography.py
59 lines (39 loc) · 1.68 KB
/
conjugate_gradient_tomography.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
"""Tomography using the `conjugate_gradient_normal` solver.
Solves the inverse problem
A(x) = g
Where ``A`` is a parallel beam forward projector, ``x`` the result and
``g`` is given noisy data.
"""
import numpy as np
import odl
# --- Set up the forward operator (ray transform) --- #
# Reconstruction space: discretized functions on the rectangle
# [-20, 20]^2 with 300 samples per dimension.
reco_space = odl.uniform_discr(
min_pt=[-20, -20], max_pt=[20, 20], shape=[300, 300], dtype='float32')
# Make a parallel beam geometry with flat detector
# Angles: uniformly spaced, n = 360, min = 0, max = pi
angle_partition = odl.uniform_partition(0, np.pi, 360)
# Detector: uniformly sampled, n = 300, min = -30, max = 30
detector_partition = odl.uniform_partition(-30, 30, 300)
geometry = odl.tomo.Parallel2dGeometry(angle_partition, detector_partition)
# Create the forward operator
ray_trafo = odl.tomo.RayTransform(reco_space, geometry)
# --- Generate artificial data --- #
# Create phantom
discr_phantom = odl.phantom.shepp_logan(reco_space, modified=True)
# Create sinogram of forward projected phantom with noise
data = ray_trafo(discr_phantom)
data += odl.phantom.white_noise(ray_trafo.range) * np.mean(data) * 0.1
# Optionally pass callback to the solver to display intermediate results
callback = (odl.solvers.CallbackPrintIteration() &
odl.solvers.CallbackShow())
# Choose a starting point
x = ray_trafo.domain.zero()
# Run the algorithm
odl.solvers.conjugate_gradient_normal(
ray_trafo, x, data, niter=20, callback=callback)
# Display images
discr_phantom.show(title='Original Image')
data.show(title='Sinogram')
x.show(title='Reconstructed Image', force_show=True)