Support mask
This page explains the mask
aspects of the Julia package ImageGeoms
.
This page comes from a single Julia file: 2-mask.jl
.
You can access the source code for such Julia documentation using the 'Edit on GitHub' link in the top right. You can view the corresponding notebook in nbviewer here: 2-mask.ipynb
, or open it in binder here: 2-mask.ipynb
.
Setup
Packages needed here.
using ImageGeoms: ImageGeom, MaskCircle, MaskAllButEdge
using ImageGeoms: maskit, embed, embed!, getindex! # +jim +size
using ImageGeoms: mask_outline
using MIRTjim: jim, prompt
using Unitful: mm
The following line is helpful when running this file as a script; this way it will prompt user to hit a key after each figure is displayed.
isinteractive() ? jim(:prompt, true) : prompt(:draw);
Mask overview
In tomographic image reconstruction, patients are usually more "round" than "square" so often we only want to estimate the pixels inside some support mask
: a Bool
array indicating which pixels are to be estimated. (The rest are constrained to be zero.) The ImageGeom
struct has an entry to store this mask
. The default is Trues(dims)
which is a "lazy" Bool AbstractArray
from the FillArrays
package that is conceptually similar to trues(dims)
but requires O(1)
storage. So there is essentially no memory penalty to storing this entry in the ImageGeom
for users who do not want to think about a mask
. For users who do want a mask
, fortunately Julia uses a special BitArray
type to store Bool
arrays, so the storage is 8× less than using bytes in most other languages.
Often we use a "circle inscribed in the square" as a generic support mask, and one of the built-in constructors can generate such a circular mask:
ig = ImageGeom(MaskCircle() ; dims=(40,32), deltas=(1mm,1mm))
ImageGeom{2, NTuple{2,Unitful.Quantity{Int64, 𝐋, Unitful.FreeUnits{(mm,), 𝐋, nothing}}}, BitMatrix}
dims::NTuple{2,Int64} (40, 32)
deltas::NTuple{2,Unitful.Quantity{Int64, 𝐋, Unitful.FreeUnits{(mm,), 𝐋, nothing}}} (1 mm, 1 mm)
offsets::NTuple{2,Float32} (0.0f0, 0.0f0)
mask: 40×32 BitMatrix {716 of 1280}
That last line shows that 716 of 1280=40*32 mask pixels are nonzero.
jim(ig)
Note that jim
displays the axes with the units naturally; see MIRTjim.jl.
A 3D mask can be hard to visualize, so there is a mask_or
method that collapses it to 2D:
ig = ImageGeom(MaskAllButEdge() ; dims=(32,32,16))
jim(ig)
Mask operations
Often we need to extract the pixel values within a mask:
ig = ImageGeom(MaskAllButEdge() ; dims=(6,4))
x = 1:size(ig,1)
y = 1:size(ig,2)
ramp = x .+ 10*y'
ig.mask
core = ramp[ig.mask]
8-element Vector{Int64}:
22
23
24
25
32
33
34
35
Or equivalently:
maskit(ramp, ig.mask)
8-element Vector{Int64}:
22
23
24
25
32
33
34
35
Conversely, we can embed
that list of pixels back into an array:
array = embed(core, ig.mask)
6×4 Matrix{Int64}:
0 0 0 0
0 22 32 0
0 23 33 0
0 24 34 0
0 25 35 0
0 0 0 0
There are in-place versions of these two operations:
core = Array{Float32}(undef, sum(ig.mask))
getindex!(core, ramp, ig.mask)
8-element Vector{Float32}:
22.0
23.0
24.0
25.0
32.0
33.0
34.0
35.0
array = collect(zeros(Float16, ig))
embed!(array, core, ig.mask)
6×4 Matrix{Float16}:
0.0 0.0 0.0 0.0
0.0 22.0 32.0 0.0
0.0 23.0 33.0 0.0
0.0 24.0 34.0 0.0
0.0 25.0 35.0 0.0
0.0 0.0 0.0 0.0
Mask outline
Sometimes we need the outline of the mask.
ig = ImageGeom(MaskCircle() ; dims=(40,32))
outline = mask_outline(ig.mask)
jim(
jim(ig.mask, "Mask"; prompt=false),
jim(outline, "Outline"; prompt=false),
)
This page was generated using Literate.jl.