Skip to content

Commit

Permalink
deploy: 00d18ae
Browse files Browse the repository at this point in the history
  • Loading branch information
gschramm committed Nov 14, 2024
1 parent 68a4428 commit 0ce15ec
Show file tree
Hide file tree
Showing 337 changed files with 69,523 additions and 0 deletions.
4 changes: 4 additions & 0 deletions pr-98/.buildinfo
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Sphinx build info version 1
# This file records the configuration used when building these files. When it is not found, a full rebuild will be done.
config: f890332ff33e9a7902f7376252864dd5
tags: 645f666f9bcd5a90fca523b33c5a78b7
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file added pr-98/.doctrees/auto_examples/index.doctree
Binary file not shown.
Binary file not shown.
Binary file added pr-98/.doctrees/cuda_kernels.doctree
Binary file not shown.
Binary file added pr-98/.doctrees/environment.pickle
Binary file not shown.
Binary file added pr-98/.doctrees/index.doctree
Binary file not shown.
Binary file added pr-98/.doctrees/installation.doctree
Binary file not shown.
Binary file added pr-98/.doctrees/libparallelproj_c.doctree
Binary file not shown.
Binary file added pr-98/.doctrees/libparallelproj_cuda.doctree
Binary file not shown.
Binary file added pr-98/.doctrees/python_api.doctree
Binary file not shown.
Binary file added pr-98/.doctrees/sg_execution_times.doctree
Binary file not shown.
Binary file not shown.
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
"""
PET non-TOF listmode projector
==============================
In this example we will show how to setup and use a non-TOF
PET listmode projector including geometrical forward projection
in listmode, image-based resolution model and a listmode
attenuation model.
.. tip::
parallelproj is python array API compatible meaning it supports different
array backends (e.g. numpy, cupy, torch, ...) and devices (CPU or GPU).
Choose your preferred array API ``xp`` and device ``dev`` below.
.. image:: https://mybinder.org/badge_logo.svg
:target: https://mybinder.org/v2/gh/gschramm/parallelproj/master?labpath=examples
"""

# %%
import array_api_compat.numpy as xp

# import array_api_compat.cupy as xp
# import array_api_compat.torch as xp

import parallelproj
from array_api_compat import to_device
import array_api_compat.numpy as np
import matplotlib.pyplot as plt

# choose a device (CPU or CUDA GPU)
if "numpy" in xp.__name__:
# using numpy, device must be cpu
dev = "cpu"
elif "cupy" in xp.__name__:
# using cupy, only cuda devices are possible
dev = xp.cuda.Device(0)
elif "torch" in xp.__name__:
# using torch valid choices are 'cpu' or 'cuda'
dev = "cuda"

# %%
# Setup a small regular polygon PET scanner with 5 rings (polygons)
# -----------------------------------------------------------------

num_rings = 4
scanner = parallelproj.RegularPolygonPETScannerGeometry(
xp,
dev,
radius=65.0,
num_sides=12,
num_lor_endpoints_per_side=15,
lor_spacing=2.3,
ring_positions=xp.linspace(-10, 10, num_rings),
symmetry_axis=1,
)

# %%
# Generate 4 arbitrary listmode events
# ------------------------------------

start_ring = xp.asarray([2, 1, 0, 3], device=dev)
start_xtal = xp.asarray([0, 59, 143, 75], device=dev)

end_ring = xp.asarray([2, 0, 1, 3], device=dev)
end_xtal = xp.asarray([79, 140, 33, 147], device=dev)

event_start_coordinates = scanner.get_lor_endpoints(start_ring, start_xtal)
event_end_coordinates = scanner.get_lor_endpoints(end_ring, end_xtal)

print(event_start_coordinates)
print(event_end_coordinates)

# %%
# Show the scanner geometry and the events
# ----------------------------------------

fig = plt.figure(figsize=(8, 8))
ax = fig.add_subplot(111, projection="3d")
scanner.show_lor_endpoints(ax)
for i in range(event_start_coordinates.shape[0]):
ax.plot(
[float(event_start_coordinates[i, 0]), float(event_end_coordinates[i, 0])],
[float(event_start_coordinates[i, 1]), float(event_end_coordinates[i, 1])],
[float(event_start_coordinates[i, 2]), float(event_end_coordinates[i, 2])],
)
fig.tight_layout()
fig.show()


# %%
# Setup a listmode projector and a test image
# -------------------------------------------

img_shape = (40, 9, 40)
voxel_size = (2.0, 3.0, 2.0)

lm_proj = parallelproj.ListmodePETProjector(
event_start_coordinates, event_end_coordinates, img_shape, voxel_size
)

x = xp.ones(img_shape, dtype=xp.float32, device=dev)

# %%
# Perform listmode forward and back projections
# ---------------------------------------------

x_fwd = lm_proj(x)
print(x_fwd)

# back project a list of ones
ones_list = xp.ones(lm_proj.num_events, dtype=xp.float32, device=dev)
y_back = lm_proj.adjoint(ones_list)

# %%
# Show the backprojected list of ones (events)
# --------------------------------------------

fig2, ax2 = plt.subplots(3, 3, figsize=(8, 8))
vmax = float(xp.max(y_back))
for i in range(ax2.size):
if i < y_back.shape[1]:
axx = ax2.ravel()[i]
axx.imshow(
parallelproj.to_numpy_array(y_back[:, i, :].T),
cmap="Greys",
vmin=0,
vmax=vmax,
)
axx.set_title(f"img plane {i}", fontsize="medium")
else:
ax2.ravel()[i].set_axis_off()
fig2.tight_layout()
fig2.show()

# %%
# Combine the listmode projector with a resolution and attenuation model
# ----------------------------------------------------------------------

# setup a simple image-based resolution model with an Gaussian FWHM of 4.5mm
res_model = parallelproj.GaussianFilterOperator(
lm_proj.in_shape, sigma=4.5 / (2.35 * lm_proj.voxel_size)
)

# define arbritrary attenuation factors
att_list = xp.asarray([0.3, 0.4, 0.2, 0.6], device=dev)
att_op = parallelproj.ElementwiseMultiplicationOperator(att_list)


lm_proj_with_res_model_and_att = parallelproj.CompositeLinearOperator(
(att_op, lm_proj, res_model)
)

x_fwd2 = lm_proj_with_res_model_and_att(x)
print(x_fwd2)

y_back2 = lm_proj_with_res_model_and_att.adjoint(ones_list)

# %%
# Show the backprojected list of ones (events)
# --------------------------------------------

