Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for 3D tomographic projection with astra #427

Merged
merged 17 commits into from
Jul 11, 2023
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/test_examples.yml
Original file line number Diff line number Diff line change
Expand Up @@ -69,4 +69,4 @@ jobs:
# Run example test
- name: Run example test
run: |
${GITHUB_WORKSPACE}/examples/scriptcheck.sh -e -d -t
${GITHUB_WORKSPACE}/examples/scriptcheck.sh -e -d -t -g
2 changes: 1 addition & 1 deletion data
3 changes: 3 additions & 0 deletions docs/source/examples.rst
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ Computed Tomography
examples/ct_abel_tv_admm_tune
examples/ct_astra_noreg_pcg
examples/ct_astra_tv_admm
examples/ct_astra_3d_tv_admm
examples/ct_astra_weighted_tv_admm
examples/ct_svmbir_tv_multi
examples/ct_svmbir_ppp_bm3d_admm_cg
Expand Down Expand Up @@ -126,6 +127,7 @@ Total Variation
examples/ct_abel_tv_admm
examples/ct_abel_tv_admm_tune
examples/ct_astra_tv_admm
examples/ct_astra_3d_tv_admm
examples/ct_astra_weighted_tv_admm
examples/ct_svmbir_tv_multi
examples/deconv_circ_tv_admm
Expand Down Expand Up @@ -193,6 +195,7 @@ ADMM
examples/ct_abel_tv_admm
examples/ct_abel_tv_admm_tune
examples/ct_astra_tv_admm
examples/ct_astra_3d_tv_admm
examples/ct_astra_weighted_tv_admm
examples/ct_svmbir_tv_multi
examples/ct_svmbir_ppp_bm3d_admm_cg
Expand Down
13 changes: 10 additions & 3 deletions examples/scriptcheck.sh
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,22 @@ Usage: $SCRIPT [-h] [-d]
[-e] Display excerpt of error message on failure
[-d] Skip tests involving additional data downloads
[-t] Skip tests related to learned model training
[-g] Skip tests that need the GPU
Michael-T-McCann marked this conversation as resolved.
Show resolved Hide resolved
EOF
)

