MIRT overview
This is a placeholder
This page was generated using Literate.jl.
diff --git a/dev/examples/1-mirt/index.html b/dev/examples/1-mirt/index.html index a603f184..cf5bf704 100644 --- a/dev/examples/1-mirt/index.html +++ b/dev/examples/1-mirt/index.html @@ -1,2 +1,2 @@ -
This is a placeholder
This page was generated using Literate.jl.
Settings
This document was generated with Documenter.jl version 0.27.23 on Tuesday 25 October 2022. Using Julia version 1.8.2.
This is a placeholder
This page was generated using Literate.jl.
Settings
This document was generated with Documenter.jl version 0.27.23 on Tuesday 25 October 2022. Using Julia version 1.8.2.
MIRT.jl is a collection of Julia functions for performing image reconstruction and solving related inverse problems.
It is very much still under construction, although there are already enough tools to solve useful problems like compressed sensing MRI reconstruction. Trying the demos is a good way to get started.
The documentation is even more still under construction.
Further examples will likely be shared at JuliaImageRecon; see Examples there.
Settings
This document was generated with Documenter.jl version 0.27.23 on Tuesday 25 October 2022. Using Julia version 1.8.2.
MIRT.jl is a collection of Julia functions for performing image reconstruction and solving related inverse problems.
It is very much still under construction, although there are already enough tools to solve useful problems like compressed sensing MRI reconstruction. Trying the demos is a good way to get started.
The documentation is even more still under construction.
Further examples will likely be shared at JuliaImageRecon; see Examples there.
Settings
This document was generated with Documenter.jl version 0.27.23 on Tuesday 25 October 2022. Using Julia version 1.8.2.
MIRT.Afft
— MethodA = Afft(samp::AbstractArray{Bool} ; T::DataType = ComplexF32)
Make a LinearMapAO object for (under-sampled) FFT, of type T
, using given sampling pattern samp
. Especially for compressed sensing MRI with Cartesian sampling.
Option:
operator::Bool = true
set to false
to return a LinearMapAM
work::AbstractArray
work space for in-place fft operationsMIRT.Anufft
— MethodAnufft(ω, N ; kwargs ...)
Make a LinearMapAO
object of size length(ω) × prod(N)
. See nufft_init
for options.
MIRT.Aodwt
— MethodA, levels, mfun = Aodwt(dims ; level::Int=3, wt=wavelet(WT.haar))
Create orthogonal discrete wavelet transform (ODWT) LinearMapAA
in
dims::Dims
tuple of dimensionsoption
level::Int
# of levels; default 3wt
wavelet transform type (see Wavelets
package); default Haaroperator::Bool=true
default to LinearMapAO
T::DataType
: Float32
by default; use ComplexF32
if neededout
A
a LinearMapAX
objectscales
array of size dims
showing the scale of each coefficientwhich is useful when imposing scale-dependent regularization
mfun
convenience function for A*X when X is a Matrix or Array (not vector)2019-02-23 Jeff Fessler, University of Michigan
MIRT.caller_name
— Methodcaller_name() or caller_name(;level=4)
Return "filename line fun():" as a string to describe where this function was called.
Stack levels:
Hence the default level is 4, but we increment it by one in case user says @show caller_name()
in which case stack[3] is a macro expansion.
MIRT.diff_adj
— MethodZ = diff_adj(dx, N::Dims{D} ; dims = 1:D)
Adjoint of finite differences of arrays along one or more dimensions. By default performs the same operations as $vec(Z) = [(I_{N_d} \otimes \cdots \otimes D_{N_1}); \dots; (D_{N_d} \otimes \cdots \otimes I_{N_1})]' * d$ where D_N
denotes the N-1 × N
1D finite difference matrix and ⊗
denotes the Kronecker product, but does it efficiently without using spdiagm
(or any SparseArrays
function).
in
dx
vector of typical length N_d*...*(N_1-1) + ... + (N_d-1)*...*N_1
N::Dims
desired output sizeoption
dims
dimension(s) for performing adjoint finite differences; default 1:ndims(X)
out
Z
N_1 × ... × N_d
array by defaultMIRT.diff_forw
— Methodd = diff_forw(X ; dims = 1:ndims(X))
Finite differences along one or more dimensions of an array, e.g., for anisotropic TV regularization.
By default performs the same operations as $d = [(I_{N_d} \otimes \cdots \otimes D_{N_1}); \dots; (D_{N_d} \otimes \cdots \otimes I_{N_1})] vec(X)$ where $D_N$ denotes the N-1 × N
1D finite difference matrix and ⊗
denotes the Kronecker product, but does it efficiently without using spdiagm
(or any SparseArrays
function).
Input dimension N
must exceed 1
for each dimension specified by dims
.
in
X
N_1 × ... × N_d
array (typically an N-D image).option
dims
dimension(s) for performing finite differences; default 1:ndims(X)
must have unique elements and be a nonempty subset of 1:ndims(X)
out
d
vector of default length N_d*...*(N_1-1) + ... + (N_d-1)*...*N_1
MIRT.diff_map
— MethodT = diff_map(N::Dims{D} ; dims = 1:D)
in
N::Dims
image sizeout
T
LinearMapAA
object for computing finite differences via T*x
MIRT.diffl!
— Methoddiffl!(g::AbstractArray, x::AbstractArray, dims::AbstractVector{Int} ; ...)
When x
is a N
-dimensional array, the i
th slice of the g
array (along its last dimension) is the diffl!
of x
along dims[i]
. This is useful for total variation (TV) and other regularizers that need finite differences along multiple dimensions.
MIRT.diffl!
— Methoddiffl!(g::AbstractArray, x::AbstractArray, dim::Int ; ...)
Apply left finite difference operator to input array x
, storing the result "in-place" in pre-allocated output array g
. (The letter g
is mnemonic for "gradient".)
Arrays g
and x
must have the same size, and cannot alias. By default, the "first" elements of g
are zero for dimension dim
. The default is dim=1
.
Option:
add::Bool = false
use x[i] + x[i-1]
instead of x[i] - x[i-1]
(useful for certain diagonal majorizers).edge::Symbol = :zero
set the first elements of dimension dim
to 0edge=:circ
to use circulant (aka periodic) boundary conditions.edge=:none
to leave the first elements untouched.Example
julia> x = [2, 6, 7]; g = similar(x); diffl!(g, x)
+Function References · MIRT.jl Function References
MIRT.Afft
— MethodA = Afft(samp::AbstractArray{Bool} ; T::DataType = ComplexF32)
Make a LinearMapAO object for (under-sampled) FFT, of type T
, using given sampling pattern samp
. Especially for compressed sensing MRI with Cartesian sampling.
Option:
operator::Bool = true
set to false
to return a LinearMapAM
work::AbstractArray
work space for in-place fft operations
sourceMIRT.Anufft
— MethodAnufft(ω, N ; kwargs ...)
Make a LinearMapAO
object of size length(ω) × prod(N)
. See nufft_init
for options.
sourceMIRT.Aodwt
— MethodA, levels, mfun = Aodwt(dims ; level::Int=3, wt=wavelet(WT.haar))
Create orthogonal discrete wavelet transform (ODWT) LinearMapAA
in
dims::Dims
tuple of dimensions
option
level::Int
# of levels; default 3wt
wavelet transform type (see Wavelets
package); default Haaroperator::Bool=true
default to LinearMapAO
T::DataType
: Float32
by default; use ComplexF32
if needed
out
A
a LinearMapAX
objectscales
array of size dims
showing the scale of each coefficient
which is useful when imposing scale-dependent regularization
mfun
convenience function for A*X when X is a Matrix or Array (not vector)
2019-02-23 Jeff Fessler, University of Michigan
sourceMIRT.caller_name
— Methodcaller_name() or caller_name(;level=4)
Return "filename line fun():" as a string to describe where this function was called.
Stack levels:
- 1: #caller_name
- 2: caller_name()
- 3: function that invoked caller()
- 4: the calling function we want to return
Hence the default level is 4, but we increment it by one in case user says @show caller_name()
in which case stack[3] is a macro expansion.
sourceMIRT.diff_adj
— MethodZ = diff_adj(dx, N::Dims{D} ; dims = 1:D)
Adjoint of finite differences of arrays along one or more dimensions. By default performs the same operations as $vec(Z) = [(I_{N_d} \otimes \cdots \otimes D_{N_1}); \dots; (D_{N_d} \otimes \cdots \otimes I_{N_1})]' * d$ where D_N
denotes the N-1 × N
1D finite difference matrix and ⊗
denotes the Kronecker product, but does it efficiently without using spdiagm
(or any SparseArrays
function).
in
dx
vector of typical length N_d*...*(N_1-1) + ... + (N_d-1)*...*N_1
N::Dims
desired output size
option
dims
dimension(s) for performing adjoint finite differences; default 1:ndims(X)
out
Z
N_1 × ... × N_d
array by default
sourceMIRT.diff_forw
— Methodd = diff_forw(X ; dims = 1:ndims(X))
Finite differences along one or more dimensions of an array, e.g., for anisotropic TV regularization.
By default performs the same operations as $d = [(I_{N_d} \otimes \cdots \otimes D_{N_1}); \dots; (D_{N_d} \otimes \cdots \otimes I_{N_1})] vec(X)$ where $D_N$ denotes the N-1 × N
1D finite difference matrix and ⊗
denotes the Kronecker product, but does it efficiently without using spdiagm
(or any SparseArrays
function).
Input dimension N
must exceed 1
for each dimension specified by dims
.
in
X
N_1 × ... × N_d
array (typically an N-D image).
option
dims
dimension(s) for performing finite differences; default 1:ndims(X)
must have unique elements and be a nonempty subset of 1:ndims(X)
out
d
vector of default length N_d*...*(N_1-1) + ... + (N_d-1)*...*N_1
sourceMIRT.diff_map
— MethodT = diff_map(N::Dims{D} ; dims = 1:D)
in
N::Dims
image size
out
T
LinearMapAA
object for computing finite differences via T*x
sourceMIRT.diffl!
— Methoddiffl!(g::AbstractArray, x::AbstractArray, dims::AbstractVector{Int} ; ...)
When x
is a N
-dimensional array, the i
th slice of the g
array (along its last dimension) is the diffl!
of x
along dims[i]
. This is useful for total variation (TV) and other regularizers that need finite differences along multiple dimensions.
sourceMIRT.diffl!
— Methoddiffl!(g::AbstractArray, x::AbstractArray, dim::Int ; ...)
Apply left finite difference operator to input array x
, storing the result "in-place" in pre-allocated output array g
. (The letter g
is mnemonic for "gradient".)
Arrays g
and x
must have the same size, and cannot alias. By default, the "first" elements of g
are zero for dimension dim
. The default is dim=1
.
Option:
add::Bool = false
use x[i] + x[i-1]
instead of x[i] - x[i-1]
(useful for certain diagonal majorizers).edge::Symbol = :zero
set the first elements of dimension dim
to 0- Choose
edge=:circ
to use circulant (aka periodic) boundary conditions. - Choose
edge=:none
to leave the first elements untouched.
Example
julia> x = [2, 6, 7]; g = similar(x); diffl!(g, x)
3-element Vector{Int64}:
0
4
- 1
sourceMIRT.diffl
— Methodg = diffl(x::AbstractArray, dims::AbstractVector{Int} ; ...)
Allocating version of diffl!
for dims
sourceMIRT.diffl
— Methodg = diffl(x::AbstractArray, dim::Int ; ...)
Allocating version of diffl!
along dim
Example
julia> x = [1,2] .+ [10 30 70]; g = diffl(x, 2)
+ 1
sourceMIRT.diffl
— Methodg = diffl(x::AbstractArray, dims::AbstractVector{Int} ; ...)
Allocating version of diffl!
for dims
sourceMIRT.diffl
— Methodg = diffl(x::AbstractArray, dim::Int ; ...)
Allocating version of diffl!
along dim
Example
julia> x = [1,2] .+ [10 30 70]; g = diffl(x, 2)
2×3 Matrix{Int64}:
0 20 40
- 0 20 40
sourceMIRT.diffl
— Methodg = diffl(x::AbstractArray ; ...)
Allocating version of diffl!
along dim=1
sourceMIRT.diffl_adj!
— Methoddiffl_adj!(z::AbstractArray, g::AbstractArray, dims::AbstractVector{Int} ; ...)
Adjoint of diffl!
for multiple dimensions dims
. Here g
must have one more dimension than z
.
sourceMIRT.diffl_adj!
— Methoddiffl_adj!(z, g, dim::Int ; ...)
Adjoint of left finite difference diffl!
, in-place. Arrays z
and g
must be same size. See diffl_adj
for details.
sourceMIRT.diffl_adj
— Methodz = diffl_adj(g::AbstractArray, dim::Int ; ...)
Allocating version of diffl_adj!
along dim
.
Example
julia> g = ones(Int,2,3); z = diffl_adj(g, 2)
+ 0 20 40
sourceMIRT.diffl
— Methodg = diffl(x::AbstractArray ; ...)
Allocating version of diffl!
along dim=1
sourceMIRT.diffl_adj!
— Methoddiffl_adj!(z::AbstractArray, g::AbstractArray, dims::AbstractVector{Int} ; ...)
Adjoint of diffl!
for multiple dimensions dims
. Here g
must have one more dimension than z
.
sourceMIRT.diffl_adj!
— Methoddiffl_adj!(z, g, dim::Int ; ...)
Adjoint of left finite difference diffl!
, in-place. Arrays z
and g
must be same size. See diffl_adj
for details.
sourceMIRT.diffl_adj
— Methodz = diffl_adj(g::AbstractArray, dim::Int ; ...)
Allocating version of diffl_adj!
along dim
.
Example
julia> g = ones(Int,2,3); z = diffl_adj(g, 2)
2×3 Matrix{Int64}:
-1 0 1
- -1 0 1
sourceMIRT.diffl_adj
— Methodz = diffl_adj(g::AbstractArray ; ...)
Allocating version of diffl_adj!
along dim=1
.
Example
julia> g = [0, 2, 5]; z = diffl_adj(g)
+ -1 0 1
sourceMIRT.diffl_adj
— Methodz = diffl_adj(g::AbstractArray ; ...)
Allocating version of diffl_adj!
along dim=1
.
Example
julia> g = [0, 2, 5]; z = diffl_adj(g)
3-element Vector{Int64}:
-2
-3
- 5
sourceMIRT.diffl_adj
— Methodz = diffl_adj(g::AbstractArray, dims::AbstractVector{Int} ; ...)
Allocating version of diffl_adj!
for dims
.
sourceMIRT.diffl_map
— MethodT = diffl_map(N::Dims{D}, dims::AbstractVector{Int} ; kwargs...)
-T = diffl_map(N::Dims{D}, dim::Int ; kwargs...)
in
N::Dims
image size
options: see diffl!
T::Type
for LinearMapAA
, default Float32
operator::Bool = true
use false
for LinearMapAM
out
T
LinearMapAA
object for computing finite differences via T*x
using diffl!
and diffl_adj!
sourceMIRT.downsample1
— Methody = downsample1(x, down ; warn=true)
downsample 1D vector by factor down
in
x [n1]
down::Int
downsampling factor
option
warn::Bool
warn if noninteger multiple; default isinteractive()
out
y [n1/down]
sourceMIRT.downsample2
— Methody = downsample2(x, down ; warn=true, T)
downsample by averaging by integer factors in
x [nx ny]
down
can be a scalar (same factor for both dimensions) or a NTuple{2,Int}
option
warn::Bool
warn if noninteger multiple; default isinteractive()
T::DataType
specify output eltype; default eltype(x[1] / down[1])
out
y [nx/down ny/down]
sourceMIRT.downsample3
— Methody = downsample3(x, down ; warn=true, T)
downsample by averaging by integer factors in
x [nx ny nz]
down
can be a scalar (same factor for all dimensions) or a NTuple{3,Int}
option
warn::Bool
warn if noninteger multiple; default trueT::DataType
specify output eltype; default eltype(x[1] / down[1])
out
y [nx/down ny/down nz/down]
sourceMIRT.downsample_dim1
— Methody = downsample_dim1(x, down ; warn::Bool)
Down-sample x
by factor down
along first dimension by averaging.
in
x [n1 (Nd)]
down::Int
downsampling factor
option
warn::Bool
warn if non-integer multiple; default isinteractive()
out
y [n1÷down (Nd)]
sourceMIRT.dtft
— MethodX = dtft(w, x ; n_shift=?)
multi-dimensional DTFT (DSFT)
$X[m] = \sum_{n=0}^{N-1} x[n] \exp(-i w[m,:] (n - n_{shift})), m=1,…,M$ where here n
is a CartesianIndex
in
w::AbstractMatrix{<:Real}
[M,D]
frequency locations ("units" radians/sample)x::AbstractArray{<:Number}
[(Nd)]
D-dimensional signal
option
n_shift::AbstractVector{<:Real}
often is N/2; default zeros(D)
out
X::AbstractVector{ComplexF64}
[M]
DTFT
sourceMIRT.dtft
— MethodX = dtft(w, x ; n_shift=?)
1D DTFT
$X[m] = \sum_{n=0}^{N-1} x[n] \exp(-i w[m] (n - n_{shift})), m=1,…,M$
in
w::AbstractVector{<:Real}
[M]
frequency locations ("units" radians/sample)x::AbstractVector{<:Number}
[N]
1D signal
option
n_shift::Real
often is N/2; default 0
out
X::AbstractVector{ComplexF64}
[M]
DTFT
sourceMIRT.dtft_adj
— Methodx = dtft_adj(w, X, N ; n_shift=?)
adjoint for multi-dimensional DTFT (DSFT)
$x[n] = \sum_{m=1}^M X[m] \exp(i w[m,:] (n - n_{shift})), n=0,…,N-1$ where here n
is a CartesianIndex
in
X::AbstractVector{ComplexF64}
[M]
DTFTw::AbstractMatrix{<:Real}
[M,D]
frequency locations ("units" radians/sample)N::Dims
[D]
dimensions of signal x
option
n_shift::AbstractVector{<:Real}
often is N/2
; default zeros(D)
T::DataType
default (eltype(w) == Float64) ? ComplexF64 : ComplexF32
out
x::AbstractArray{<:Number}
[(N)]
D
-dimensional signal
sourceMIRT.dtft_adj
— Methodx = dtft_adj(w, X, N ; n_shift=?)
adjoint for 1D DTFT
$x[n] = \sum_{m=1}^M X[m] \exp(i w[m] (n - n_{shift})), n=0,…,N-1$
This is the adjoint (transpose) of dtft
, not an inverse DTFT.
in
w::AbstractVector{<:Real}
[M]
frequency locations ("units" radians/sample)X::AbstractVector{ComplexF64}
[M]
spectrum valuesN::Int
size of signal x
option
n_shift::Real
often is N/2; default 0T::DataType
output data type; default ComplexF64
out
x::AbstractVector{<:Number}
signal [N]
sourceMIRT.dtft_init
— Methodd = dtft_init(w, N ; n_shift=?)
for multi-dimensional DTFT (DSFT)
in
w::AbstractMatrix{<:Real}
[M,D]
frequency locations ("units" radians/sample)N::Dims
[D]
dimensions of signal x
option
n_shift::AbstractVector{<:Real}
often is N/2; default zeros(D)T::DataType
default ComplexF64
for testing NUFFT accuracy
out
d::NamedTuple
with fields
`dtft = x -> dtft(x), adjoint = y -> dtft_adj(y), A=LinearMapAO`
sourceMIRT.dtft_init
— Methodd = dtft_init(w, N ; n_shift=?)
for 1D DTFT
in
w::AbstractVector{<:Real}
[M]
frequency locations ("units" radians/sample)N::Int
size of signal x
option
n_shift::Real
often is N/2; default 0T::DataType
default ComplexF64
for testing NUFFT accuracy
out
d::NamedTuple
with fields
`dtft = x -> dtft(x), adjoint = y -> dtft_adj(y), A=LinearMapAO`
sourceMIRT.embed!
— Methodembed!(array, v, mask ; filler=0)
embed vector v
of length sum(mask)
into elements of array
where mask
is true
, setting the remaining elements to filler
(default 0).
sourceMIRT.embed
— Methodarray = embed(matrix::AbstractMatrix{<:Number}, mask::AbstractArray{Bool})
Embed each column of matrix
into mask
then cat
along next dimension In:
matrix [sum(mask) L]
mask [(N)]
Out:
array [(N) L]
sourceMIRT.embed
— Methodarray = embed(v, mask ; filler=0)
embed vector v
of length sum(mask)
into elements of an array where mask
is true
; see embed!
.
sourceMIRT.eql_root
— Methodx = eql_root(a,b,c)
+ 5
sourceMIRT.diffl_adj
— Methodz = diffl_adj(g::AbstractArray, dims::AbstractVector{Int} ; ...)
Allocating version of diffl_adj!
for dims
.
sourceMIRT.diffl_map
— MethodT = diffl_map(N::Dims{D}, dims::AbstractVector{Int} ; kwargs...)
+T = diffl_map(N::Dims{D}, dim::Int ; kwargs...)
in
N::Dims
image size
options: see diffl!
T::Type
for LinearMapAA
, default Float32
operator::Bool = true
use false
for LinearMapAM
out
T
LinearMapAA
object for computing finite differences via T*x
using diffl!
and diffl_adj!
sourceMIRT.downsample1
— Methody = downsample1(x, down ; warn=true)
downsample 1D vector by factor down
in
x [n1]
down::Int
downsampling factor
option
warn::Bool
warn if noninteger multiple; default isinteractive()
out
y [n1/down]
sourceMIRT.downsample2
— Methody = downsample2(x, down ; warn=true, T)
downsample by averaging by integer factors in
x [nx ny]
down
can be a scalar (same factor for both dimensions) or a NTuple{2,Int}
option
warn::Bool
warn if noninteger multiple; default isinteractive()
T::DataType
specify output eltype; default eltype(x[1] / down[1])
out
y [nx/down ny/down]
sourceMIRT.downsample3
— Methody = downsample3(x, down ; warn=true, T)
downsample by averaging by integer factors in
x [nx ny nz]
down
can be a scalar (same factor for all dimensions) or a NTuple{3,Int}
option
warn::Bool
warn if noninteger multiple; default trueT::DataType
specify output eltype; default eltype(x[1] / down[1])
out
y [nx/down ny/down nz/down]
sourceMIRT.downsample_dim1
— Methody = downsample_dim1(x, down ; warn::Bool)
Down-sample x
by factor down
along first dimension by averaging.
in
x [n1 (Nd)]
down::Int
downsampling factor
option
warn::Bool
warn if non-integer multiple; default isinteractive()
out
y [n1÷down (Nd)]
sourceMIRT.dtft
— MethodX = dtft(w, x ; n_shift=?)
multi-dimensional DTFT (DSFT)
$X[m] = \sum_{n=0}^{N-1} x[n] \exp(-i w[m,:] (n - n_{shift})), m=1,…,M$ where here n
is a CartesianIndex
in
w::AbstractMatrix{<:Real}
[M,D]
frequency locations ("units" radians/sample)x::AbstractArray{<:Number}
[(Nd)]
D-dimensional signal
option
n_shift::AbstractVector{<:Real}
often is N/2; default zeros(D)
out
X::AbstractVector{ComplexF64}
[M]
DTFT
sourceMIRT.dtft
— MethodX = dtft(w, x ; n_shift=?)
1D DTFT
$X[m] = \sum_{n=0}^{N-1} x[n] \exp(-i w[m] (n - n_{shift})), m=1,…,M$
in
w::AbstractVector{<:Real}
[M]
frequency locations ("units" radians/sample)x::AbstractVector{<:Number}
[N]
1D signal
option
n_shift::Real
often is N/2; default 0
out
X::AbstractVector{ComplexF64}
[M]
DTFT
sourceMIRT.dtft_adj
— Methodx = dtft_adj(w, X, N ; n_shift=?)
adjoint for multi-dimensional DTFT (DSFT)
$x[n] = \sum_{m=1}^M X[m] \exp(i w[m,:] (n - n_{shift})), n=0,…,N-1$ where here n
is a CartesianIndex
in
X::AbstractVector{ComplexF64}
[M]
DTFTw::AbstractMatrix{<:Real}
[M,D]
frequency locations ("units" radians/sample)N::Dims
[D]
dimensions of signal x
option
n_shift::AbstractVector{<:Real}
often is N/2
; default zeros(D)
T::DataType
default (eltype(w) == Float64) ? ComplexF64 : ComplexF32
out
x::AbstractArray{<:Number}
[(N)]
D
-dimensional signal
sourceMIRT.dtft_adj
— Methodx = dtft_adj(w, X, N ; n_shift=?)
adjoint for 1D DTFT
$x[n] = \sum_{m=1}^M X[m] \exp(i w[m] (n - n_{shift})), n=0,…,N-1$
This is the adjoint (transpose) of dtft
, not an inverse DTFT.
in
w::AbstractVector{<:Real}
[M]
frequency locations ("units" radians/sample)X::AbstractVector{ComplexF64}
[M]
spectrum valuesN::Int
size of signal x
option
n_shift::Real
often is N/2; default 0T::DataType
output data type; default ComplexF64
out
x::AbstractVector{<:Number}
signal [N]
sourceMIRT.dtft_init
— Methodd = dtft_init(w, N ; n_shift=?)
for multi-dimensional DTFT (DSFT)
in
w::AbstractMatrix{<:Real}
[M,D]
frequency locations ("units" radians/sample)N::Dims
[D]
dimensions of signal x
option
n_shift::AbstractVector{<:Real}
often is N/2; default zeros(D)T::DataType
default ComplexF64
for testing NUFFT accuracy
out
d::NamedTuple
with fields
`dtft = x -> dtft(x), adjoint = y -> dtft_adj(y), A=LinearMapAO`
sourceMIRT.dtft_init
— Methodd = dtft_init(w, N ; n_shift=?)
for 1D DTFT
in
w::AbstractVector{<:Real}
[M]
frequency locations ("units" radians/sample)N::Int
size of signal x
option
n_shift::Real
often is N/2; default 0T::DataType
default ComplexF64
for testing NUFFT accuracy
out
d::NamedTuple
with fields
`dtft = x -> dtft(x), adjoint = y -> dtft_adj(y), A=LinearMapAO`
sourceMIRT.embed!
— Methodembed!(array, v, mask ; filler=0)
embed vector v
of length sum(mask)
into elements of array
where mask
is true
, setting the remaining elements to filler
(default 0).
sourceMIRT.embed
— Methodarray = embed(matrix::AbstractMatrix{<:Number}, mask::AbstractArray{Bool})
Embed each column of matrix
into mask
then cat
along next dimension In:
matrix [sum(mask) L]
mask [(N)]
Out:
array [(N) L]
sourceMIRT.embed
— Methodarray = embed(v, mask ; filler=0)
embed vector v
of length sum(mask)
into elements of an array where mask
is true
; see embed!
.
sourceMIRT.eql_root
— Methodx = eql_root(a,b,c)
Numerically stable method for computing the positive root
of the quadratic polynomial `-ax^2 - 2bx + c, a >= 0`.
-Assumes solvable equations; will throw otherwise.
in
a
: The negative of the x^2
term. Must be positive.b
: Half the negative of the x
term.c
: The constant term.
out
x
: The positive root that satisfies 0 = -ax^2 - 2bx + c
.
sourceMIRT.exp_mult
— MethodD = exp_mult(A, u, v ; warnboth)
Memory efficient and fast implementation of D = A' * exp(-u * v^T)
that is useful for B0-field-corrected MRI image reconstruction.
in:
A [N L]
matrixu [N]
vectorv [M]
vectorwarnboth
warn if both u
and v
are complex; default: true
out:
D [L M]
complex vector: D = A' * exp(-u * v^T)
D_lm = sum_n A_nl^* exp(-u_n v_m)
sourceMIRT.exp_xform
— Methodexp_xform(x, u, v ; mode::Symbol = :matrix)
in:
x [N L]
possibly complex vector(s)u [D N]
possibly complex vectorsv [D M]
possibly complex vectorsmode::Symbol
:matrix
(default) | :element
| :row
| :column
out:
y [M L]
typically complex vector
y[m,l] = sum_n x[n,l] exp(-sum(u[:,n] .* v[:,m]))
Iterates through subsets of the ML matrix designated by :mode
(i.e. row, column, element, or just computing the entire matrix) This is the 'slow' 'exact' transform model for MRI.
Output type will depend on input types.
sourceMIRT.genkspace
— Methodgenkspace
Generate the proper length of k-space trajectory.
It linearly interpolates the output of genspiral
to the correct length()
& takes care of the rotations for the interleaves.
ld
is the length of the datanint
is the number of interleaves
Brad Sutton; University of Michigan
sourceMIRT.genspi
— MethodGx, Gy, kx, ky, sx, sy, gts = genspi(...)
This is translation of C code from scanner: exactly what is played out to gradients at 4us.
multi-shot spiral design uses Duyn's approximate slewrate limited design augmented with archimedian gmax
limit in [args]
D
= FOV; cm
N
= matrix size()
Tmax
= longest acquisition allowed; s
dts
= output sample spacing; s
gtype
= trajectory type()
option [CVs]
nl
= number of interleavesgamp
= design grad max; G/cmgslew
= design slew rate; mT/m/msnramp
= number of rampdown points; default 0
out
Gx; Gy
time is in sec()
- rev 0 12/26/98 original
- rev 1 4/15/99 little better calc of ts
Borrowed from Doug Noll; Univ. of Michigan. Modified to take more input cv's.
sourceMIRT.getindex!
— Methodgetindex!(y::AbstractVector, x::AbstractArray{T,D}, mask::AbstractArray{Bool,D})
Equivalent to the in-place y .= x[mask]
but is non-allocating.
For non-Boolean indexing, just use @views y .= A[index]
, per https://discourse.julialang.org/t/efficient-non-allocating-in-place-getindex-for-bitarray/42268
sourceMIRT.interp1
— Methodyi = interp1(x, y, xi ; how=Gridded(Linear()), extrap=0)
1D interpolation of y = f(x)
at points xi
In:
x::AbstractVector{<:Real}
y::AbstractVector{<:Number}
Option:
how::Interpolations.InterpolationType
default Gridded(Linear())
extrap::Any
how to extrapolate, e.g., Flat()
; default 0
other options from Interpolations.jl are Line()
Periodic()
Reflect()
Throw()
Output is same size as input xi
sourceMIRT.ir_dump
— Methodir_dump(x::Any ; io::IO = stdout)
-ir_dump(io::IO, x::Any)
Show all the fields of a structure or NamedTuple
more nicely than dump() does
sourceMIRT.ir_load_brainweb_t1_256
— Methoddata = ir_load_brainweb_t1_256()
Load brainweb T1-weighted MRI slice of size 256 × 256
.
sourceMIRT.ir_mri_coil_compress
— Method(odata, σ, Vr) = ir_mri_coil_compress(idata ; ncoil)
MRI coil compression via PCA. Given multiple MRI surface coil images (idata), use SVD/PCA to find a smaller number of virtual coil images (odata).
In:
idata
[(N) n_in]
: noisy complex images (2D or 3D) for each coil
Option:
ncoil
Desired # of virtual coils (default: 1)
Out:
odata
[(N) ncoil]
: virtual coil imagesσ
[n_in]
: singular values.Vr
[n_in, ncoil]
: compression matrix for reducing other data.
todo: currently ignores noise correlations
sourceMIRT.ir_mri_kspace_ga_radial
— Methodkspace = ir_mri_kspace_ga_radial(; Nro=?, Nspoke=?, ...)
Generate k-space sampling pattern for "golden angle" radial sampling.
option
Nro:Int
number of samples in each readout/spoke, default 256Nspoke::Int
number of spokes, default 1start::Real
first angle in series [radians], default π/2angle::Real
angular spacing [radians], default GAdelta_ro::Real
readout spacing, default 1/Nro
shift::Real
shift due to gradient delays, default 0- radial sample locations are
ir * delta_ro
- where
ir = [-(Nro/2 - 1):1:Nro/2] + shift
out
kspace
[Nro Nspoke 2]
(Float32)
kx
and ky
k-space locations for Nspoke*Nro
samples in interval (-0.5 0.5]
for default shift
, delta_ro
so default units are "cycles / sample"
2015-07 Mai Le, original Matlab version
2015-07-04 Jeff Fessler, minor changes to Matlab version
sourceMIRT.ir_mri_sensemap_sim
— Method(smap,info) = ir_mri_sensemap_sim( :all ; kwargs)
Like ir_mri_sensemap_sim
but also returns info
with data for all coils, mainly for testing and plotting.
sourceMIRT.ir_mri_sensemap_sim
— Method(smap,info) = ir_mri_sensemap_sim( ir_ic_pair ; kwargs)
Like ir_mri_sensemap_sim
but also returns info
with data for specific coils where ir_ic_pair::Vector{Tuple{Int,Int}}
. (Usually used internally only.)
info::NamedTuple
geometry information for plots
sourceMIRT.ir_mri_sensemap_sim
— Methodsmap = ir_mri_sensemap_sim(...)
Simulate 2D or 3D sensitivity maps for sensitivity-encoded MRI based on grivich:00:tmf http://doi.org/10.1119/1.19461
This code makes maps for multiple coils, but does not model coupling between coils, so most likely it is an approximation at best.
option
dims::Dims
image size; default (64, 64)dx::Real
pixel/voxel dimension; default: 3dy::Real
pixel/voxel dimension; default: dx
dz::Real
""ncoil::Int
# of coils total; default 4nring::Int
# of rings of coils; default 1rcoil::Real
coil radius; default dx * nx / 2 * 0.50
dz_coil
ring spacing in z; default nz*dz/nring
- (3D geometry is a cylinder)
coil_distance::Real
distance of coil center from isocenter- for central ring of coils as a multiple of
FOVx
, - where
FOVx=nx*dx
; default 1.2
orbit::Real
default 360 [degrees]orbit_start::AbstractVector{<:Real} = fill(0, nring)
[degrees]scale::Symbol
:none
(default)
+ ssos_center
make SSoS of center = 1
out
smap [dims ncoil]
simulated sensitivity maps (complex!)
All length parameters must have same units (e.g., mm or cm)
sourceMIRT.ir_mri_sensemap_sim_do
— Method(smap, info) = ir_mri_sensemap_sim_do()
sourceMIRT.ir_mri_smap1
— Methodir_mri_smap1()
based on grivich:00:tmf
for a circular coil in "x-y plane" of radius "a"
Note that coil x-y plane is not same as object x-y plane!
Returns (i,j,k)
components of B vector for each (x,y,z)
location
sourceMIRT.ir_mri_smap_r
— Methodir_mri_smap_r(r, z)
function for testing near 0
sourceMIRT.jinc
— Methodjinc(x)
Return jinc(x) = J1(pi*x)/(2x)
, where J1
is a Bessel function of the first kind.
Units of x
are typically cycles/m.
Return type is promote_type(typeof(x), Float32)
.
sourceMIRT.map_many
— Methody = map_many(fun::Function, x::AbstractArray{<:Any}, idim::Dims)
apply a function fun
to leading slices of input x
; cousin of mapslices
in
fun::Function
maps input of size idim
to output of some size odim
x [idim ldim]
out
y [odim ldim]
Example: if fun
maps array of size (1,2) to array of size (3,4,5) and if input x
has size (1,2,7,8) then output y
will have size (3,4,5,7,8) where y[:,:,:,i,j] = fun(x[:,:,i,j])
sourceMIRT.mask_or
— Methodmask_or(mask)
compress 3D mask to 2D by logical or
along z
direction
sourceMIRT.mask_outline
— Methodmask_outline(mask)
return outer boundary of 2D mask (or mask_or for 3D)
sourceMIRT.maskit
— Methodmaskit(x::AbstractArray{<:Number})
opposite of embed
sourceMIRT.max_percent_diff
— Methodd = max_percent_diff(s1, s2, [options])
Compute the "maximum percent difference" between two signals: s1, s2
.
Default is to normalize by maximum(abs.(s1))
.
options
maxboth::Bool
use max of both arguments to normalize; default false
normalize::Bool
normalize each before comparing; default false
sourceMIRT.mri_kspace_spiral
— Methodkspace, omega, gradxy = mri_kspace_spiral( [options] )
Make k-space spiral trajectory based on GE 3T scanner constraints
Option:
N
dimention of reconstructed imageNt
# of time pointsfov
field of view in cmdt
time sampling interval out; default 5e-6
secgamp::Real
design gradient amplitude max, G/cm; default 2.2gslew::Int
design slew rate, mT/m/ms; default 180
Out:
kspace [Nt,2]
kspace trajectory [kx ky]
in cycles/cm, NO: cycles/FOVomega [Nt,2]
"" in radiansgradxy [Nt 2]
gradient waveforms in (units?)
sourceMIRT.mri_trajectory
— Methodkspace, omega, wi = mri_trajectory( ; ktype, N, fov, arg_wi, kwargs...)
Generate kspace trajectory samples and density compensation functions.
option
ktype::Symbol
k-space trajectory type; default :radial
N::Dims
target image size; default (32,30)fov
field of view in x and y (and z); default (250,250) mmarg_wi
options to pass to ir_mri_density_comp
- not yet donekwargs
options for the specific trajectory
out
kspace [Nk 2|3]
kspace samples in units 1/fovomega [Nk 2|3]
trajectory samples over [-π,π)wi [Nk 1]
(optional) density compensation factors
trajectory types: :cartesian
:radial
:cart_y_2
:random
:half8
:epi_sin
:spiral0 :spiral1 :spiral3
:rosette3
:epi_under
:gads
(emulate golden-angle data sharing per winkelmann:07:aor)
sourceMIRT.mri_trajectory_gads
— Methodomega, wi = mri_trajectory_gads(N, fov ; ...)
emulate 2D golden angle radial sampling with data sharing
option: Nro
# of samples in each readout/spoke shift
shift along read-out due to gradient delays (stress) kmax_frac
fractions of maximum krad (0.5) for rings (annuli) under
under-sampling factor for each annulus
sourceMIRT.mri_trajectory_radial
— Methodmri_trajectory_radial()
option:
na_nr
default ensures proper sampling at edge of k-spacena
angular spokes; default: na_nr * nrnr
radial samples per spokeir
default: 0:nr
todo: generalize to 3D using barger:02:trc
sourceMIRT.mri_trajectory_rosette3
— Methodmri_trajectory_rosette3(N, fov ; ...)
3d rosette, with default parameters from bucholz:08:miw
options: omax: maximum omega nt : time samples (65.536 ms for 4 usec dt) dt : time sample spacing (4 usec) ti : time samples
sourceMIRT.ncg
— Method(x,out) = ncg(B, gradf, curvf, x0 ; ...)
Nonlinear preconditioned conjugate gradient algorithm to minimize a general "inverse problem" cost function of the form $\Psi(x) = \sum_{j=1}^J f_j(B_j x)$ where each function $f_j(v)$ has a quadratic majorizer of the form
\[q_j(v;u) = f_j(u) + \nabla f_j(u) (v - u) + 1/2 \|v - u\|^2_{C_j(u)}\]
where $C_j(u)$ is diagonal matrix of curvatures. (It suffices for each $f_j$ to have a Lipschitz smooth gradient.)
This CG method uses a majorize-minimize (MM) line search.
in
B
array of $J$ blocks $B_1,...,B_J$gradf
array of $J$ functions return gradients of $f_1,...,f_J$curvf
array of $J$ functions z -> curv(z)
that return a scalar
or a vector of curvature values for each element of $z$
x0
initial guess; need length(x) == size(B[j],2)
for $j=1...J$
Usually x0
is a Vector
but it can be an Array
if each B_j
is a linear operator (e.g., LinearMapAO
) of suitable "dimensions".
option
niter
# number of outer iterations; default 50ninner
# number of inner iterations of MM line search; default 5P
# preconditioner; default I
betahow
"beta" method for the search direction; default :dai_yuan
fun
User-defined function to be evaluated with two arguments (x,iter).- It is evaluated at (x0,0) and then after each iteration.
output
x
final iterateout
[niter+1] (fun(x0,0), fun(x1,1), ..., fun(x_niter,niter))
- (all 0 by default). This is an array of length
niter+1
sourceMIRT.ncg
— Method(x,out) = ncg(grad, curv, x0, ...)
special case of ncg
(nonlinear CG) for minimizing a cost function whose gradient is grad(x)
and that has a quadratic majorizer with diagonal Hessian given by curv(x)
. Typically curv = (x) -> L
where L
is the Lipschitz constant of grad
sourceMIRT.ndgrid
— Method(xx,yy,zz) = ndgrid(x::AbstractVector{<:Any}, y::..., z::...)
todo - improve?
sourceMIRT.ndgrid
— Method(xx,yy) = ndgrid(x::AbstractVector{<:Any}, y::AbstractVector{<:Any})
todo - improve?
sourceMIRT.nufft_eltype
— Methodnufft_eltype(::DataType)
ensure plan_nfft eltype is Float32 or Float64
sourceMIRT.nufft_errors
— Methodw, errs = nufft_errors( ; M=?, w=?, N=?, n_shift=?, ...)
Compute NUFFT approximation errors (for signal of length N
of unit norm), for given digital frequency values w
, i.e., Ω.
sourceMIRT.nufft_init
— Methodp = nufft_init(w, N ; nfft_m=4, nfft_sigma=2.0, pi_error=true, n_shift=0)
Setup 1D NUFFT, for computing fast $O(N \log N)$ approximation to
$X[m] = \sum_{n=0}^{N-1} x[n] \exp(-i w[m] (n - n_{shift})), m=1,…,M$
in
w::AbstractArray{<:Real}
[M]
frequency locations (aka Ω, units radians/sample)eltype(w)
determines the plan_nfft
type; so to save memory use Float32!size(w)
determines odim
for A
if operator=true
N::Int
signal length
option
nfft_m::Int
see NFFT.jl documentation; default 4nfft_sigma::Real
"", default 2.0n_shift::Real
often is N/2; default 0pi_error::Bool
throw error if $|w| > π$, default true
- Set to
false
only if you are very sure of what you are doing!
do_many::Bool
support extended inputs via map_many
? default true
operator::Bool=true
set to false
to make A
an LinearMapAM
out
p NamedTuple
(nufft = x -> nufft(x), adjoint = y -> nufft_adj(y), A::LinearMapAO)
The default settings are such that for a 1D signal of length N=512, the worst-case error is below 1e-5 which is probably adequate for typical medical imaging applications. To verify this statement, run nufft_plot1()
and see plot.
sourceMIRT.nufft_init
— Methodp = nufft_init(w, N ; nfft_m=4, nfft_sigma=2.0, pi_error=true, n_shift=?)
Setup multi-dimensional NUFFT, for computing fast $O(N \log N)$ approximation to
$X[m] = \sum_{n=0}^{N-1} x[n] \exp(-i w[m,:] (n - n_{shift})), m=1,…,M$
in
w::AbstractArray{<:Real}
[M,D]
frequency locations (aka Ω, units radians/sample)
+ `eltype(w)` determines the `plan_nfft` type; so to save memory use Float32!
+Assumes solvable equations; will throw otherwise.
in
a
: The negative of the x^2
term. Must be positive.b
: Half the negative of the x
term.c
: The constant term.
out
x
: The positive root that satisfies 0 = -ax^2 - 2bx + c
.
sourceMIRT.exp_mult
— MethodD = exp_mult(A, u, v ; warnboth)
Memory efficient and fast implementation of D = A' * exp(-u * v^T)
that is useful for B0-field-corrected MRI image reconstruction.
in:
A [N L]
matrixu [N]
vectorv [M]
vectorwarnboth
warn if both u
and v
are complex; default: true
out:
D [L M]
complex vector: D = A' * exp(-u * v^T)
D_lm = sum_n A_nl^* exp(-u_n v_m)
sourceMIRT.exp_xform
— Methodexp_xform(x, u, v ; mode::Symbol = :matrix)
in:
x [N L]
possibly complex vector(s)u [D N]
possibly complex vectorsv [D M]
possibly complex vectorsmode::Symbol
:matrix
(default) | :element
| :row
| :column
out:
y [M L]
typically complex vector
y[m,l] = sum_n x[n,l] exp(-sum(u[:,n] .* v[:,m]))
Iterates through subsets of the ML matrix designated by :mode
(i.e. row, column, element, or just computing the entire matrix) This is the 'slow' 'exact' transform model for MRI.
Output type will depend on input types.
sourceMIRT.genkspace
— Methodgenkspace
Generate the proper length of k-space trajectory.
It linearly interpolates the output of genspiral
to the correct length()
& takes care of the rotations for the interleaves.
ld
is the length of the datanint
is the number of interleaves
Brad Sutton; University of Michigan
sourceMIRT.genspi
— MethodGx, Gy, kx, ky, sx, sy, gts = genspi(...)
This is translation of C code from scanner: exactly what is played out to gradients at 4us.
multi-shot spiral design uses Duyn's approximate slewrate limited design augmented with archimedian gmax
limit in [args]
D
= FOV; cm
N
= matrix size()
Tmax
= longest acquisition allowed; s
dts
= output sample spacing; s
gtype
= trajectory type()
option [CVs]
nl
= number of interleavesgamp
= design grad max; G/cmgslew
= design slew rate; mT/m/msnramp
= number of rampdown points; default 0
out
Gx; Gy
time is in sec()
- rev 0 12/26/98 original
- rev 1 4/15/99 little better calc of ts
Borrowed from Doug Noll; Univ. of Michigan. Modified to take more input cv's.
sourceMIRT.getindex!
— Methodgetindex!(y::AbstractVector, x::AbstractArray{T,D}, mask::AbstractArray{Bool,D})
Equivalent to the in-place y .= x[mask]
but is non-allocating.
For non-Boolean indexing, just use @views y .= A[index]
, per https://discourse.julialang.org/t/efficient-non-allocating-in-place-getindex-for-bitarray/42268
sourceMIRT.interp1
— Methodyi = interp1(x, y, xi ; how=Gridded(Linear()), extrap=0)
1D interpolation of y = f(x)
at points xi
In:
x::AbstractVector{<:Real}
y::AbstractVector{<:Number}
Option:
how::Interpolations.InterpolationType
default Gridded(Linear())
extrap::Any
how to extrapolate, e.g., Flat()
; default 0
other options from Interpolations.jl are Line()
Periodic()
Reflect()
Throw()
Output is same size as input xi
sourceMIRT.ir_dump
— Methodir_dump(x::Any ; io::IO = stdout)
+ir_dump(io::IO, x::Any)
Show all the fields of a structure or NamedTuple
more nicely than dump() does
sourceMIRT.ir_load_brainweb_t1_256
— Methoddata = ir_load_brainweb_t1_256()
Load brainweb T1-weighted MRI slice of size 256 × 256
.
sourceMIRT.ir_mri_coil_compress
— Method(odata, σ, Vr) = ir_mri_coil_compress(idata ; ncoil)
MRI coil compression via PCA. Given multiple MRI surface coil images (idata), use SVD/PCA to find a smaller number of virtual coil images (odata).
In:
idata
[(N) n_in]
: noisy complex images (2D or 3D) for each coil
Option:
ncoil
Desired # of virtual coils (default: 1)
Out:
odata
[(N) ncoil]
: virtual coil imagesσ
[n_in]
: singular values.Vr
[n_in, ncoil]
: compression matrix for reducing other data.
todo: currently ignores noise correlations
sourceMIRT.ir_mri_kspace_ga_radial
— Methodkspace = ir_mri_kspace_ga_radial(; Nro=?, Nspoke=?, ...)
Generate k-space sampling pattern for "golden angle" radial sampling.
option
Nro:Int
number of samples in each readout/spoke, default 256Nspoke::Int
number of spokes, default 1start::Real
first angle in series [radians], default π/2angle::Real
angular spacing [radians], default GAdelta_ro::Real
readout spacing, default 1/Nro
shift::Real
shift due to gradient delays, default 0- radial sample locations are
ir * delta_ro
- where
ir = [-(Nro/2 - 1):1:Nro/2] + shift
out
kspace
[Nro Nspoke 2]
(Float32)
kx
and ky
k-space locations for Nspoke*Nro
samples in interval (-0.5 0.5]
for default shift
, delta_ro
so default units are "cycles / sample"
2015-07 Mai Le, original Matlab version
2015-07-04 Jeff Fessler, minor changes to Matlab version
sourceMIRT.ir_mri_sensemap_sim
— Method(smap,info) = ir_mri_sensemap_sim( :all ; kwargs)
Like ir_mri_sensemap_sim
but also returns info
with data for all coils, mainly for testing and plotting.
sourceMIRT.ir_mri_sensemap_sim
— Method(smap,info) = ir_mri_sensemap_sim( ir_ic_pair ; kwargs)
Like ir_mri_sensemap_sim
but also returns info
with data for specific coils where ir_ic_pair::Vector{Tuple{Int,Int}}
. (Usually used internally only.)
info::NamedTuple
geometry information for plots
sourceMIRT.ir_mri_sensemap_sim
— Methodsmap = ir_mri_sensemap_sim(...)
Simulate 2D or 3D sensitivity maps for sensitivity-encoded MRI based on grivich:00:tmf http://doi.org/10.1119/1.19461
This code makes maps for multiple coils, but does not model coupling between coils, so most likely it is an approximation at best.
option
dims::Dims
image size; default (64, 64)dx::Real
pixel/voxel dimension; default: 3dy::Real
pixel/voxel dimension; default: dx
dz::Real
""ncoil::Int
# of coils total; default 4nring::Int
# of rings of coils; default 1rcoil::Real
coil radius; default dx * nx / 2 * 0.50
dz_coil
ring spacing in z; default nz*dz/nring
- (3D geometry is a cylinder)
coil_distance::Real
distance of coil center from isocenter- for central ring of coils as a multiple of
FOVx
, - where
FOVx=nx*dx
; default 1.2
orbit::Real
default 360 [degrees]orbit_start::AbstractVector{<:Real} = fill(0, nring)
[degrees]scale::Symbol
:none
(default)
+ ssos_center
make SSoS of center = 1
out
smap [dims ncoil]
simulated sensitivity maps (complex!)
All length parameters must have same units (e.g., mm or cm)
sourceMIRT.ir_mri_sensemap_sim_do
— Method(smap, info) = ir_mri_sensemap_sim_do()
sourceMIRT.ir_mri_smap1
— Methodir_mri_smap1()
based on grivich:00:tmf
for a circular coil in "x-y plane" of radius "a"
Note that coil x-y plane is not same as object x-y plane!
Returns (i,j,k)
components of B vector for each (x,y,z)
location
sourceMIRT.ir_mri_smap_r
— Methodir_mri_smap_r(r, z)
function for testing near 0
sourceMIRT.jinc
— Methodjinc(x)
Return jinc(x) = J1(pi*x)/(2x)
, where J1
is a Bessel function of the first kind.
Units of x
are typically cycles/m.
Return type is promote_type(typeof(x), Float32)
.
sourceMIRT.map_many
— Methody = map_many(fun::Function, x::AbstractArray{<:Any}, idim::Dims)
apply a function fun
to leading slices of input x
; cousin of mapslices
in
fun::Function
maps input of size idim
to output of some size odim
x [idim ldim]
out
y [odim ldim]
Example: if fun
maps array of size (1,2) to array of size (3,4,5) and if input x
has size (1,2,7,8) then output y
will have size (3,4,5,7,8) where y[:,:,:,i,j] = fun(x[:,:,i,j])
sourceMIRT.mask_or
— Methodmask_or(mask)
compress 3D mask to 2D by logical or
along z
direction
sourceMIRT.mask_outline
— Methodmask_outline(mask)
return outer boundary of 2D mask (or mask_or for 3D)
sourceMIRT.maskit
— Methodmaskit(x::AbstractArray{<:Number})
opposite of embed
sourceMIRT.max_percent_diff
— Methodd = max_percent_diff(s1, s2, [options])
Compute the "maximum percent difference" between two signals: s1, s2
.
Default is to normalize by maximum(abs.(s1))
.
options
maxboth::Bool
use max of both arguments to normalize; default false
normalize::Bool
normalize each before comparing; default false
sourceMIRT.mri_kspace_spiral
— Methodkspace, omega, gradxy = mri_kspace_spiral( [options] )
Make k-space spiral trajectory based on GE 3T scanner constraints
Option:
N
dimention of reconstructed imageNt
# of time pointsfov
field of view in cmdt
time sampling interval out; default 5e-6
secgamp::Real
design gradient amplitude max, G/cm; default 2.2gslew::Int
design slew rate, mT/m/ms; default 180
Out:
kspace [Nt,2]
kspace trajectory [kx ky]
in cycles/cm, NO: cycles/FOVomega [Nt,2]
"" in radiansgradxy [Nt 2]
gradient waveforms in (units?)
sourceMIRT.mri_trajectory
— Methodkspace, omega, wi = mri_trajectory( ; ktype, N, fov, arg_wi, kwargs...)
Generate kspace trajectory samples and density compensation functions.
option
ktype::Symbol
k-space trajectory type; default :radial
N::Dims
target image size; default (32,30)fov
field of view in x and y (and z); default (250,250) mmarg_wi
options to pass to ir_mri_density_comp
- not yet donekwargs
options for the specific trajectory
out
kspace [Nk 2|3]
kspace samples in units 1/fovomega [Nk 2|3]
trajectory samples over [-π,π)wi [Nk 1]
(optional) density compensation factors
trajectory types: :cartesian
:radial
:cart_y_2
:random
:half8
:epi_sin
:spiral0 :spiral1 :spiral3
:rosette3
:epi_under
:gads
(emulate golden-angle data sharing per winkelmann:07:aor)
sourceMIRT.mri_trajectory_gads
— Methodomega, wi = mri_trajectory_gads(N, fov ; ...)
emulate 2D golden angle radial sampling with data sharing
option: Nro
# of samples in each readout/spoke shift
shift along read-out due to gradient delays (stress) kmax_frac
fractions of maximum krad (0.5) for rings (annuli) under
under-sampling factor for each annulus
sourceMIRT.mri_trajectory_radial
— Methodmri_trajectory_radial()
option:
na_nr
default ensures proper sampling at edge of k-spacena
angular spokes; default: na_nr * nrnr
radial samples per spokeir
default: 0:nr
todo: generalize to 3D using barger:02:trc
sourceMIRT.mri_trajectory_rosette3
— Methodmri_trajectory_rosette3(N, fov ; ...)
3d rosette, with default parameters from bucholz:08:miw
options: omax: maximum omega nt : time samples (65.536 ms for 4 usec dt) dt : time sample spacing (4 usec) ti : time samples
sourceMIRT.ncg
— Method(x,out) = ncg(B, gradf, curvf, x0 ; ...)
Nonlinear preconditioned conjugate gradient algorithm to minimize a general "inverse problem" cost function of the form $\Psi(x) = \sum_{j=1}^J f_j(B_j x)$ where each function $f_j(v)$ has a quadratic majorizer of the form
\[q_j(v;u) = f_j(u) + \nabla f_j(u) (v - u) + 1/2 \|v - u\|^2_{C_j(u)}\]
where $C_j(u)$ is diagonal matrix of curvatures. (It suffices for each $f_j$ to have a Lipschitz smooth gradient.)
This CG method uses a majorize-minimize (MM) line search.
in
B
array of $J$ blocks $B_1,...,B_J$gradf
array of $J$ functions return gradients of $f_1,...,f_J$curvf
array of $J$ functions z -> curv(z)
that return a scalar
or a vector of curvature values for each element of $z$
x0
initial guess; need length(x) == size(B[j],2)
for $j=1...J$
Usually x0
is a Vector
but it can be an Array
if each B_j
is a linear operator (e.g., LinearMapAO
) of suitable "dimensions".
option
niter
# number of outer iterations; default 50ninner
# number of inner iterations of MM line search; default 5P
# preconditioner; default I
betahow
"beta" method for the search direction; default :dai_yuan
fun
User-defined function to be evaluated with two arguments (x,iter).- It is evaluated at (x0,0) and then after each iteration.
output
x
final iterateout
[niter+1] (fun(x0,0), fun(x1,1), ..., fun(x_niter,niter))
- (all 0 by default). This is an array of length
niter+1
sourceMIRT.ncg
— Method(x,out) = ncg(grad, curv, x0, ...)
special case of ncg
(nonlinear CG) for minimizing a cost function whose gradient is grad(x)
and that has a quadratic majorizer with diagonal Hessian given by curv(x)
. Typically curv = (x) -> L
where L
is the Lipschitz constant of grad
sourceMIRT.ndgrid
— Method(xx,yy,zz) = ndgrid(x::AbstractVector{<:Any}, y::..., z::...)
todo - improve?
sourceMIRT.ndgrid
— Method(xx,yy) = ndgrid(x::AbstractVector{<:Any}, y::AbstractVector{<:Any})
todo - improve?
sourceMIRT.nufft_eltype
— Methodnufft_eltype(::DataType)
ensure plan_nfft eltype is Float32 or Float64
sourceMIRT.nufft_errors
— Methodw, errs = nufft_errors( ; M=?, w=?, N=?, n_shift=?, ...)
Compute NUFFT approximation errors (for signal of length N
of unit norm), for given digital frequency values w
, i.e., Ω.
sourceMIRT.nufft_init
— Methodp = nufft_init(w, N ; nfft_m=4, nfft_sigma=2.0, pi_error=true, n_shift=0)
Setup 1D NUFFT, for computing fast $O(N \log N)$ approximation to
$X[m] = \sum_{n=0}^{N-1} x[n] \exp(-i w[m] (n - n_{shift})), m=1,…,M$
in
w::AbstractArray{<:Real}
[M]
frequency locations (aka Ω, units radians/sample)eltype(w)
determines the plan_nfft
type; so to save memory use Float32!size(w)
determines odim
for A
if operator=true
N::Int
signal length
option
nfft_m::Int
see NFFT.jl documentation; default 4nfft_sigma::Real
"", default 2.0n_shift::Real
often is N/2; default 0pi_error::Bool
throw error if $|w| > π$, default true
- Set to
false
only if you are very sure of what you are doing!
do_many::Bool
support extended inputs via map_many
? default true
operator::Bool=true
set to false
to make A
an LinearMapAM
out
p NamedTuple
(nufft = x -> nufft(x), adjoint = y -> nufft_adj(y), A::LinearMapAO)
The default settings are such that for a 1D signal of length N=512, the worst-case error is below 1e-5 which is probably adequate for typical medical imaging applications. To verify this statement, run nufft_plot1()
and see plot.
sourceMIRT.nufft_init
— Methodp = nufft_init(w, N ; nfft_m=4, nfft_sigma=2.0, pi_error=true, n_shift=?)
Setup multi-dimensional NUFFT, for computing fast $O(N \log N)$ approximation to
$X[m] = \sum_{n=0}^{N-1} x[n] \exp(-i w[m,:] (n - n_{shift})), m=1,…,M$
in
w::AbstractArray{<:Real}
[M,D]
frequency locations (aka Ω, units radians/sample)
+ `eltype(w)` determines the `plan_nfft` type; so to save memory use Float32!
+ `size(w)[1:(end-1)]` determines `odim` if `operator=true`
N::Dims{D}
signal dimensions
option
nfft_m::Int
see NFFT.jl documentation; default 4nfft_sigma::Real
"", default 2.0n_shift::AbstractVector{<:Real}
[D]
often is N/2; default zeros(D)pi_error::Bool
throw error if $|w| > π$, default true
- Set to
false
only if you are very sure of what you are doing!
do_many::Bool
support extended inputs via map_many
? default true
operator::Bool=true
set to false
to make A
an LinearMapAM
The default do_many
option is designed for parallel MRI where the k-space sampling pattern applies to every coil. It may also be useful for dynamic MRI with repeated sampling patterns. The coil and/or time dimensions must come after the spatial dimensions.
out
p NamedTuple
with fields
`nufft = x -> nufft(x), adjoint = y -> nufft_adj(y), A=LinearMapAO`
-(Using `operator=true` allows the `LinearMapAO` to support `do_many`.)
sourceMIRT.nufft_typer
— Methodnufft_typer(T::DataType, x::AbstractArray{<:Real} ; warn::Bool=true)
type conversion wrapper for nfft()
sourceMIRT.ogm_ls
— Method(x,out) = ogm_ls(B, gradf, curvf, x0; niter=?, ninner=?, fun=?)
OGM with a line search; Drori&Taylor @arxiv 1803.05676; to minimize a general "inverse problem" cost function of the form $\Psi(x) = \sum_{j=1}^J f_j(B_j x)$ where each function $f_j(v)$ has a quadratic majorizer of the form
\[q_j(v;u) = f_j(u) + \nabla f_j(u) (v - u) + 1/2 \|v - u\|^2_{C_j(u)}\]
where $C_j(u)$ is diagonal matrix of curvatures. (It suffices for each $f_j$ to have a Lipschitz smooth gradient.)
This OGM method uses a majorize-minimize (MM) line search.
in
B
array of $J$ blocks $B_1,...,B_J$gradf
array of $J$ functions return gradients of $f_1,...,f_J$curvf
array of $J$ functions z -> curv(z)
that return a scalar
or a vector of curvature values for each element of $z$
x0
initial guess; need length(x) == size(B[j],2)
for $j=1...J$
option
niter
# number of outer iterations; default 50ninner
# number of inner iterations of MM line search; default 5fun
User-defined function to be evaluated with two arguments (x,iter).- It is evaluated at (x0,0) and then after each iteration.
output
x
final iterateout
[niter+1] (fun(x0,0), fun(x1,1), ..., fun(x_niter,niter))
- (all 0 by default). This is an array of length
niter+1
sourceMIRT.ogm_ls
— Method(x,out) = ogm_ls(grad, curv, x0, ...)
special case of ogm_ls
(OGM with line search) for minimizing a cost function whose gradient is grad(x)
and that has a quadratic majorizer with diagonal Hessian given by curv(x)
. Typically curv = (x) -> L
where L
is the Lipschitz constant of grad
sourceMIRT.pogm_restart
— Methodx, out = pogm_restart(x0, Fcost, f_grad, f_L ;
+(Using `operator=true` allows the `LinearMapAO` to support `do_many`.)
sourceMIRT.nufft_typer
— Methodnufft_typer(T::DataType, x::AbstractArray{<:Real} ; warn::Bool=true)
type conversion wrapper for nfft()
sourceMIRT.ogm_ls
— Method(x,out) = ogm_ls(B, gradf, curvf, x0; niter=?, ninner=?, fun=?)
OGM with a line search; Drori&Taylor @arxiv 1803.05676; to minimize a general "inverse problem" cost function of the form $\Psi(x) = \sum_{j=1}^J f_j(B_j x)$ where each function $f_j(v)$ has a quadratic majorizer of the form
\[q_j(v;u) = f_j(u) + \nabla f_j(u) (v - u) + 1/2 \|v - u\|^2_{C_j(u)}\]
where $C_j(u)$ is diagonal matrix of curvatures. (It suffices for each $f_j$ to have a Lipschitz smooth gradient.)
This OGM method uses a majorize-minimize (MM) line search.
in
B
array of $J$ blocks $B_1,...,B_J$gradf
array of $J$ functions return gradients of $f_1,...,f_J$curvf
array of $J$ functions z -> curv(z)
that return a scalar
or a vector of curvature values for each element of $z$
x0
initial guess; need length(x) == size(B[j],2)
for $j=1...J$
option
niter
# number of outer iterations; default 50ninner
# number of inner iterations of MM line search; default 5fun
User-defined function to be evaluated with two arguments (x,iter).- It is evaluated at (x0,0) and then after each iteration.
output
x
final iterateout
[niter+1] (fun(x0,0), fun(x1,1), ..., fun(x_niter,niter))
- (all 0 by default). This is an array of length
niter+1
sourceMIRT.ogm_ls
— Method(x,out) = ogm_ls(grad, curv, x0, ...)
special case of ogm_ls
(OGM with line search) for minimizing a cost function whose gradient is grad(x)
and that has a quadratic majorizer with diagonal Hessian given by curv(x)
. Typically curv = (x) -> L
where L
is the Lipschitz constant of grad
sourceMIRT.pogm_restart
— Methodx, out = pogm_restart(x0, Fcost, f_grad, f_L ;
f_mu=0, mom=:pogm, restart=:gr, restart_cutoff=0.,
-bsig=1, niter=10, g_prox=(z,c)->z, fun=...)
Iterative proximal algorithms (PGM=ISTA, FPGM=FISTA, POGM) with restart.
in
x0
initial guessFcost
function for computing the cost function value $F(x)$- (needed only if
restart === :fr
)
f_grad
function for computing the gradient of $f(x)$f_L
Lipschitz constant of the gradient of $f(x)$
option
f_mu
strong convexity parameter of $f(x)$; default 0.- if
f_mu > 0
, $(\alpha, \beta_k, \gamma_k)$ is chosen by Table 1 in [KF18]
g_prox
function g_prox(z,c)
for the proximal operator for $g(x)$g_prox(z,c)
computes $argmin_x 1/2 \|z-x\|^2 + c \, g(x)$
mom
momentum option:pogm
POGM (fastest); default!:fpgm
(FISTA), $\gamma_k = 0$:pgm
PGM (ISTA), $\beta_k = \gamma_k = 0$
restart
restart option:gr
gradient restart; default!:fr
function restart:none
no restart
restart_cutoff
for :gr
restart if cos(angle) < this; default 0.bsig
gradient "gamma" decrease option (value within [0 1]); default 1- see $\bar{\sigma}$ in [KF18]
niter
number of iterations; default 10fun
function(iter, xk, yk, is_restart)
user-defined function evaluated each iter
with secondary xk
, primary yk
, and boolean is_restart
indicating whether this iteration was a restart
out
x
final iterate- for PGM (ISTA): $x_N = y_N$
- for FPGM (FISTA): primary iterate $y_N$
- for POGM: secondary iterate $x_N$, see [KF18]
out [fun(0, x0, x0, false), fun(1, x1, y1, is_restart), ...]
array of length [niter+1]
Optimization Problem: Nonsmooth Composite Convex Minimization
- $argmin_x F(x), F(x) := f(x) + g(x))$
- $f(x)$ smooth convex function
- $g(x)$ convex function, possibly nonsmooth and "proximal-friendly" [CP11]
Optimization Algorithms:
Accelerated First-order Algorithms when $g(x) = 0$ [KF18] iterate as below for given coefficients $(\alpha, \beta_k, \gamma_k)$
- For k = 0,1,...
- $y_{k+1} = x_k - \alpha f'(x_k)$ : gradient update
- $x_{k+1} = y_{k+1} + \beta_k (y_{k+1} - y_k) + \gamma_k (y_{k+1} - x_k)$ : momentum update
Proximal versions of the above for $g(x) \neq 0$ are in the below references, and use the proximal operater $prox_g(z) = argmin_x {1/2\|z-x\|^2 + g(x)}$.
- Proximal Gradient method (PGM or ISTA) - $\beta_k = \gamma_k = 0$. [BT09]
- Fast Proximal Gradient Method (FPGM or FISTA) - $\gamma_k = 0$. [BT09]
- Proximal Optimized Gradient Method (POGM) - [THG15]
- FPGM(FISTA) with Restart - [OC15]
- POGM with Restart - [KF18]
references
- [CP11] P. L. Combettes, J. C. Pesquet,
"Proximal splitting methods in signal processing," Fixed-Point Algorithms for Inverse Problems in Science and Engineering, Springer, Optimization and Its Applications, 2011.
- [KF18] D. Kim, J.A. Fessler,
"Adaptive restart of the optimized gradient method for convex optimization," 2018 Arxiv:1703.04641, [http://doi.org/10.1007/s10957-018-1287-4]
- [BT09] A. Beck, M. Teboulle:
"A fast iterative shrinkage-thresholding algorithm for linear inverse problems," SIAM J. Imaging Sci., 2009.
- [THG15] A.B. Taylor, J.M. Hendrickx, F. Glineur,
"Exact worst-case performance of first-order algorithms for composite convex optimization," Arxiv:1512.07516, 2015, SIAM J. Opt. 2017 [http://doi.org/10.1137/16m108104x]
Copyright 2017-3-31, Donghwan Kim and Jeff Fessler, University of Michigan 2018-08-13 Julia 0.7.0 2019-02-24 interface redesign
sourceMIRT.poweriter
— Methodv1,σ1 = poweriter(A; niter=?, ...)
Determine first right singular vector v1
and first singular value σ1
of A
by applying power iteration to A'A
in
A
M × N matrix
option
niter
default 200x0
initial guess of v1
tol
stopping tolerance for s1, default 1e-6chat::Bool
verbose? default false
out
v1
[N]
principal right singular vectorσ1
spectral norm of A
sourceMIRT.rect
— Methodrect(x::Real)
Unit width rect function. Potential problem? Bring up with fess.
sourceMIRT.reverser
— Methody = reverser(x, dims)
reverse array along specified dimensions (or all if unspecified)
sourceMIRT.rmsd100
— Methodrmsd = rmsd100(x, y ; mask)
Compute 100 * RMSD (root mean squared difference) between x
and y
within domain mask.
in
x
: arrayy
: another array of same size
option:
mask::Array{Bool}
: domain over which to compute the RMSE; default trues(size(x))
out
- rmsd : rmsd of
x
vs y
within mask
in %
sourceMIRT.rotate2d
— Method(xr,yr) = rotate2d(x, y, theta)
2D rotation
sourceMIRT.snr2sigma
— Methodsnr2sigma(db, yb)
Convert SNR in dB to noise σ for complex gaussian noise. No sqrt(2)
factors is needed here because randn(Complex{Float})
already accounts for that. (See randn
documentation.)
sourceSettings
This document was generated with Documenter.jl version 0.27.23 on Tuesday 25 October 2022. Using Julia version 1.8.2.
+bsig=1, niter=10, g_prox=(z,c)->z, fun=...)
Iterative proximal algorithms (PGM=ISTA, FPGM=FISTA, POGM) with restart.
in
x0
initial guessFcost
function for computing the cost function value $F(x)$restart === :fr
)f_grad
function for computing the gradient of $f(x)$f_L
Lipschitz constant of the gradient of $f(x)$option
f_mu
strong convexity parameter of $f(x)$; default 0.f_mu > 0
, $(\alpha, \beta_k, \gamma_k)$ is chosen by Table 1 in [KF18]g_prox
function g_prox(z,c)
for the proximal operator for $g(x)$g_prox(z,c)
computes $argmin_x 1/2 \|z-x\|^2 + c \, g(x)$mom
momentum option:pogm
POGM (fastest); default!:fpgm
(FISTA), $\gamma_k = 0$:pgm
PGM (ISTA), $\beta_k = \gamma_k = 0$restart
restart option:gr
gradient restart; default!:fr
function restart:none
no restartrestart_cutoff
for :gr
restart if cos(angle) < this; default 0.bsig
gradient "gamma" decrease option (value within [0 1]); default 1niter
number of iterations; default 10fun
function(iter, xk, yk, is_restart)
user-defined function evaluated each iter
with secondary xk
, primary yk
, and boolean is_restart
indicating whether this iteration was a restartout
x
final iterateout [fun(0, x0, x0, false), fun(1, x1, y1, is_restart), ...]
array of length [niter+1]
Optimization Problem: Nonsmooth Composite Convex Minimization
Optimization Algorithms:
Accelerated First-order Algorithms when $g(x) = 0$ [KF18] iterate as below for given coefficients $(\alpha, \beta_k, \gamma_k)$
Proximal versions of the above for $g(x) \neq 0$ are in the below references, and use the proximal operater $prox_g(z) = argmin_x {1/2\|z-x\|^2 + g(x)}$.
references
"Proximal splitting methods in signal processing," Fixed-Point Algorithms for Inverse Problems in Science and Engineering, Springer, Optimization and Its Applications, 2011.
"Adaptive restart of the optimized gradient method for convex optimization," 2018 Arxiv:1703.04641, [http://doi.org/10.1007/s10957-018-1287-4]
"A fast iterative shrinkage-thresholding algorithm for linear inverse problems," SIAM J. Imaging Sci., 2009.
"Exact worst-case performance of first-order algorithms for composite convex optimization," Arxiv:1512.07516, 2015, SIAM J. Opt. 2017 [http://doi.org/10.1137/16m108104x]
Copyright 2017-3-31, Donghwan Kim and Jeff Fessler, University of Michigan 2018-08-13 Julia 0.7.0 2019-02-24 interface redesign
MIRT.poweriter
— Methodv1,σ1 = poweriter(A; niter=?, ...)
Determine first right singular vector v1
and first singular value σ1
of A
by applying power iteration to A'A
in
A
M × N matrixoption
niter
default 200x0
initial guess of v1
tol
stopping tolerance for s1, default 1e-6chat::Bool
verbose? default falseout
v1
[N]
principal right singular vectorσ1
spectral norm of A
MIRT.rect
— Methodrect(x::Real)
Unit width rect function. Potential problem? Bring up with fess.
MIRT.reverser
— Methody = reverser(x, dims)
reverse array along specified dimensions (or all if unspecified)
MIRT.rmsd100
— Methodrmsd = rmsd100(x, y ; mask)
Compute 100 * RMSD (root mean squared difference) between x
and y
within domain mask.
in
x
: arrayy
: another array of same sizeoption:
mask::Array{Bool}
: domain over which to compute the RMSE; default trues(size(x))
out
x
vs y
within mask
in %MIRT.rotate2d
— Method(xr,yr) = rotate2d(x, y, theta)
2D rotation
MIRT.snr2sigma
— Methodsnr2sigma(db, yb)
Convert SNR in dB to noise σ for complex gaussian noise. No sqrt(2)
factors is needed here because randn(Complex{Float})
already accounts for that. (See randn
documentation.)
Settings
This document was generated with Documenter.jl version 0.27.23 on Tuesday 25 October 2022. Using Julia version 1.8.2.
Settings
This document was generated with Documenter.jl version 0.27.23 on Tuesday 25 October 2022. Using Julia version 1.8.2.
Settings
This document was generated with Documenter.jl version 0.27.23 on Tuesday 25 October 2022. Using Julia version 1.8.2.
Settings
This document was generated with Documenter.jl version 0.27.23 on Tuesday 25 October 2022. Using Julia version 1.8.2.
Settings
This document was generated with Documenter.jl version 0.27.23 on Tuesday 25 October 2022. Using Julia version 1.8.2.