Skip to content

Commit 064d097

Browse files
authored
Document sinogram geometries (#17)
* 4space * concise unit show * sino plot units * docs * show sg
1 parent 0b4cfe3 commit 064d097

File tree

8 files changed

+124
-22
lines changed

8 files changed

+124
-22
lines changed

docs/lit/examples/02-sino-geom.jl

Lines changed: 101 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,11 @@ This page was generated from a single Julia file:
2626

2727
# Packages needed here.
2828

29-
using Sinograms: SinoPar, SinoMoj, SinoFanArc, SinoFanFlat, rays
29+
using Unitful: mm, °
30+
using UnitfulRecipes
31+
using Plots # must precede 'using Sinograms' for sino_plot_rays to work
32+
using Sinograms: SinoPar, SinoMoj, SinoFanArc, SinoFanFlat, SinoFan
33+
using Sinograms: sino_plot_rays
3034
using MIRTjim: jim, prompt
3135
using InteractiveUtils: versioninfo
3236

@@ -72,25 +76,117 @@ In this package,
7276
is the type that describes
7377
a parallel-beam sinogram geometry.
7478
75-
The built-in defaults are helpful.
79+
The built-in defaults provide helpful reminders about the usage.
7680
=#
7781

7882
SinoPar()
7983

84+
#=
85+
This package supports units via the
86+
[Unitful.jl](https://github.com/PainterQubits/Unitful.jl)
87+
and using units is recommended
88+
(but not required).
89+
90+
Here is an example of how to specify
91+
a parallel-beam geometry.
92+
Everything is a named keyword argument with sensible default values.
93+
94+
* `orbit` and `orbit_start` must both be unitless (degrees)
95+
or have the same units (e.g., degrees or radians).
96+
* detector spacing `d` and `strip_width`
97+
must both be unitless or have the same units (e.g., mm).
98+
* The projection angles ``ϕ`` are equally space and given by
99+
`orbit_start + (0:(nb-1))/nb * orbit`.
100+
=#
101+
102+
sg = SinoPar( ;
103+
nb = 64, # number of radial samples ("bins")
104+
na = 30, # number of angular samples
105+
d = 2mm, # detector spacing
106+
offset = 0.25, # quarter detector offset (unitless)
107+
orbit = 180, # angular range (in degrees)
108+
orbit_start = 0, # starting angle (in degrees)
109+
strip_width = 2mm, # detector width
110+
)
111+
112+
#=
113+
The struct `sg` has numerous useful properties;
114+
type `?SinoGeom` to see the full list.
115+
116+
For example,
117+
to access the angular samples in degrees
118+
type `sg.ad`
119+
=#
80120

81-
## todo: more details
121+
sg.ad
82122

83123

124+
# The following function visualizes the sampling pattern.
125+
126+
sino_plot_rays(sg; ylims=(0,180), yticks=(0:90:180), widen=true, title="Parallel")
127+
128+
#
129+
prompt()
130+
131+
132+
#=
84133
## Fan-beam CT with an arc detector (3rd generation CT)
85134
86-
SinoFanArc()
135+
For a fan-beam geometry,
136+
the arguments are the same as for `SinoPar`
137+
with the addition of specifying:
138+
* `dsd` distance from source to detector
139+
* `dod` distance from origin (isocenter) to detector
140+
* `dfs` distance from focal point of detector to source
141+
(0 for a 3rd gen arc detector, and `Inf` for a flat detector)
142+
* `source_offset` for misaligned systems
143+
where the ray from the source to the detector center
144+
does not intersect the isocenter.
145+
Not fully supported; submit an issue if you need this feature.
146+
147+
Here is an example that corresponds to a GE Lightspeed CT system.
148+
These numbers are published in
149+
[IEEE T-MI Oct. 2006, p.1272-1283](http://doi.org/10.1109/TMI.2006.882141).
150+
=#
151+
152+
sg = SinoFanArc( ; nb=888, na=984,
153+
d=1.0239mm, offset=1.25, dsd=949.075mm, dod=408.075mm)
154+
155+
156+
# Here is a smaller example for plotting the rays.
157+
158+
sg = SinoFanArc( ; nb=64, na=30,
159+
d=20mm, offset=0.25, dsd=900mm, dod=400mm)
160+
sino_plot_rays(sg; ylims=(-50,400), yticks=(0:180:360), widen=true,
161+
title="Fan-beam for arc detector")
87162

163+
#
164+
prompt()
88165

166+
167+
#=
89168
## Fan-beam CT with a flat detector
90169
91-
SinoFanFlat()
170+
This geometry is the same as the arc detector
171+
except that `dfs=Inf`.
172+
=#
92173

174+
sg = SinoFanFlat( ; nb=64, na=30,
175+
d=20mm, offset=0.25, dsd=900mm, dod=400mm)
93176

177+
178+
# Here is its sampling plot
179+
sino_plot_rays(sg; ylims=(-50,400), yticks=(0:180:360), widen=true,
180+
title="Fan-beam for flat detector")
181+
182+
#
183+
prompt()
184+
185+
186+
#=
94187
## Mojette sampling
188+
This is a specialized sampling geometry
189+
that is currently incompletely supported.
190+
=#
95191

96192
SinoMoj()

matlab/test1.jl

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,12 @@ using Plots
44

55
# setup matlab to use MIRT
66
if !@isdefined(irtdir)
7-
ENV["MATLAB_ROOT"] = "/Applications/freeware/matlab"
7+
ENV["MATLAB_ROOT"] = "/Applications/freeware/matlab"
88

9-
irtdir = "/Users/fessler/src/matlab/alg"
10-
tmp = "addpath('$irtdir')"
11-
eval_string(tmp)
12-
mat"setup"
9+
irtdir = "/Users/fessler/src/matlab/alg"
10+
tmp = "addpath('$irtdir')"
11+
eval_string(tmp)
12+
mat"setup"
1313
end
1414

1515
fov = 500.
@@ -36,12 +36,12 @@ mat"im_mat = ellipse_im(ig, ell)"
3636

3737
@mget im_mat
3838

39-
plot(jim(im_julia, "julia"), jim(im_mat, "matlab"), jim(im_mat - im_julia))
39+
plot(jim(im_julia, "julia"), jim(im_mat, "matlab"), jim(im_mat - im_julia))
4040

4141
sino_julia = ellipse_sino(sg, ell)
4242

4343
mat"[sino_mat, pos, ang] = ellipse_sino(sg, ell)"
4444
mat"sizeof(sino_mat)"
4545
#@mget sino_mat
4646

47-
#plot(jim(sino_julia, "julia"), jim(sino_mat, "matlab"), jim(sino_mat - sino_julia))
47+
#plot(jim(sino_julia, "julia"), jim(sino_mat, "matlab"), jim(sino_mat - sino_julia))

matlab/zwart_powell.jl

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,12 @@ using LazyGrids: ndgrid_array
88

99
# setup matlab to use MIRT
1010
if !@isdefined(irtdir)
11-
ENV["MATLAB_ROOT"] = "/Applications/freeware/matlab"
11+
ENV["MATLAB_ROOT"] = "/Applications/freeware/matlab"
1212

13-
irtdir = "/Users/fessler/src/matlab/alg"
14-
tmp = "addpath('$irtdir')"
15-
eval_string(tmp)
16-
mat"setup"
13+
irtdir = "/Users/fessler/src/matlab/alg"
14+
tmp = "addpath('$irtdir')"
15+
eval_string(tmp)
16+
mat"setup"
1717
end
1818

1919

src/Sinograms.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ If no Unitful package loaded, assume `angle` is in degrees and convert to radian
3434
#to_radians(angle::Real) = deg2rad(Float32(angle))
3535
to_radians(aa::AbstractArray{T}) where {T <: AbstractFloat} = aa * T(deg2rad(1))
3636
#to_radians(aa::AbstractArray{T}) where {T <: Real} = aa * deg2rad(1f0) # Float32
37+
_unit_precision(x::T) where {T <: Number} = T
3738

3839

3940
# support Plots iff user has loaded that package

src/fbp2/sino-geom.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -766,7 +766,7 @@ function Base.show(io::IO, ::MIME"text/plain", sg::SinoGeom)
766766
println(io, "$(typeof(sg)) :")
767767
for f in fieldnames(typeof(sg))
768768
p = getproperty(sg, f)
769-
t = typeof(p)
769+
t = (p isa Number) ? _unit_precision(p) : typeof(p)
770770
println(io, " ", f, "::", t, " ", p)
771771
end
772772
end

src/fbp2/sino-plot.jl

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,16 +19,19 @@ Requires `Plots`.
1919
function sino_plot_rays(sg::SinoGeom; kwargs...)
2020
r, phi = rays(sg)
2121
ad = rad2deg.(phi)
22-
ylims = (min(0, minimum(ad)), max(360, maximum(ad)))
23-
rmax = ceil(maximum(abs, r)/10, digits=0) * 10
22+
unit_a = oneunit(eltype(ad))
23+
ylims = (min(zero(unit_a), minimum(ad)),
24+
max(360*unit_a, maximum(ad)))
25+
unit_r = oneunit(eltype(r))
26+
rmax = ceil(maximum(abs, r/unit_r)/10, digits=0) * 10 * unit_r
2427
xlims = (-1,1) .* rmax
2528
scatter(
2629
r, ad ;
2730
label="",
2831
markersize=1, markerstrokecolor=:auto,
2932
markershape=:circle, linewidth=0,
3033
ylims, xlims, ylabel="ϕ",
31-
xticks=(-1:1)*rmax, yticks=[0,360],
34+
xticks=(-1:1)*rmax, yticks=[0,360] * unit_a,
3235
title="$(typeof(sg))",
3336
kwargs...
3437
)

src/units.jl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,5 @@ Convert `Unitful` quantity to radians.
1515
# aa * ((one(Float32)*rad) / oneunit(eltype(aa)))
1616
to_radians(aa::AbstractArray{<: Unitful.Quantity{T}}) where {T <: AbstractFloat} =
1717
aa * ((one(T)*rad) / oneunit(eltype(aa)))
18+
19+
_unit_precision(x::Unitful.Quantity{T}) where {T <: Number} = "Unit{$T}"

test/sys2/zwart_powell.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ using Test: @test, @testset, @test_throws, @inferred
2222
sino = zwart_powell.(r, ϕ')
2323
2424
p2 = plot()
25-
for (i,θ) in enumerate(ϕ)
25+
for (i,θ) in enumerate(ϕ)
2626
plot!(r, sino[:,i], label="ϕ=$θ")
2727
end
2828
plot(p1, p2)

0 commit comments

Comments
 (0)