• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

kunzaatko / TransferFunctions.jl / 16896616505

12 Aug 2025 01:38AM UTC coverage: 76.226%. Remained the same
16896616505

push

github

kunzaatko
fix: Rename LinearTransferFunction -> LinearShiftInvariantTransferFunction

0 of 3 new or added lines in 2 files covered. (0.0%)

404 of 530 relevant lines covered (76.23%)

160737.66 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

23.53
/src/psf/point-spread-function.jl
1
using InterfaceFunctions
2
using Roots
3
using TransferFunctions.Apodization
4

5
"""
6
    PointSpreadFunction <: LinearShiftInvariantTransferFunction
7
A point spread function is a description of a transfer functions specifying the intensity transfer of a single point
8
source in the object plane into a region of the image plane.
9

10
# Implementation
11
To create a new Point spread function (PSF) `A <: PointSpreadFunction`, you must define the __intensity__ at a given
12
[length](@extref Unitful `Length`) coordinate `intensity(psf::A, x::Length, y::Length)`.
13
"""
14
abstract type PointSpreadFunction <: LinearShiftInvariantTransferFunction end
15
Broadcast.broadcastable(tf::PointSpreadFunction) = Ref(tf)
15✔
16

17
"""
18
    intensity(psf::PointSpreadFunction, x::Length, y::Length)
19
The intensity of a `PSF` at a given location.
20
"""
21
@interface intensity(psf::PointSpreadFunction, ::Length, ::Length)
22
@interface Base.maximum(psf::PointSpreadFunction) = intensity(psf, 0u"nm", 0u"nm")
×
23

24
"""
25
    FWHM(psf::PointSpreadFunction)
26
Find the FWHM of the PSF `psf` in the x and y directions.
27
```jldoctest
28
julia> tf = TransferFunctions.BornWolf(λ=488u"nm", NA=1.4)
29
BornWolf{Float64}(488.0 nm, 1.4, 1.3333333333333333)
30

31
julia> TransferFunctions.FWHM(tf)
32
((-119.55929936703521 nm, 119.55929936703521 nm), (-119.55929936703521 nm, 119.55929936703521 nm))
33
``` 
34
"""
35
@interface function FWHM(psf::PointSpreadFunction)
×
36
    max = maximum(psf)
×
37
    x_fwhm_right = find_zero(x -> intensity(psf, x * 1u"nm", 0u"nm") - max / 2, (0.0, Inf)) * 1u"nm"
×
38
    x_fwhm_left = find_zero(x -> intensity(psf, x * 1u"nm", 0u"nm") - max / 2, (-Inf, 0.0)) * 1u"nm"
×
39
    y_fwhm_right = find_zero(y -> intensity(psf, 0u"nm", y * 1u"nm") - max / 2, (0.0, Inf)) * 1u"nm"
×
40
    y_fwhm_left = find_zero(y -> intensity(psf, 0u"nm", y * 1u"nm") - max / 2, (-Inf, 0.0)) * 1u"nm"
×
41
    return ((x_fwhm_left, x_fwhm_right), (y_fwhm_left, y_fwhm_right))
×
42
end
43

44
"""
45
    psf(tf::PointSpreadFunction, Δ::PixelSize{2}, wh::Dims{2})
46
Generate a PSF array size `wh` for the model `tf` with  the pixel size `Δ`.
47
"""
48
psf(
15✔
49
    tf::PointSpreadFunction,
50
    Δ::PixelSize{2},
51
    wh::Dims{2}
52
) = OriginAt(roundupcenter(wh))(intensity.(tf, posgrid(wh, Δ)...))
53
psf(tf::PointSpreadFunction, Δ::Length, wh::Dims{2}) = psf(tf, fillsize(Δ, 2), wh)
10✔
54

55
"""
56
    conv(tf::PointSpreadFunction, img::SpatialArray{<:Real,2}, [args...]; <kwargs>)
57
Convolve the image `img` with the PSF `tf`. Additional arguments are passed to `imfilter`.
58

59
# Keyword arguments
60
- `border=nothing` If the border is a `NamedTuple` with the keys `border` of a type compatible with
61
[`BorderArray`](@extref) and `apodization` of type [`Apodization.ApodizationFunction`](@ref), the border is applied to the image
62
with the size of the FWHM of the PSF in the corresponding directions with the `border` and `apodization` used for edge
63
tapering ([`taperedges`](@ref))) and the full expanded array is returned.
64
"""
65
function conv(tf::PointSpreadFunction, img::SpatialArray{<:Real,2}, args...; border=nothing)
×
66
    Δ = sampling(img)
×
67
    if border == true
×
68
        border = (border=:fill, apodization=Apodization.Cosine())
×
69
    end
70
    if border !== nothing
×
71
        @assert border isa NamedTuple && [:border, :apodization] ⊆ keys(border) "`border` must be a NamedTuple with keys `border` and `apodization`."
×
72
        border_widths = map(FWHM(tf), sampling(img)) do fwhm, Δ
×
73
            px_widths = fwhm ./ Δ
×
74
            abs.((floor(Int, px_widths[1]), ceil(Int, px_widths[1])))
×
75
        end
76
        img = taperedges(border.apodization, img, border_widths, border.border)
×
77
    end
78
    # FIX: I would like the SpatialArray to the be outer wrapper type <30-07-25> 
79
    psf_array = psf(tf, Δ, 2 .* size(img))
×
80
    psf_array ./= sum(psf_array)
×
NEW
81
    return conv(img, psf_array)
×
82
end
83
deconv(tf::PointSpreadFunction, img::SpatialArray) = _wiener_deconv(fft(psf(tf, sampling(img), size(img))), img.parent)
×
84

85
"""
86
    ModelPSF <: PointSpreadFunction 
87
""" # TODO: Docs <24-04-25> 
88
abstract type ModelPSF <: PointSpreadFunction end
89
"""
90
    fit(::ModelPSF, ::SpatialArray)
91
""" # TODO: Docs <24-04-25> 
92
fit(::ModelPSF, ::SpatialArray) = error("TODO")
×
93

94
"""
95
    RadialPSF <: ModelPSF
96
""" # TODO: Docs <24-04-25> 
97
abstract type RadialPSF <: ModelPSF end
98
@interface intensity(psf::RadialPSF, ::Length)
99
intensity(psf::RadialPSF, x::Length, y::Length) = intensity(psf, hypot(x, y))
3,932,168✔
100

101
function FWHM(psf::RadialPSF)
3✔
102
    max = maximum(psf)
3✔
103
    r_fwhm = find_zero(x -> intensity(psf, x * 1u"nm") - max / 2, (0.0, Inf)) * 1u"nm"
198✔
104
    return ((-r_fwhm, r_fwhm), (-r_fwhm, r_fwhm))
3✔
105
end
106

107
"""
108
    MeasuredPSF <: PointSpreadFunction
109
""" # TODO: Docs <24-04-25> 
110
struct MeasuredPSF{T<:PointSpreadFunction} <: PointSpreadFunction
111
    psf::T
112
    function MeasuredPSF(psf::T) where {T<:PointSpreadFunction}
×
113
        psf isa MeasuredPSF && return psf
×
114
        return new{T}(T)
×
115
    end
116
end
117

118
include("./psf-array.jl")
119

120
# Models
121
include("./gibson-lanni.jl")
122
include("./born-wolf.jl")
123

124
include("./estimation.jl")
125

126
export intensity, psf
127
export BornWolf, GibsonLanni, PSFArray
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc