Optical Transfer Functions

TransferFunctions.RadialOTFType
RadialOTF{N} <: OpticalTransferFunction{N}

If the pupil function of the system is symmetric, the OTF as well as the PSF are radially symmetric which can be used to optimize the calculations.

Implementation

  • attenuation(model::A, fr::Frequency)
  • cutoff(model::A, [a=0]) returning the largest frequency f such that attenuation(model, f) >= a if a > 0 and

attenuation(model, f) > 0 if a = 0.

source
TransferFunctions.otfFunction
otf(tf::OpticalTransferFunction, Δxy::PixelSize{2}, wh::Dims{2})
source
otf(tf::PointSpreadFunction{2}, A::SpatialMatrix; ε=0.01)

Sample an OTF from the transfer function tf for the image A using the energy error ε.

See also psf

julia> tf = AiryDisc{2}(λ=488u"nm", NA=1.4);

julia> A = SpatialMatrix(testimage("mandril_gray"), Δ);

julia> A_otf = otf(tf, A; ε=0.05);
Inclusion of the energy (1 - ε) is not enforced

If the allowed energy error is too small that the sampled PSF does not fit into the array size that is Fourier transformed, then the resulting OTF may not be accurate to the specified error. In that case a warning is printed.

julia> A_otf_bad = otf(tf, SampledArray(ones(5,5), 61u"nm")); # prints a warning

julia> A_otf_bad[1,1] ≈ 1 # OTF should be 1 at the origin but this is not enforced
false

julia> A_otf[1,1] ≈ 1 # For it to be true array `A` must be large enough to hold the PSF with the specified error
true
source

Point Spread Functions

TransferFunctions.psfFunction
psf(tf::PointSpreadFunction, Δ, wh::Dims; normalize=true)

Generate a PSF array size wh for the model tf with the pixel size Δ.

julia> tf = AiryDisc{2}(λ=488u"nm", NA=1.4);

julia> A_psf = psf(tf, 61u"nm", (-3:3, -3:3))
7×7 SampledArray{Float64, Quantity{Int64, 𝐋, Unitful.FreeUnits{(nm,), 𝐋, nothing}}, 2, OffsetArrays.OffsetMatrix{Float64, Matrix{Float64}}, (61 nm, 61 nm)} with indices -3:3×-3:3:
 0.00154644   7.98472e-5  0.000815467  0.00205246  0.000815467  7.98472e-5  0.00154644
 7.98472e-5   0.00416274  0.0194095    0.0291836   0.0194095    0.00416274  7.98472e-5
 0.000815467  0.0194095   0.0602568    0.0836632   0.0602568    0.0194095   0.000815467
 0.00205246   0.0291836   0.0836632    0.1141      0.0836632    0.0291836   0.00205246
 0.000815467  0.0194095   0.0602568    0.0836632   0.0602568    0.0194095   0.000815467
 7.98472e-5   0.00416274  0.0194095    0.0291836   0.0194095    0.00416274  7.98472e-5
 0.00154644   7.98472e-5  0.000815467  0.00205246  0.000815467  7.98472e-5  0.00154644

julia> sum(A_psf) ≈ 1
true
source
psf(tf::PointSpreadFunction{2}, Δ, ε::Real; <kwargs>)

Sample the PSF tf with a pixel size Δ over a window such that the energy error is less than ε.

kwargs are passed to the final psf function.

source
TransferFunctions.FWHMFunction
FWHM(psf::PointSpreadFunction)

Find the FWHM of the PSF psf in the x and y directions.

See also HWHM

julia> tf = IsotropicGaussian(488u"nm", 1.4);

julia> TF.FWHM(tf)
(179.33894905055288 nm, 179.33894905055288 nm, 93.61250264937092 nm)
source
TransferFunctions.HWHMFunction
HWHM(psf::PointSpreadFunction)

Find the HWHM of the PSF psf in all the axes directions.

See also FWHM

julia> tf = AiryDisc(λ=488u"nm", NA=1.4);

julia> TransferFunctions.HWHM(tf)
((-89.66947452527637 nm, 89.66947452527637 nm), (-89.66947452527637 nm, 89.66947452527637 nm), (-147.04617530370933 nm, 147.04617530370933 nm))
source

Non-linear Transfer Functions

TransferFunctions.ImpulseResponseMappingType
ImpulseResponseMapping{2} <: LinearTransferFunction{2}

An impulse response mapping is a description of a transfer function that prescribes an impulse response to every point in the object plane. This may be a point spread function or some other function that prescribes the response to the object plane point in the image plane.