fig3, ax3 = plt.subplots(3, 3, figsize=(8, 8))
vmax = float(xp.max(y_back2))
for i in range(ax3.size):
if i < y_back.shape[1]:
axx = ax3.ravel()[i]
axx.imshow(
parallelproj.to_numpy_array(y_back2[:, i, :].T),
cmap="Greys",
vmin=0,
vmax=vmax,
)
axx.set_title(f"img plane {i}", fontsize="medium")
else:
ax3.ravel()[i].set_axis_off()
fig3.tight_layout()
fig3.show()
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n# PET non-TOF listmode projector\n\nIn this example we will show how to setup and use a non-TOF \nPET listmode projector including geometrical forward projection\nin listmode, image-based resolution model and a listmode \nattenuation model.\n\n.. tip::\n parallelproj is python array API compatible meaning it supports different \n array backends (e.g. numpy, cupy, torch, ...) and devices (CPU or GPU).\n Choose your preferred array API ``xp`` and device ``dev`` below.\n\n<img src=\"https://mybinder.org/badge_logo.svg\" target=\"https://mybinder.org/v2/gh/gschramm/parallelproj/master?labpath=examples\">\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"import array_api_compat.numpy as xp\n\n# import array_api_compat.cupy as xp\n# import array_api_compat.torch as xp\n\nimport parallelproj\nfrom array_api_compat import to_device\nimport array_api_compat.numpy as np\nimport matplotlib.pyplot as plt\n\n# choose a device (CPU or CUDA GPU)\nif \"numpy\" in xp.__name__:\n # using numpy, device must be cpu\n dev = \"cpu\"\nelif \"cupy\" in xp.__name__:\n # using cupy, only cuda devices are possible\n dev = xp.cuda.Device(0)\nelif \"torch\" in xp.__name__:\n # using torch valid choices are 'cpu' or 'cuda'\n dev = \"cuda\""
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Setup a small regular polygon PET scanner with 5 rings (polygons)\n\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"num_rings = 4\nscanner = parallelproj.RegularPolygonPETScannerGeometry(\n xp,\n dev,\n radius=65.0,\n num_sides=12,\n num_lor_endpoints_per_side=15,\n lor_spacing=2.3,\n ring_positions=xp.linspace(-10, 10, num_rings),\n symmetry_axis=1,\n)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Generate 4 arbitrary listmode events\n\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"start_ring = xp.asarray([2, 1, 0, 3], device=dev)\nstart_xtal = xp.asarray([0, 59, 143, 75], device=dev)\n\nend_ring = xp.asarray([2, 0, 1, 3], device=dev)\nend_xtal = xp.asarray([79, 140, 33, 147], device=dev)\n\nevent_start_coordinates = scanner.get_lor_endpoints(start_ring, start_xtal)\nevent_end_coordinates = scanner.get_lor_endpoints(end_ring, end_xtal)\n\nprint(event_start_coordinates)\nprint(event_end_coordinates)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Show the scanner geometry and the events\n\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"fig = plt.figure(figsize=(8, 8))\nax = fig.add_subplot(111, projection=\"3d\")\nscanner.show_lor_endpoints(ax)\nfor i in range(event_start_coordinates.shape[0]):\n ax.plot(\n [float(event_start_coordinates[i, 0]), float(event_end_coordinates[i, 0])],\n [float(event_start_coordinates[i, 1]), float(event_end_coordinates[i, 1])],\n [float(event_start_coordinates[i, 2]), float(event_end_coordinates[i, 2])],\n )\nfig.tight_layout()\nfig.show()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Setup a listmode projector and a test image\n\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"img_shape = (40, 9, 40)\nvoxel_size = (2.0, 3.0, 2.0)\n\nlm_proj = parallelproj.ListmodePETProjector(\n event_start_coordinates, event_end_coordinates, img_shape, voxel_size\n)\n\nx = xp.ones(img_shape, dtype=xp.float32, device=dev)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Perform listmode forward and back projections\n\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"x_fwd = lm_proj(x)\nprint(x_fwd)\n\n# back project a list of ones\nones_list = xp.ones(lm_proj.num_events, dtype=xp.float32, device=dev)\ny_back = lm_proj.adjoint(ones_list)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Show the backprojected list of ones (events)\n\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"fig2, ax2 = plt.subplots(3, 3, figsize=(8, 8))\nvmax = float(xp.max(y_back))\nfor i in range(ax2.size):\n if i < y_back.shape[1]:\n axx = ax2.ravel()[i]\n axx.imshow(\n parallelproj.to_numpy_array(y_back[:, i, :].T),\n cmap=\"Greys\",\n vmin=0,\n vmax=vmax,\n )\n axx.set_title(f\"img plane {i}\", fontsize=\"medium\")\n else:\n ax2.ravel()[i].set_axis_off()\nfig2.tight_layout()\nfig2.show()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Combine the listmode projector with a resolution and attenuation model\n\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"# setup a simple image-based resolution model with an Gaussian FWHM of 4.5mm\nres_model = parallelproj.GaussianFilterOperator(\n lm_proj.in_shape, sigma=4.5 / (2.35 * lm_proj.voxel_size)\n)\n\n# define arbritrary attenuation factors\natt_list = xp.asarray([0.3, 0.4, 0.2, 0.6], device=dev)\natt_op = parallelproj.ElementwiseMultiplicationOperator(att_list)\n\n\nlm_proj_with_res_model_and_att = parallelproj.CompositeLinearOperator(\n (att_op, lm_proj, res_model)\n)\n\nx_fwd2 = lm_proj_with_res_model_and_att(x)\nprint(x_fwd2)\n\ny_back2 = lm_proj_with_res_model_and_att.adjoint(ones_list)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Show the backprojected list of ones (events)\n\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"fig3, ax3 = plt.subplots(3, 3, figsize=(8, 8))\nvmax = float(xp.max(y_back2))\nfor i in range(ax3.size):\n if i < y_back.shape[1]:\n axx = ax3.ravel()[i]\n axx.imshow(\n parallelproj.to_numpy_array(y_back2[:, i, :].T),\n cmap=\"Greys\",\n vmin=0,\n vmax=vmax,\n )\n axx.set_title(f\"img plane {i}\", fontsize=\"medium\")\n else:\n ax3.ravel()[i].set_axis_off()\nfig3.tight_layout()\nfig3.show()"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.12.7"
}
},
"nbformat": 4,
"nbformat_minor": 0
}
Loading

0 comments on commit 0ce15ec

Please sign in to comment.