{ "cells": [ { "cell_type": "markdown", "source": [ "# 2D sinogram geometry" ], "metadata": {} }, { "cell_type": "markdown", "source": [ "This page describes the 2D sinogram geometries\n", "available in the Julia package\n", "[`Sinograms.jl`](https://github.com/JeffFessler/Sinograms.jl).\n", "\n", "This page was generated from a single Julia file:\n", "[02-sino-geom.jl](https://github.com/JeffFessler/Sinograms.jl/blob/main/docs/lit/examples/02-sino-geom.jl)." ], "metadata": {} }, { "cell_type": "markdown", "source": [ "### Setup" ], "metadata": {} }, { "cell_type": "markdown", "source": [ "Packages needed here." ], "metadata": {} }, { "outputs": [], "cell_type": "code", "source": [ "using Unitful: mm, °\n", "using UnitfulRecipes\n", "using Plots # must precede 'using Sinograms' for sino_plot_rays to work\n", "using Sinograms: SinoPar, SinoMoj, SinoFanArc, SinoFanFlat, SinoFan\n", "using Sinograms: sino_plot_rays\n", "using MIRTjim: jim, prompt\n", "using InteractiveUtils: versioninfo" ], "metadata": {}, "execution_count": null }, { "cell_type": "markdown", "source": [ "The following line is helpful when running this example.jl file as a script;\n", "this way it will prompt user to hit a key after each figure is displayed." ], "metadata": {} }, { "outputs": [], "cell_type": "code", "source": [ "isinteractive() ? jim(:prompt, true) : prompt(:draw);" ], "metadata": {}, "execution_count": null }, { "cell_type": "markdown", "source": [ "### 2D Sinogram geometries\n", "\n", "To perform 2D image reconstruction\n", "from a 2D sinogram,\n", "one must first describe\n", "how the rays in the sinogram are sampled.\n", "\n", "Mathematically,\n", "the Radon transform $p(r,\\phi)$ of $f(x,y)$\n", "is defined for all $r$ and $ϕ$\n", "but practical systems\n", "record $p(r,ϕ)$\n", "only for certain finite sets of samples\n", "of those values.\n", "\n", "\n", "## Parallel-beam geometry\n", "\n", "The simplest form of sinogram sampling\n", "is equally spaced samples\n", "in both $r$ and $ϕ$.\n", "This sampling is called a parallel-beam geometry.\n", "(Very few practical systems have this sampling pattern,\n", "but it is an easy place to start.)\n", "Both FBP and iterative reconstruction methods\n", "need to know which values\n", "of $r$ and $ϕ$\n", "are sampled.\n", "\n", "In this package,\n", "`SinoPar`\n", "is the type that describes\n", "a parallel-beam sinogram geometry.\n", "\n", "The built-in defaults provide helpful reminders about the usage." ], "metadata": {} }, { "outputs": [], "cell_type": "code", "source": [ "SinoPar()" ], "metadata": {}, "execution_count": null }, { "cell_type": "markdown", "source": [ "This package supports units via the\n", "[Unitful.jl](https://github.com/PainterQubits/Unitful.jl)\n", "and using units is recommended\n", "(but not required).\n", "\n", "Here is an example of how to specify\n", "a parallel-beam geometry.\n", "Everything is a named keyword argument with sensible default values.\n", "\n", "* `orbit` and `orbit_start` must both be unitless (degrees)\n", " or have the same units (e.g., degrees or radians).\n", "* detector spacing `d` and `strip_width`\n", " must both be unitless or have the same units (e.g., mm).\n", "* The projection angles $ϕ$ are equally space and given by\n", " `orbit_start + (0:(nb-1))/nb * orbit`." ], "metadata": {} }, { "outputs": [], "cell_type": "code", "source": [ "sg = SinoPar( ;\n", " nb = 64, # number of radial samples (\"bins\")\n", " na = 30, # number of angular samples\n", " d = 2mm, # detector spacing\n", " offset = 0.25, # quarter detector offset (unitless)\n", " orbit = 180, # angular range (in degrees)\n", " orbit_start = 0, # starting angle (in degrees)\n", " strip_width = 2mm, # detector width\n", ")" ], "metadata": {}, "execution_count": null }, { "cell_type": "markdown", "source": [ "The struct `sg` has numerous useful properties;\n", "type `?SinoGeom` to see the full list.\n", "\n", "For example,\n", "to access the angular samples in degrees\n", "type `sg.ad`" ], "metadata": {} }, { "outputs": [], "cell_type": "code", "source": [ "sg.ad" ], "metadata": {}, "execution_count": null }, { "cell_type": "markdown", "source": [ "The following function visualizes the sampling pattern." ], "metadata": {} }, { "outputs": [], "cell_type": "code", "source": [ "sino_plot_rays(sg; ylims=(0,180), yticks=(0:90:180), widen=true, title=\"Parallel\")" ], "metadata": {}, "execution_count": null }, { "outputs": [], "cell_type": "code", "source": [ "prompt()" ], "metadata": {}, "execution_count": null }, { "cell_type": "markdown", "source": [ "## Fan-beam CT with an arc detector (3rd generation CT)\n", "\n", "For a fan-beam geometry,\n", "the arguments are the same as for `SinoPar`\n", "with the addition of specifying:\n", "* `dsd` distance from source to detector\n", "* `dod` distance from origin (isocenter) to detector\n", "* `dfs` distance from focal point of detector to source\n", " (0 for a 3rd gen arc detector, and `Inf` for a flat detector)\n", "* `source_offset` for misaligned systems\n", " where the ray from the source to the detector center\n", " does not intersect the isocenter.\n", " Not fully supported; submit an issue if you need this feature.\n", "\n", "Here is an example that corresponds to a GE Lightspeed CT system.\n", "These numbers are published in\n", "[IEEE T-MI Oct. 2006, p.1272-1283](http://doi.org/10.1109/TMI.2006.882141)." ], "metadata": {} }, { "outputs": [], "cell_type": "code", "source": [ "sg = SinoFanArc( ; nb=888, na=984,\n", " d=1.0239mm, offset=1.25, dsd=949.075mm, dod=408.075mm)" ], "metadata": {}, "execution_count": null }, { "cell_type": "markdown", "source": [ "Here is a smaller example for plotting the rays." ], "metadata": {} }, { "outputs": [], "cell_type": "code", "source": [ "sg = SinoFanArc( ; nb=64, na=30,\n", " d=20mm, offset=0.25, dsd=900mm, dod=400mm)\n", "sino_plot_rays(sg; ylims=(-50,400), yticks=(0:180:360), widen=true,\n", " title=\"Fan-beam for arc detector\")" ], "metadata": {}, "execution_count": null }, { "outputs": [], "cell_type": "code", "source": [ "prompt()" ], "metadata": {}, "execution_count": null }, { "cell_type": "markdown", "source": [ "## Fan-beam CT with a flat detector\n", "\n", "This geometry is the same as the arc detector\n", "except that `dfs=Inf`." ], "metadata": {} }, { "outputs": [], "cell_type": "code", "source": [ "sg = SinoFanFlat( ; nb=64, na=30,\n", " d=20mm, offset=0.25, dsd=900mm, dod=400mm)" ], "metadata": {}, "execution_count": null }, { "cell_type": "markdown", "source": [ "Here is its sampling plot" ], "metadata": {} }, { "outputs": [], "cell_type": "code", "source": [ "sino_plot_rays(sg; ylims=(-50,400), yticks=(0:180:360), widen=true,\n", " title=\"Fan-beam for flat detector\")" ], "metadata": {}, "execution_count": null }, { "outputs": [], "cell_type": "code", "source": [ "prompt()" ], "metadata": {}, "execution_count": null }, { "cell_type": "markdown", "source": [ "## Mojette sampling\n", "This is a specialized sampling geometry\n", "that is currently incompletely supported." ], "metadata": {} }, { "outputs": [], "cell_type": "code", "source": [ "SinoMoj()" ], "metadata": {}, "execution_count": null }, { "cell_type": "markdown", "source": [ "---\n", "\n", "*This notebook was generated using [Literate.jl](https://github.com/fredrikekre/Literate.jl).*" ], "metadata": {} } ], "nbformat_minor": 3, "metadata": { "language_info": { "file_extension": ".jl", "mimetype": "application/julia", "name": "julia", "version": "1.7.3" }, "kernelspec": { "name": "julia-1.7", "display_name": "Julia 1.7.3", "language": "julia" } }, "nbformat": 4 }