An transfer defined by an impulse response mapping is a linear system, but is not translation invariant hence does not belong to the class of linear transfer functions.

source

Internal Utility Functions and Types

Functions

TransferFunctions.roundupcenterFunction
roundupcenter(A)

Calculate center index of A rounded-up (i.e. fft center).

Examples

julia> TF.roundupcenter(ones(15,15))
CartesianIndex(8, 8)

julia> TF.roundupcenter((16,16))
CartesianIndex(9, 9)
source
TransferFunctions.rounddowncenterFunction
rounddowncenter(A)

Calculate center index of A rounded-down (i.e. ifft center).

Examples

julia> TF.rounddowncenter(ones(15,15))
CartesianIndex(8, 8)

julia> TF.rounddowncenter((16,16))
CartesianIndex(8, 8)
source
TransferFunctions.exactcenterFunction
 exactcenter(A)

Calculate the exact center coordinate of A.

Examples

julia> TF.exactcenter(ones(15,15))
(8.0, 8.0)

julia> TF.exactcenter((16,16))
(8.5, 8.5)
source
TransferFunctions.interiorFunction
interior(inds::Indices{N}, kern::Indices{N})

Return 'valid' indices for convolution of an array with indices inds with a kernel having the indices kern.

source
TransferFunctions.freqgridFunction
freqgrid(s::Size, Δ)

Generate a frequency grid for multidimensional FFTs of the signal of size s with the pixel size Δ (i.e. sampling rate 1/Δ)

julia> x_f, y_f = TF.freqgrid((5,5), 50u"nm");

julia> x_f
5×5 Matrix{Quantity{Float64, 𝐋^-1, Unitful.FreeUnits{(nm^-1,), 𝐋^-1, nothing}}}:
  0.0 nm^-1     0.0 nm^-1     0.0 nm^-1     0.0 nm^-1     0.0 nm^-1
  0.004 nm^-1   0.004 nm^-1   0.004 nm^-1   0.004 nm^-1   0.004 nm^-1
  0.008 nm^-1   0.008 nm^-1   0.008 nm^-1   0.008 nm^-1   0.008 nm^-1
 -0.008 nm^-1  -0.008 nm^-1  -0.008 nm^-1  -0.008 nm^-1  -0.008 nm^-1
 -0.004 nm^-1  -0.004 nm^-1  -0.004 nm^-1  -0.004 nm^-1  -0.004 nm^-1

julia> y_f' == x_f
true

julia> _,_,z_f = TF.freqgrid((4,4,3), (50u"nm", 30u"nm", 15u"nm"));

julia> z_f
4×4×3 Array{Quantity{Float64, 𝐋^-1, Unitful.FreeUnits{(nm^-1,), 𝐋^-1, nothing}}, 3}:
[:, :, 1] =
 0.0 nm^-1  0.0 nm^-1  0.0 nm^-1  0.0 nm^-1
 0.0 nm^-1  0.0 nm^-1  0.0 nm^-1  0.0 nm^-1
 0.0 nm^-1  0.0 nm^-1  0.0 nm^-1  0.0 nm^-1
 0.0 nm^-1  0.0 nm^-1  0.0 nm^-1  0.0 nm^-1

[:, :, 2] =
 0.0222222 nm^-1  0.0222222 nm^-1  0.0222222 nm^-1  0.0222222 nm^-1
 0.0222222 nm^-1  0.0222222 nm^-1  0.0222222 nm^-1  0.0222222 nm^-1
 0.0222222 nm^-1  0.0222222 nm^-1  0.0222222 nm^-1  0.0222222 nm^-1
 0.0222222 nm^-1  0.0222222 nm^-1  0.0222222 nm^-1  0.0222222 nm^-1

[:, :, 3] =
 -0.0222222 nm^-1  -0.0222222 nm^-1  -0.0222222 nm^-1  -0.0222222 nm^-1
 -0.0222222 nm^-1  -0.0222222 nm^-1  -0.0222222 nm^-1  -0.0222222 nm^-1
 -0.0222222 nm^-1  -0.0222222 nm^-1  -0.0222222 nm^-1  -0.0222222 nm^-1
 -0.0222222 nm^-1  -0.0222222 nm^-1  -0.0222222 nm^-1  -0.0222222 nm^-1
source
TransferFunctions.posgridFunction
posgrid(a::Indices, Δ)
posgrid(s::Size, Δ; center=roundupcenter(s))

Generate a position grid for sampled images with the pixel/voxel size Δ.

If a size s is passed generate a position grid with the given size and the center in center. If Δ is a tuple of Lengths then the elements are used for the sampling in the respective dimensions. If Δ is a single length, then it is used for all dimensions.

