Spectrum

Working with HyperSpectrum objects

HyperSpectrum{T<:Real, N, NP} <: AbstractArray{Spectrum{T}, N} represents an N-dimensional array of Spectrum{T} which share common properties. N = 1 represents a line scan, N = 2 represents a spectrum image, N = 3 can represent a slice-and-view type hyperspectrum cube or a time series of spectrum images. Higher N are also possible.

To construct an empty HyperSpectrum use

hs = HyperSpectrum(
    energy::EnergyScale,
    props::Dict{Symbol,Any},
    dims::Tuple,
    depth::Int,
    type::Type{<:Real};
    axisnames = ( "Y", "X", "Z", "A", "B", "C" ), 
    fov = ( 1.0, 1.0, 1.0, 1.0, 1.0, 1.0 ),
    offset = ( 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 ), #
    stagemap::Type{<:StageMapping}=DefaultStageMapping
)

To construct a HyperSpectrum from an existing array of (N+1) dimensions. The first dimension is the channel data like (ch, Y, X, ...)

hs = HyperSpectrum(
    energy::EnergyScale, 
    props::Dict{Symbol,Any}, 
    arr::Array{<:Real};
    axisnames = ( "Y", "X", "Z", "A", "B", "C" ), #
    fov = [ 1.0, 1.0, 1.0, 1.0, 1.0, 1.0 ], #
    offset = zeros(length(fov)), #
    stagemap::Type{<:StageMapping}=DefaultStageMapping, #
    livetime=fill(get(props, :LiveTime, 1.0), size(arr)[2:end]...)
)

We will assume a 2D hyperspectrum ("spectrum image") for these examples.

The Spectrum representing individual pixels in a HyperSpectrum are accessed using

hs[10,20]  # access the 10th row, 20th column

To index energy planes within the HyperSpectrum you can use

plane(
    hss::HyperSpectrum{T, N, NP},
    chs::AbstractUnitRange{<:Integer},
    normalize = false,
)

which sums over chs and optionally normalizes to the brightest pixel. Alternatively,

plane(
    hss::HyperSpectrum{T, N, NP},
    cxr::CharXRay,
    normalize = false,
)

will extract one FWHM centered on cxr. Like plane(hss,n"Fe K-L3").

To extract HyperSpectrum data items representing regions from the HyperSpectrum

hs[10:20,20:30] # extract a HyperSpectrum representing the 10th to 20th row and 20th to 30th columns.
hs[10:2:20,20:2:30] # extract a HyperSpectrum representing every other pixel in the 10th to 20th row and 20th to 30th columns.

To extract a linescan from within a 2D HyperSpectrum

linescan(hss::HyperSpectrum{T,2,3}, ci1::CartesianIndex{2}, ci2::CartesianIndex{2}, width::Int=1)

Mostly, a HyperSpectrum acts like an Array{Spectrum} and you can view and process the individual spectra this way. However, this is often inefficient as a new Spectrum datum must be allocated each coordinate. There are functions designed to operate more efficiently on the channel data.

sum(hs) # Produce a sum spectrum
maxpixel(hs) # produce a Bright's max-pixel spectrum

To find out which pixel contains the max-pixel for each channel in the HyperSpectrum

indexofmaxpixel(hss::HyperSpectrum) # An array of CartesianIndices
indexofmaxpixel(hss::HyperSpectrum, ch::Int) # A CartesianIndices for channel `ch`

To visualize planes within the HyperSpectrum as images

hss[n"Fe K-L3"]  # A FWHM ROI around the Fe K-L3 transition
roiimage(hss::HyperSpectrum, chs::AbstractUnitRange{<:Integer})

For an RGB image of up to three lines

colorize(hss::HyperSpectrum, cxrs::AbstractVector{CharXRay}, normalize=:All)
colorize(hs, [ n"Fe K-L3", n"Si K-L3", n"Al K-L3" ])

Quantifying HyperSpectra is like quantifying spectra. There is a specialization of fit_spectrum(...) and quantify(...) optimized for hyper-spectra.

fit_spectra(
    hs::HyperSpectrum,
    ffp::FilterFitPacket{S, T};
    mode::Symbol = :Fast[|:Intermediate|:Full]
    zero = x -> max(Base.zero(T), x),
    sigma = Base.zero(T)
)::Array{KRatios}

:Fast uses a highly optimized but less precise algorithm that works for up to approximately 15 to 20 elements. :Intermediate and :Full perform the slower weighted filtered least-square fit. :Intermediate sets k-ratios less than zero to zero but doesn't refit, while :Full removes k-ratios that are less than zero and refits.

To convert the Array{KRatios} from fit_spectra to Array{Material}

NeXLMatrixCorrection.quantify(
    measured::AbstractVector{<:KRatios};
    mc::Type{<:MatrixCorrection} = XPP,
    fc::Type{<:FluorescenceCorrection} = NullFluorescence,
    cc::Type{<:CoatingCorrection} = NullCoating,
    kro::KRatioOptimizer = SimpleKRatioOptimizer(1.5),
    coating::Union{Nothing, Pair{CharXRay, <:Material}}=nothing
)