OPTIND=1
DISPLAY_ERROR=0
SKIP_DOWNLOAD=0
SKIP_TRAINING=0
while getopts ":hedt" opt; do
SKIP_GPU=0
while getopts ":hedtg" opt; do
case $opt in
h) echo "$USAGE"; exit 0;;
e) DISPLAY_ERROR=1;;
d) SKIP_DOWNLOAD=1;;
t) SKIP_TRAINING=1;;
g) SKIP_GPU=1;;
\?) echo "Error: invalid option -$OPTARG" >&2
echo "$USAGE" >&2
exit 1
Expand Down Expand Up @@ -74,15 +77,19 @@ for f in $SCRIPTPATH/scripts/*.py; do

# Skip problem cases.
if [ $SKIP_DOWNLOAD -eq 1 ] && grep -q '_microscopy' <<< $f; then
printf "%s\n" skipped
continue
printf "%s\n" skipped
Michael-T-McCann marked this conversation as resolved.
Show resolved Hide resolved
continue
fi
if [ $SKIP_TRAINING -eq 1 ]; then
if grep -q '_datagen' <<< $f || grep -q '_train' <<< $f; then
printf "%s\n" skipped
continue
fi
fi
if [ $SKIP_GPU -eq 1 ] && grep -q '_astra_3d' <<< $f; then
printf "%s\n" skipped
continue
fi

# Create temporary copy of script with all algorithm maxiter values set
# to small number and final input statements commented out.
Expand Down
131 changes: 131 additions & 0 deletions examples/scripts/ct_astra_3d_tv_admm.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# This file is part of the SCICO package. Details of the copyright
# and user license can be found in the 'LICENSE.txt' file distributed
# with the package.

r"""
3D TV-Regularized Sparse-View CT Reconstruction
============================================
Michael-T-McCann marked this conversation as resolved.
Show resolved Hide resolved

This example demonstrates solution of a sparse-view CT reconstruction
Michael-T-McCann marked this conversation as resolved.
Show resolved Hide resolved
problem with isotropic total variation (TV) regularization

$$\mathrm{argmin}_{\mathbf{x}} \; (1/2) \| \mathbf{y} - A \mathbf{x}
\|_2^2 + \lambda \| C \mathbf{x} \|_{2,1} \;,$$

where $A$ is the Radon transform, $\mathbf{y}$ is the sinogram, $C$ is
a 3D finite difference operator, and $\mathbf{x}$ is the desired
image.
"""

import numpy as np

import jax

from mpl_toolkits.axes_grid1 import make_axes_locatable

from scico import functional, linop, loss, metric, plot
from scico.linop.radon_astra import TomographicProjector
from scico.optimize.admm import ADMM, LinearSubproblemSolver
from scico.util import device_info


def make_tangle(nx, ny, nz):
Michael-T-McCann marked this conversation as resolved.
Show resolved Hide resolved
xs = 1.0 * np.linspace(-1.0, 1.0, nx)
ys = 1.0 * np.linspace(-1.0, 1.0, ny)
zs = 1.0 * np.linspace(-1.0, 1.0, nz)

# default ordering for meshgrid is `xy`, this makes inputs of length
# M, N, P will create a mesh of N, M, P. Thus we want ys, zs and xs.
xx, yy, zz = np.meshgrid(ys, zs, xs, copy=True)
xx = 3.0 * xx
yy = 3.0 * yy
zz = 3.0 * zz
values = (
xx * xx * xx * xx
- 5.0 * xx * xx
+ yy * yy * yy * yy
- 5.0 * yy * yy
+ zz * zz * zz * zz
- 5.0 * zz * zz
+ 11.8
) * 0.2 + 0.5
return values


Nx = 128
Ny = 256
Nz = 64

tangle = (make_tangle(Nx, Ny, Nz) < 2.0).astype(float)
tangle = jax.device_put(tangle)

n_projection = 10 # number of projections
angles = np.linspace(0, np.pi, n_projection) # evenly spaced projection angles
A = TomographicProjector(
tangle.shape, [1.0, 1.0], [Nz, max(Nx, Ny)], angles
) # Radon transform operator
y = A @ tangle # sinogram


"""
Set up ADMM solver object.
"""
λ = 2e0 # L1 norm regularization parameter
ρ = 5e0 # ADMM penalty parameter
maxiter = 25 # number of ADMM iterations
cg_tol = 1e-4 # CG relative tolerance
cg_maxiter = 25 # maximum CG iterations per ADMM iteration

# The append=0 option makes the results of horizontal and vertical
# finite differences the same shape, which is required for the L21Norm,
# which is used so that g(Cx) corresponds to isotropic TV.
C = linop.FiniteDifference(input_shape=tangle.shape, append=0)
g = λ * functional.L21Norm()

f = loss.SquaredL2Loss(y=y, A=A)

x0 = A.T(y)

solver = ADMM(
f=f,
g_list=[g],
C_list=[C],
rho_list=[ρ],
x0=x0,
maxiter=maxiter,
subproblem_solver=LinearSubproblemSolver(cg_kwargs={"tol": cg_tol, "maxiter": cg_maxiter}),
itstat_options={"display": True, "period": 5},
)

"""
Run the solver.
"""
print(f"Solving on {device_info()}\n")
solver.solve()
hist = solver.itstat_object.history(transpose=True)
tangle_recon = solver.x

print(
"TV Restruction\nSNR: %.2f (dB), MAE: %.3f"
% (metric.snr(tangle, tangle_recon), metric.mae(tangle, tangle_recon))
)

"""
Show the recovered image.
"""
fig, ax = plot.subplots(nrows=1, ncols=2, figsize=(7, 5))
plot.imview(tangle[32], title="Ground truth (central slice)", cbar=None, fig=fig, ax=ax[0])

plot.imview(
tangle_recon[32],
title="TV Reconstruction (central slice)\nSNR: %.2f (dB), MAE: %.3f"
% (metric.snr(tangle, tangle_recon), metric.mae(tangle, tangle_recon)),
fig=fig,
ax=ax[1],
)
divider = make_axes_locatable(ax[1])
cax = divider.append_axes("right", size="5%", pad=0.2)
fig.colorbar(ax[1].get_images()[0], cax=cax, label="arbitrary units")
fig.show()
3 changes: 3 additions & 0 deletions examples/scripts/index.rst
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new example has been added to the main index file, but I don't see it in the built docs. Perhaps you still need to run makeindex.py and commit the changed secondary index files?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I did this, but it's still not showing up as far as I can tell. Any suggestions?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps a problem with the submodule commit attached to this branch. When the submodule changes in a PR, it's usually cleanest to make a corresponding branch and PR for scico-data, with the submodule here linked to the head of that branch.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, the generated notebook was blank and sphinx was smart enough to not include it. Working on a fix.

Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ Computed Tomography
- ct_abel_tv_admm.py
- ct_abel_tv_admm_tune.py
- ct_astra_noreg_pcg.py
- ct_astra_3d_tv_admm.py
- ct_astra_tv_admm.py
- ct_astra_weighted_tv_admm.py
- ct_svmbir_tv_multi.py
Expand Down Expand Up @@ -95,6 +96,7 @@ Total Variation
- ct_abel_tv_admm.py
- ct_abel_tv_admm_tune.py
- ct_astra_tv_admm.py
- ct_astra_3d_tv_admm.py
- ct_astra_weighted_tv_admm.py
- ct_svmbir_tv_multi.py
- deconv_circ_tv_admm.py
Expand Down Expand Up @@ -150,6 +152,7 @@ ADMM
- ct_abel_tv_admm.py
- ct_abel_tv_admm_tune.py
- ct_astra_tv_admm.py
- ct_astra_3d_tv_admm.py
- ct_astra_weighted_tv_admm.py
- ct_svmbir_tv_multi.py
- ct_svmbir_ppp_bm3d_admm_cg.py
Expand Down
Loading
Loading