Interface

This section introduces the abstract types we need to implement for our reconstruction package and how they relate to interface and types of AbstractImageReconstruction.jl.

Abstract Types

We start by defining the abstract types we need to implement for our reconstruction package. AbstractImageReconstruction.jl provides two abstract types:

abstract type AbstractImageReconstructionAlgorithm end
abstract type AbstractImageReconstructionParameters end

AbstractImageReconstructionAlgorithms represent a given reconstruction algorithm, while AbstractImageReconstructionParameters represent the parameters an algorithm was constructed with. Once constructed, algorithms can be used to reconstruct images repeatly and idealy without unecessary recomputations.

For our package we extend these abstract types with our own abstract subtypes:

using AbstractImageReconstruction
abstract type AbstractRadonAlgorithm <: AbstractImageReconstructionAlgorithm end
abstract type AbstractRadonParameters <: AbstractImageReconstructionParameters end

Later on we will have parameters that are shared between different algorithms and parameters for different processings steps of a reconstruction. In our case we will have preprocessing parameters and reconstruction parameters. For these we introduce the following abstract types:

abstract type AbstractRadonPreprocessingParameters <: AbstractRadonParameters end
abstract type AbstractRadonReconstructionParameters <: AbstractRadonParameters end

Since we want to implement both direct and iterative methods for our reconstruction, we introduce the following abstract types:

abstract type AbstractDirectRadonAlgorithm <: AbstractRadonAlgorithm end
abstract type AbstractIterativeRadonAlgorithm <: AbstractRadonAlgorithm end

Internal Interface

Reconstruction algorithms in AbstractImageReconstruction.jl are expected to be implemented in the form of distinct processing steps, implemented in their own process methods. The process function takes an algorithm, parameters, and inputs and returns the result of the processing step. If no function is defined for an instance of an algorithm, the default implementation is called. This method tries to call the function process with the type of the algorithm:

process(algo::AbstractImageReconstructionAlgorithm, param::AbstractImageReconstructionParameters, inputs...) = process(typeof(algo), param, inputs...)

The implementation of reconstruction algorithms is therefore expected to either implement the process function for the algorithm type or for the instance. Dispatch on instances allow an instance to change its state, while dispatch on types allows for pure helper functions.

A process itself can invoke other process functions to enable multiple processing steps and generally have arbitarry control flow. It is not required to implement a straight-foward pipeline. We will see this later when we implementd our algorithms.

Let's define a preprocessing step that we can share between our algorithms. We want to allow the user to select certain frames from a time series and average them. We will use the @kwdef macro to provide constructor with keyword arguments and default values

using Statistics
Base.@kwdef struct RadonPreprocessingParameters <: AbstractRadonPreprocessingParameters
  frames::Vector{Int64} = []
  numAverages::Int64 = 1
end
function AbstractImageReconstruction.process(::Type{<:AbstractRadonAlgorithm}, params::RadonPreprocessingParameters, data::AbstractArray{T, 4}) where {T}
  frames = isempty(params.frames) ? (1:size(data, 4)) : params.frames
  data = data[:, :, :, frames]

  if params.numAverages > 1
    data = reshape(data, size(data)[1:3]..., params.numAverage, :)
    data = dropdims(mean(data, dims = 4), dims = 4)
  end

  return data
end

User Interface

A user of our package should be able to reconstruct images by calling the reconstruct function. This function takes an algorithm and an input and returns the reconstructed image. Internally, the reconstruct function calls the put! and take! functions of the algorithm to pass the input and retrieve the output. Algorithms must implement these functions and are expected to have FIFO behavior.


This page was generated using Literate.jl.