julia> x_p, y_p = TF.posgrid((-3:5, -1:3), (50u"nm", 20u"nm"));

julia> x_p
9×5 Matrix{Quantity{Int64, 𝐋, Unitful.FreeUnits{(nm,), 𝐋, nothing}}}:
 -150 nm  -150 nm  -150 nm  -150 nm  -150 nm
 -100 nm  -100 nm  -100 nm  -100 nm  -100 nm
  -50 nm   -50 nm   -50 nm   -50 nm   -50 nm
    0 nm     0 nm     0 nm     0 nm     0 nm
   50 nm    50 nm    50 nm    50 nm    50 nm
  100 nm   100 nm   100 nm   100 nm   100 nm
  150 nm   150 nm   150 nm   150 nm   150 nm
  200 nm   200 nm   200 nm   200 nm   200 nm
  250 nm   250 nm   250 nm   250 nm   250 nm

julia> y_p
9×5 Matrix{Quantity{Int64, 𝐋, Unitful.FreeUnits{(nm,), 𝐋, nothing}}}:
 -20 nm  0 nm  20 nm  40 nm  60 nm
 -20 nm  0 nm  20 nm  40 nm  60 nm
 -20 nm  0 nm  20 nm  40 nm  60 nm
 -20 nm  0 nm  20 nm  40 nm  60 nm
 -20 nm  0 nm  20 nm  40 nm  60 nm
 -20 nm  0 nm  20 nm  40 nm  60 nm
 -20 nm  0 nm  20 nm  40 nm  60 nm
 -20 nm  0 nm  20 nm  40 nm  60 nm
 -20 nm  0 nm  20 nm  40 nm  60 nm

julia> TF.posgrid((3,3,3), 50u"nm")[3]
3×3×3 Array{Quantity{Int64, 𝐋, Unitful.FreeUnits{(nm,), 𝐋, nothing}}, 3}:
[:, :, 1] =
 -50 nm  -50 nm  -50 nm
 -50 nm  -50 nm  -50 nm
 -50 nm  -50 nm  -50 nm

[:, :, 2] =
 0 nm  0 nm  0 nm
 0 nm  0 nm  0 nm
 0 nm  0 nm  0 nm

[:, :, 3] =
 50 nm  50 nm  50 nm
 50 nm  50 nm  50 nm
 50 nm  50 nm  50 nm
source
TransferFunctions.posaxesFunction
posaxes(a::SampledArray)

Returns the positions of the axes of samples in a.

See also posgrid

julia> sa = SampledArray(reshape(1:16, (4,4)), 61u"nm");

julia> TF.posaxes(sa)
((61:61:244) nm, (61:61:244) nm)

julia> TF.posgrid(sa)[1]
4×4 Matrix{Quantity{Int64, 𝐋, Unitful.FreeUnits{(nm,), 𝐋, nothing}}}:
  61 nm   61 nm   61 nm   61 nm
 122 nm  122 nm  122 nm  122 nm
 183 nm  183 nm  183 nm  183 nm
 244 nm  244 nm  244 nm  244 nm
source
TransferFunctions.fillsizeFunction
fillsize(Δ::Length, N::Integer) => PixelSize{N}

Construct a PixelSize with the same sampling Δ in every direction.

source
TransferFunctions.inner_axesFunction
inner_axes(A, edges)
inner_axes(A, K)

Determine the inner axes of the array with edges edges or when filtered with kernel K.

See also outer_axes.

julia> TF.inner_axes(ones(100,100), ((2,4), (1,10)))
(3:96, 2:90)

julia> TF.inner_axes(ones(100,100), OAs.OffsetArray(ones(11,11), -5:5, -3:7))
(6:95, 4:93)
source

Type Aliases

Unit Types

TransferFunctions.FrequencyType
TransferFunctions.Frequency{T, U}

A supertype for quantities and levels of dimension Unitful.𝐋 ^ -1 with a value of type T and units U.

See also: Unitful.Quantity, Unitful.Level.

source
TransferFunctions.FrequencyUnitsType
TransferFunctions.FrequencyUnits{U}

A supertype for units of dimension Unitful.𝐋 ^ -1. Equivalent to Unitful.Units{U, Unitful.𝐋 ^ -1}.

See also: Unitful.Units.

source
TransferFunctions.FrequencyFreeUnitsType
TransferFunctions.FrequencyFreeUnits{U}

A supertype for Unitful.FreeUnits of dimension Unitful.𝐋 ^ -1. Equivalent to Unitful.FreeUnits{U, Unitful.𝐋 ^ -1}.

source