diff --git a/dev/API/index.html b/dev/API/index.html index 581c77a2..aa1578ec 100644 --- a/dev/API/index.html +++ b/dev/API/index.html @@ -1,2 +1,2 @@ -API · Julia MRI Package

API

This page contains documentation of the public API of MRIReco. In the Julia REPL one can access this documentation by entering the help mode with ? and then writing the function for which the documentation should be shown.

Operators

Operators are implemented as subtypes of AbstractLinearOperator, which is defined in the package LinearOperators.jl. Such operators must provide a function implementing the product and a function implementing the product with the adjoint. Furthermore, the number of rows and columns of the operator must be specified.

Missing docstring.

Missing docstring for MRIReco.encodingOps2d_simple. Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.encodingOps3d_simple. Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.encodingOps2d_parallel. Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.encodingOps3d_parallel. Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.encodingOp2d_multiEcho. Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.encodingOp3d_multiEcho. Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.encodingOp2d_multiEcho_parallel. Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.encodingOp3d_multiEcho_parallel. Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.fourierEncodingOp2d. Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.fourierEncodingOp3d. Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.ExplicitOp(shape::NTuple{D,Int64}, tr::Trajectory, correctionmap::Array{ComplexF64,D}; MRIReco.echoImage::Bool=false, kargs...) where D. Check Documenter's build log for details.

Missing docstring.

Missing docstring for RegularizedLeastSquares.FFTOp(T::Type, shape::Tuple, shift=true). Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.NFFTOp(shape::Tuple, tr::Trajectory; nodes=nothing, kargs...). Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.FieldmapNFFTOp(shape::NTuple{D,Int64}, tr::Trajectory, correctionmap::Array{ComplexF64,D}; method::String="nfft", echoImage::Bool=true, alpha::Float64=1.75, m::Float64=3.0, K=20, kargs...) where D. Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.SamplingOp. Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.SensitivityOp. Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.SparseOp. Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.RegularizedLeastSquares.WeightingOp. Check Documenter's build log for details.

Datatypes

Missing docstring.

Missing docstring for MRIReco.AcquisitionData. Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.AcquisitionData(tr::T,kdata::Array{Matrix{ComplexF64},3} ; seqInfo=Dict{Symbol,Any}() , idx=nothing , encodingSize=Int64[0,0,0] , fov=Float64[0,0,0] , kargs...) where T <: Union{Trajectory,Vector{Trajectory}}. Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.trajectory(acqData::AcquisitionData,i::Int64=1). Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.numContrasts(acqData::AcquisitionData). Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.numChannels. Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.numSlices. Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.numRepetitions. Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.kData. Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.multiEchoData. Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.multiCoilData. Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.multiCoilMultiEchoData. Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.profileData. Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.samplingDensity. Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.changeEncodingSize2D. Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.convert3dTo2d. Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.RawAcquisitionData. Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.trajectory(f::RawAcquisitionData; slice::Int=1, contrast::Int=1). Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.rawdata(f::RawAcquisitionData). Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.AcquisitionData(f::RawAcquisitionData). Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.RawAcquisitionData(f::ISMRMRDFile, dataset="dataset"). Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.AcquisitionData(f::ISMRMRDFile, dataset="dataset"). Check Documenter's build log for details.

Trajectories

Missing docstring.

Missing docstring for MRIReco.Trajectory. Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.trajectory(trajName::AbstractString, numProfiles::Int, numSamplingPerProfile::Int; MRIReco.numSlices::Int64=1, TE::Float64=0.0, AQ::Float64=1.e-3, kargs...). Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.string(tr::Trajectory). Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.echoTime(tr::Trajectory). Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.acqTimePerProfile(tr::Trajectory). Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.numProfiles(tr::Trajectory). Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.numSamplingPerProfile(tr::Trajectory). Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.numSlices(tr::Trajectory). Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.isCircular(tr::Trajectory). Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.isCartesian(tr::Trajectory). Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.dims(tr::Trajectory). Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.kspaceNodes(tr::Trajectory). Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.readoutTimes(tr::Trajectory). Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.CartesianTrajectory. Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.EPITrajectory. Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.OneLine2dTrajectory. Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.RadialTrajectory. Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.SpiralTrajectory. Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.SpiralTrajectoryVarDens. Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.CartesianTrajectory3D. Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.KooshballTrajectory. Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.StackOfStarsTrajectory. Check Documenter's build log for details.

Sequences

Missing docstring.

Missing docstring for MRIReco.MESequence. Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.numContrasts(seq::MESequence). Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.echoTimes(seq::MESequence). Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.flipAngles(seq::MESequence). Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.echoAmplitudes(seq::MESequence, R1::Float64, R2::Float64, numStates=nothing). Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.epgAmplitudes(seq::MESequence, R1::Real, R2::Real, numStates=nothing). Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.epgRotation. Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.epgRelaxation. Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.epgDephasing. Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.rfRotation. Check Documenter's build log for details.

Sampling

Missing docstring.

Missing docstring for MRIReco.sample. Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.sample_kspace(data::AbstractArray,redFac::Float64,patFunc::AbstractString;kargs...). Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.sample_kspace(acqData::AcquisitionData,redFac::Float64, patFunc::AbstractString; rand=true, profiles=true, seed = 1234, kargs...). Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.sample_regular(shape::Tuple, redFac::Float64; kargs...). Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.sample_random(shape::Tuple{Int64,Int64},redFac::Float64;calsize::Int64=0,kargs...). Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.sample_poissondisk(shape::Tuple{Int64,Int64},redFac::Float64;calsize::Int64=0, seed::Int64=1234,kargs...). Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.sample_vdpoisson(shape::Tuple{Int64,Int64},redFac::Float64; seed::Int64=1234,kargs...). Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.sample_lines(shape::Tuple{Int64,Int64},redFac::Float64;sampleFunc="random",kargs...). Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.calculateIncoherence(acqData::AcquisitionData, recoParams::Dict, slice=1). Check Documenter's build log for details.

Simulation

Missing docstring.

Missing docstring for MRIReco.simulation(image::Array{T,3}, simParams::Dict) where T<:Union{ComplexF64,Float64}. Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.simulation(image::Array{T,3}, simParams::Dict, filename::String; force=false) where T<:Union{ComplexF64,Float64}. Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.simulation(image::Array{T,2}, simParams::Dict) where T<:Union{ComplexF64,Float64}. Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.simulation(tr::Trajectory , image::Array{ComplexF64} , correctionMap = [] ; opName="fast" , senseMaps=[] , verbose=true , kargs...). Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.simulation(seq::AbstractSequence, tr::Vector{Trajectory} , image::Array{ComplexF64,3} ; opName="fast" , r1map=[] , r2map=[] , fmap=[] , senseMaps=[] , verbose=true , kargs...). Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.addNoise(x::Vector, snr::Float64, complex= true). Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.addNoise(acqData::AcquisitionData, snr::Float64). Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.addNoise!(acqData::AcquisitionData, snr::Float64). Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.birdcageSensitivity. Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.quadraticFieldmap. Check Documenter's build log for details.

Reconstruction

MRIReco.reconstructionMethod
reconstruction(acqData::AcquisitionData, recoParams::Dict)

Performs image reconstruction of an AcquisitionData object. Parameters are specified in a dictionary.

Reconstruction types are specified by the symbol :reco. Valid reconstruction names are:

  • :direct - direct Fourier reconstruction
  • :standard - iterative reconstruction for all contrasts, coils & slices independently
  • :multiEcho - iterative joint reconstruction of all echo images
  • :multiCoil - SENSE-type iterative reconstruction
  • :multiCoilMultiEcho - SENSE-type iterative reconstruction of all echo images
source
MRIReco.reconstructionMethod
reconstruction(acqData::AcquisitionData, recoParams::Dict,filename::String; force=false)

performs the same image reconstrucion as reconstruction(acqData::AcquisitionData, recoParams::Dict) and saves the image in a file with name filename. If force=false, the reconstructed image is loaded from the the file filename if the latter is present.

source
MRIReco.setupIterativeRecoFunction
setupIterativeReco(acqData::AcquisitionData, recoParams::Dict)

builds relevant parameters and operators from the entries in recoParams

relevant parameters

  • reconSize::NTuple{2,Int64} - size of image to reconstruct
  • weights::Vector{Vector{Complex{<:AbstractFloat}}} - sampling density of the trajectories in acqData
  • sparseTrafo::AbstractLinearOperator - sparsifying transformation
  • reg::Regularization - Regularization to be used
  • normalize::Bool - adjust regularization parameter according to the size of k-space data
  • solvername::String - name of the solver to use
  • senseMaps::Array{Complex{<:AbstractFloat}} - coil sensitivities
  • correctionMap::Array{Complex{<:AbstractFloat}} - fieldmap for the correction of off-resonance effects
  • method::String="nfft" - method to use for time-segmentation when correctio field inhomogeneities

sparseTrafo and reg can also be speficied using their names in form of a string.

source
Missing docstring.

Missing docstring for MRIReco.reconstruction_direct_2d. Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.reconstruction_direct_3d. Check Documenter's build log for details.

MRIReco.reconstruction_simpleFunction

Performs iterative image reconstruction independently for the data of all coils, contrasts and slices

Arguments

  • acqData::AcquisitionData - AcquisitionData object
  • reconSize::NTuple{2,Int64} - size of image to reconstruct
  • reg::Regularization - Regularization to be used
  • sparseTrafo::AbstractLinearOperator - sparsifying transformation
  • weights::Vector{Vector{Complex{<:AbstractFloat}}} - sampling density of the trajectories in acqData
  • solvername::String - name of the solver to use
  • (normalize::Bool=false) - adjust regularization parameter according to the size of k-space data
  • (params::Dict{Symbol,Any}) - Dict with additional parameters
source
MRIReco.reconstruction_multiEchoFunction

Performs a iterative image reconstruction jointly for all contrasts. Different slices and coil images are reconstructed independently.

Arguments

  • acqData::AcquisitionData - AcquisitionData object
  • reconSize::NTuple{2,Int64} - size of image to reconstruct
  • reg::Regularization - Regularization to be used
  • sparseTrafo::AbstractLinearOperator - sparsifying transformation
  • weights::Vector{Vector{Complex{<:AbstractFloat}}} - sampling density of the trajectories in acqData
  • solvername::String - name of the solver to use
  • (normalize::Bool=false) - adjust regularization parameter according to the size of k-space data
  • (params::Dict{Symbol,Any}) - Dict with additional parameters
source
MRIReco.reconstruction_multiCoilFunction

Performs a SENSE-type iterative image reconstruction. Different slices and contrasts images are reconstructed independently.

Arguments

  • acqData::AcquisitionData - AcquisitionData object
  • reconSize::NTuple{2,Int64} - size of image to reconstruct
  • reg::Regularization - Regularization to be used
  • sparseTrafo::AbstractLinearOperator - sparsifying transformation
  • weights::Vector{Vector{Complex{<:AbstractFloat}}} - sampling density of the trajectories in acqData
  • solvername::String - name of the solver to use
  • senseMaps::Array{Complex{<:AbstractFloat}} - coil sensitivities
  • (normalize::Bool=false) - adjust regularization parameter according to the size of k-space data
  • (params::Dict{Symbol,Any}) - Dict with additional parameters
source
MRIReco.reconstruction_multiCoilMultiEchoFunction

Performs a SENSE-type iterative image reconstruction which reconstructs all contrasts jointly. Different slices are reconstructed independently.

Arguments

  • acqData::AcquisitionData - AcquisitionData object
  • reconSize::NTuple{2,Int64} - size of image to reconstruct
  • reg::Regularization - Regularization to be used
  • sparseTrafo::AbstractLinearOperator - sparsifying transformation
  • weights::Vector{Vector{Complex{<:AbstractFloat}}} - sampling density of the trajectories in acqData
  • solvername::String - name of the solver to use
  • senseMaps::Array{Complex{<:AbstractFloat}} - coil sensitivities
  • (normalize::Bool=false) - adjust regularization parameter according to the size of k-space data
  • (params::Dict{Symbol,Any}) - Dict with additional parameters
source
Missing docstring.

Missing docstring for MRIReco.espirit. Check Documenter's build log for details.

MRIReco.nrmsdFunction
nrmsd(I,Ireco)

computes the normalized root mean squared error of the image Ireco with respect to the image I.

source
+API · Julia MRI Package

API

This page contains documentation of the public API of MRIReco. In the Julia REPL one can access this documentation by entering the help mode with ? and then writing the function for which the documentation should be shown.

Operators

Operators are implemented as subtypes of AbstractLinearOperator, which is defined in the package LinearOperators.jl. Such operators must provide a function implementing the product and a function implementing the product with the adjoint. Furthermore, the number of rows and columns of the operator must be specified.

Missing docstring.

Missing docstring for MRIReco.encodingOps2d_simple. Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.encodingOps3d_simple. Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.encodingOps2d_parallel. Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.encodingOps3d_parallel. Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.encodingOp2d_multiEcho. Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.encodingOp3d_multiEcho. Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.encodingOp2d_multiEcho_parallel. Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.encodingOp3d_multiEcho_parallel. Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.fourierEncodingOp2d. Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.fourierEncodingOp3d. Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.ExplicitOp(shape::NTuple{D,Int64}, tr::Trajectory, correctionmap::Array{ComplexF64,D}; MRIReco.echoImage::Bool=false, kargs...) where D. Check Documenter's build log for details.

Missing docstring.

Missing docstring for RegularizedLeastSquares.FFTOp(T::Type, shape::Tuple, shift=true). Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.NFFTOp(shape::Tuple, tr::Trajectory; nodes=nothing, kargs...). Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.FieldmapNFFTOp(shape::NTuple{D,Int64}, tr::Trajectory, correctionmap::Array{ComplexF64,D}; method::String="nfft", echoImage::Bool=true, alpha::Float64=1.75, m::Float64=3.0, K=20, kargs...) where D. Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.SamplingOp. Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.SensitivityOp. Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.SparseOp. Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.RegularizedLeastSquares.WeightingOp. Check Documenter's build log for details.

Datatypes

Missing docstring.

Missing docstring for MRIReco.AcquisitionData. Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.AcquisitionData(tr::T,kdata::Array{Matrix{ComplexF64},3} ; seqInfo=Dict{Symbol,Any}() , idx=nothing , encodingSize=Int64[0,0,0] , fov=Float64[0,0,0] , kargs...) where T <: Union{Trajectory,Vector{Trajectory}}. Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.trajectory(acqData::AcquisitionData,i::Int64=1). Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.numContrasts(acqData::AcquisitionData). Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.numChannels. Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.numSlices. Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.numRepetitions. Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.kData. Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.multiEchoData. Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.multiCoilData. Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.multiCoilMultiEchoData. Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.profileData. Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.samplingDensity. Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.changeEncodingSize2D. Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.convert3dTo2d. Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.RawAcquisitionData. Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.trajectory(f::RawAcquisitionData; slice::Int=1, contrast::Int=1). Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.rawdata(f::RawAcquisitionData). Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.AcquisitionData(f::RawAcquisitionData). Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.RawAcquisitionData(f::ISMRMRDFile, dataset="dataset"). Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.AcquisitionData(f::ISMRMRDFile, dataset="dataset"). Check Documenter's build log for details.

Trajectories

Missing docstring.

Missing docstring for MRIReco.Trajectory. Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.trajectory(trajName::AbstractString, numProfiles::Int, numSamplingPerProfile::Int; MRIReco.numSlices::Int64=1, TE::Float64=0.0, AQ::Float64=1.e-3, kargs...). Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.string(tr::Trajectory). Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.echoTime(tr::Trajectory). Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.acqTimePerProfile(tr::Trajectory). Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.numProfiles(tr::Trajectory). Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.numSamplingPerProfile(tr::Trajectory). Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.numSlices(tr::Trajectory). Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.isCircular(tr::Trajectory). Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.isCartesian(tr::Trajectory). Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.dims(tr::Trajectory). Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.kspaceNodes(tr::Trajectory). Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.readoutTimes(tr::Trajectory). Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.CartesianTrajectory. Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.EPITrajectory. Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.OneLine2dTrajectory. Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.RadialTrajectory. Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.SpiralTrajectory. Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.SpiralTrajectoryVarDens. Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.CartesianTrajectory3D. Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.KooshballTrajectory. Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.StackOfStarsTrajectory. Check Documenter's build log for details.

Sequences

Missing docstring.

Missing docstring for MRIReco.MESequence. Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.numContrasts(seq::MESequence). Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.echoTimes(seq::MESequence). Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.flipAngles(seq::MESequence). Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.echoAmplitudes(seq::MESequence, R1::Float64, R2::Float64, numStates=nothing). Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.epgAmplitudes(seq::MESequence, R1::Real, R2::Real, numStates=nothing). Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.epgRotation. Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.epgRelaxation. Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.epgDephasing. Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.rfRotation. Check Documenter's build log for details.

Sampling

Missing docstring.

Missing docstring for MRIReco.sample. Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.sample_kspace(data::AbstractArray,redFac::Float64,patFunc::AbstractString;kargs...). Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.sample_kspace(acqData::AcquisitionData,redFac::Float64, patFunc::AbstractString; rand=true, profiles=true, seed = 1234, kargs...). Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.sample_regular(shape::Tuple, redFac::Float64; kargs...). Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.sample_random(shape::Tuple{Int64,Int64},redFac::Float64;calsize::Int64=0,kargs...). Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.sample_poissondisk(shape::Tuple{Int64,Int64},redFac::Float64;calsize::Int64=0, seed::Int64=1234,kargs...). Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.sample_vdpoisson(shape::Tuple{Int64,Int64},redFac::Float64; seed::Int64=1234,kargs...). Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.sample_lines(shape::Tuple{Int64,Int64},redFac::Float64;sampleFunc="random",kargs...). Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.calculateIncoherence(acqData::AcquisitionData, recoParams::Dict, slice=1). Check Documenter's build log for details.

Simulation

Missing docstring.

Missing docstring for MRIReco.simulation(image::Array{T,3}, simParams::Dict) where T<:Union{ComplexF64,Float64}. Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.simulation(image::Array{T,3}, simParams::Dict, filename::String; force=false) where T<:Union{ComplexF64,Float64}. Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.simulation(image::Array{T,2}, simParams::Dict) where T<:Union{ComplexF64,Float64}. Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.simulation(tr::Trajectory , image::Array{ComplexF64} , correctionMap = [] ; opName="fast" , senseMaps=[] , verbose=true , kargs...). Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.simulation(seq::AbstractSequence, tr::Vector{Trajectory} , image::Array{ComplexF64,3} ; opName="fast" , r1map=[] , r2map=[] , fmap=[] , senseMaps=[] , verbose=true , kargs...). Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.addNoise(x::Vector, snr::Float64, complex= true). Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.addNoise(acqData::AcquisitionData, snr::Float64). Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.addNoise!(acqData::AcquisitionData, snr::Float64). Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.birdcageSensitivity. Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.quadraticFieldmap. Check Documenter's build log for details.

Reconstruction

MRIReco.reconstructionMethod
reconstruction(acqData::AcquisitionData, recoParams::Dict)

Performs image reconstruction of an AcquisitionData object. Parameters are specified in a dictionary.

Reconstruction types are specified by the symbol :reco. Valid reconstruction names are:

  • :direct - direct Fourier reconstruction
  • :standard - iterative reconstruction for all contrasts, coils & slices independently
  • :multiEcho - iterative joint reconstruction of all echo images
  • :multiCoil - SENSE-type iterative reconstruction
  • :multiCoilMultiEcho - SENSE-type iterative reconstruction of all echo images
source
MRIReco.reconstructionMethod
reconstruction(acqData::AcquisitionData, recoParams::Dict,filename::String; force=false)

performs the same image reconstrucion as reconstruction(acqData::AcquisitionData, recoParams::Dict) and saves the image in a file with name filename. If force=false, the reconstructed image is loaded from the the file filename if the latter is present.

source
MRIReco.setupIterativeRecoFunction
setupIterativeReco(acqData::AcquisitionData, recoParams::Dict)

builds relevant parameters and operators from the entries in recoParams

relevant parameters

  • reconSize::NTuple{2,Int64} - size of image to reconstruct
  • weights::Vector{Vector{Complex{<:AbstractFloat}}} - sampling density of the trajectories in acqData
  • sparseTrafo::AbstractLinearOperator - sparsifying transformation
  • reg::Regularization - Regularization to be used
  • normalize::Bool - adjust regularization parameter according to the size of k-space data
  • solvername::String - name of the solver to use
  • senseMaps::Array{Complex{<:AbstractFloat}} - coil sensitivities
  • correctionMap::Array{Complex{<:AbstractFloat}} - fieldmap for the correction of off-resonance effects
  • method::String="nfft" - method to use for time-segmentation when correctio field inhomogeneities
  • noiseData::Array{ComplexF64} - noise acquisition for noise decorelation

sparseTrafo and reg can also be speficied using their names in form of a string.

source
Missing docstring.

Missing docstring for MRIReco.reconstruction_direct_2d. Check Documenter's build log for details.

Missing docstring.

Missing docstring for MRIReco.reconstruction_direct_3d. Check Documenter's build log for details.

MRIReco.reconstruction_simpleFunction

Performs iterative image reconstruction independently for the data of all coils, contrasts and slices

Arguments

  • acqData::AcquisitionData - AcquisitionData object
  • reconSize::NTuple{2,Int64} - size of image to reconstruct
  • reg::Regularization - Regularization to be used
  • sparseTrafo::AbstractLinearOperator - sparsifying transformation
  • weights::Vector{Vector{Complex{<:AbstractFloat}}} - sampling density of the trajectories in acqData
  • solvername::String - name of the solver to use
  • (normalize::Bool=false) - adjust regularization parameter according to the size of k-space data
  • (params::Dict{Symbol,Any}) - Dict with additional parameters
source
MRIReco.reconstruction_multiEchoFunction

Performs a iterative image reconstruction jointly for all contrasts. Different slices and coil images are reconstructed independently.

Arguments

  • acqData::AcquisitionData - AcquisitionData object
  • reconSize::NTuple{2,Int64} - size of image to reconstruct
  • reg::Regularization - Regularization to be used
  • sparseTrafo::AbstractLinearOperator - sparsifying transformation
  • weights::Vector{Vector{Complex{<:AbstractFloat}}} - sampling density of the trajectories in acqData
  • solvername::String - name of the solver to use
  • (normalize::Bool=false) - adjust regularization parameter according to the size of k-space data
  • (params::Dict{Symbol,Any}) - Dict with additional parameters
source
MRIReco.reconstruction_multiCoilFunction

Performs a SENSE-type iterative image reconstruction. Different slices and contrasts images are reconstructed independently.

Arguments

  • acqData::AcquisitionData - AcquisitionData object
  • reconSize::NTuple{2,Int64} - size of image to reconstruct
  • reg::Regularization - Regularization to be used
  • sparseTrafo::AbstractLinearOperator - sparsifying transformation
  • weights::Vector{Vector{Complex{<:AbstractFloat}}} - sampling density of the trajectories in acqData
  • L_inv::Array{Complex{<:AbstractFloat}} - noise decorrelation matrix
  • solvername::String - name of the solver to use
  • senseMaps::Array{Complex{<:AbstractFloat}} - coil sensitivities
  • (normalize::Bool=false) - adjust regularization parameter according to the size of k-space data
  • (params::Dict{Symbol,Any}) - Dict with additional parameters
source
MRIReco.reconstruction_multiCoilMultiEchoFunction

Performs a SENSE-type iterative image reconstruction which reconstructs all contrasts jointly. Different slices are reconstructed independently.

Arguments

  • acqData::AcquisitionData - AcquisitionData object
  • reconSize::NTuple{2,Int64} - size of image to reconstruct
  • reg::Regularization - Regularization to be used
  • sparseTrafo::AbstractLinearOperator - sparsifying transformation
  • weights::Vector{Vector{Complex{<:AbstractFloat}}} - sampling density of the trajectories in acqData
  • solvername::String - name of the solver to use
  • senseMaps::Array{Complex{<:AbstractFloat}} - coil sensitivities
  • (normalize::Bool=false) - adjust regularization parameter according to the size of k-space data
  • (params::Dict{Symbol,Any}) - Dict with additional parameters
source
Missing docstring.

Missing docstring for MRIReco.espirit. Check Documenter's build log for details.

MRIReco.nrmsdFunction
nrmsd(I,Ireco)

computes the normalized root mean squared error of the image Ireco with respect to the image I.

source
diff --git a/dev/SENSE/index.html b/dev/SENSE/index.html index c9eb7199..a714bbf5 100644 --- a/dev/SENSE/index.html +++ b/dev/SENSE/index.html @@ -31,4 +31,4 @@ # do reconstruction Ireco = reconstruction(acqData, params) -

Below one can see the orignal phantom on the left and the reconstruction on the right:

Phantom Reconstruction

+

Below one can see the orignal phantom on the left and the reconstruction on the right:

Phantom Reconstruction

diff --git a/dev/acquisitionData/index.html b/dev/acquisitionData/index.html index f990c843..68487f8c 100644 --- a/dev/acquisitionData/index.html +++ b/dev/acquisitionData/index.html @@ -13,4 +13,4 @@ subsampleIndices::Vector{Array{Int64}} encodingSize::Vector{Int64} fov::Vector{Float64} -end

It consists of the sequence informations stored in a dictionary, the k-space trajectory, the k-space data, and several parameters describing the dimension of the data and some additional index vectors.

The k-space data kdata has three dimensions encoding

  1. dim : contrasts/echoes
  2. dim : slices
  3. dim : repetitions

Each element is a matrix encoding

  1. dim : k-space nodes
  2. dim : channels/coils

In case of undersampled data, the subsampling indices are stored in subsampleIndices. One check if the data is undersampled by checking if isempty(subsampleIndices).

The encoded space is stored in the field encodingSize. It is especially relevant for non-Cartesian trajectories where it is not clear upfront, how large the grid size for reconstruction should be chosen. Finally fov describes the physical lengths of the encoding grid.

+end

It consists of the sequence informations stored in a dictionary, the k-space trajectory, the k-space data, and several parameters describing the dimension of the data and some additional index vectors.

The k-space data kdata has three dimensions encoding

  1. dim : contrasts/echoes
  2. dim : slices
  3. dim : repetitions

Each element is a matrix encoding

  1. dim : k-space nodes
  2. dim : channels/coils

In case of undersampled data, the subsampling indices are stored in subsampleIndices. One check if the data is undersampled by checking if isempty(subsampleIndices).

The encoded space is stored in the field encodingSize. It is especially relevant for non-Cartesian trajectories where it is not clear upfront, how large the grid size for reconstruction should be chosen. Finally fov describes the physical lengths of the encoding grid.

diff --git a/dev/compressedSensing/index.html b/dev/compressedSensing/index.html index 5e37974d..0371efd3 100644 --- a/dev/compressedSensing/index.html +++ b/dev/compressedSensing/index.html @@ -36,4 +36,4 @@ params[:tolInner] = 1.e-2 params[:normalizeReg] = true -img_tv = reconstruction(acqDataSub, params)

Lets compare the results, left the regular SENSE reconstruction and right the TV reglarized solution:

SENSE TV

+img_tv = reconstruction(acqDataSub, params)

Lets compare the results, left the regular SENSE reconstruction and right the TV reglarized solution:

SENSE TV

diff --git a/dev/custom/index.html b/dev/custom/index.html index b60ab36e..d8566ac1 100644 --- a/dev/custom/index.html +++ b/dev/custom/index.html @@ -64,4 +64,4 @@ img_d = reconstruction(acqData,params)

For comparison, let us perform the same reconstruction as above but with a Wavelet transform

delete!(params, :sparseTrafo)
 params[:sparseTrafoName] = "Wavelet"
 
-img_w = reconstruction(acqData,params)

The following pictures shows the wavelet based CS reconstruction on the left and the dictionary based CS reconstruction on the right:

BrainWavelet BrainDict

For reference, the original data is shown here:

BrainOrig

One can clearly see that the dictionary approach performs better than a simple Wavelet L1 prior.

+img_w = reconstruction(acqData,params)

The following pictures shows the wavelet based CS reconstruction on the left and the dictionary based CS reconstruction on the right:

BrainWavelet BrainDict

For reference, the original data is shown here:

BrainOrig

One can clearly see that the dictionary approach performs better than a simple Wavelet L1 prior.

diff --git a/dev/filehandling/index.html b/dev/filehandling/index.html index 6800a7dd..0bafb75e 100644 --- a/dev/filehandling/index.html +++ b/dev/filehandling/index.html @@ -9,4 +9,4 @@ save(fout, raw)

which will generate an ISMRMRD file containing the data.

Conversion

It should now be no surprise that MRIReco.jl does also allow for file conversion:

f = BrukerFile("brukerfileCart")
 raw = RawAcquisitionData(f)
 fout = ISMRMRDFile("outputfile.h5")
-save(fout, raw)

Currently, this is only limited to converting Bruker files into ISMRMRD files but the infrastructure is not limited to that.

+save(fout, raw)

Currently, this is only limited to converting Bruker files into ISMRMRD files but the infrastructure is not limited to that.

diff --git a/dev/generated/examples/01-binning/index.html b/dev/generated/examples/01-binning/index.html index 44d1e502..60961a00 100644 --- a/dev/generated/examples/01-binning/index.html +++ b/dev/generated/examples/01-binning/index.html @@ -38,7 +38,7 @@ size(Ireco)

let's show the results for first bin

plot_im2D(abs.(Ireco[:,:,1,1]),title = "First bin")

and the second bin

plot_im2D(abs.(Ireco[:,:,1,2]),title = "Second bin")

As expected we have more streaking artifacts on the first bin because we reconstruct the image with less projections.

Reproducibility

This page was generated with the following version of Julia:

io = IOBuffer();
 versioninfo(io);
 split(String(take!(io)), '\n')

And with the following package versions

import Pkg; Pkg.status()
Status `~/work/MRIReco.jl/MRIReco.jl/docs/Project.toml`
-  [13f3f980] CairoMakie v0.10.1
+  [13f3f980] CairoMakie v0.10.2
 ⌃ [e30172f5] Documenter v0.25.2
   [8ad4436d] ImageUtils v0.2.9
   [98b081ad] Literate v2.14.0
@@ -49,4 +49,4 @@
   [bdf86e05] MRIReco v0.7.1 `~/work/MRIReco.jl/MRIReco.jl`
   [9be66c26] MRISampling v0.1.1
   [8988da37] MRISimulation v0.1.1
-Info Packages marked with ⌃ have new versions available and may be upgradable.

This page was generated using Literate.jl.

+Info Packages marked with ⌃ have new versions available and may be upgradable.

This page was generated using Literate.jl.

diff --git a/dev/gettingStarted/index.html b/dev/gettingStarted/index.html index 46cc2ff2..79283131 100644 --- a/dev/gettingStarted/index.html +++ b/dev/gettingStarted/index.html @@ -17,4 +17,4 @@ params = Dict{Symbol, Any}() params[:reco] = "direct" params[:reconSize] = (N,N) -Ireco = reconstruction(acqData, params)

We will go through the program step by step. First we create a 2D shepp logan phantom of size N=256. Then we setup a dictionary that defines the simulation parameters. Here, we chose a simple radial trajectory with 402 spokes and 512 samples per profile. We use a gridding-based simulator by setting params[:simulation] = "fast"

After setting up the parameter dictionary params, the simulation is performed by calling

acqData = simulation(I, params)

The result simulation function outputs an acquisition object that is discussed in more detail in the section Acquisition Data. The acquisition data can also be stored to or loaded from a file, which will be discussed in section File Handling.

Using the acquisition data we can perform a reconstruction. To this end, again a parameter dictionary is setup and some basic configuration is done. In this case, for instance we specify that we want to apply a simple NFFT-based gridding reconstruction. The reconstruction is invoked by calling

Ireco = reconstruction(acqData, params)

The resulting image is of type AxisArray and has 5 dimensions. One can display the image object by calling

imshow(abs.(Ireco[:,:,1,1,1]))

Alternatively one can store the image into a file, which will be discussed in the section on Images.

The original phantom and the reconstructed image are shown below

Phantom Reconstruction

We will discuss reconstruction in more detail in the sections on Offresonance Correction, Parallel Imaging, and Compressed Sensing

+Ireco = reconstruction(acqData, params)

We will go through the program step by step. First we create a 2D shepp logan phantom of size N=256. Then we setup a dictionary that defines the simulation parameters. Here, we chose a simple radial trajectory with 402 spokes and 512 samples per profile. We use a gridding-based simulator by setting params[:simulation] = "fast"

After setting up the parameter dictionary params, the simulation is performed by calling

acqData = simulation(I, params)

The result simulation function outputs an acquisition object that is discussed in more detail in the section Acquisition Data. The acquisition data can also be stored to or loaded from a file, which will be discussed in section File Handling.

Using the acquisition data we can perform a reconstruction. To this end, again a parameter dictionary is setup and some basic configuration is done. In this case, for instance we specify that we want to apply a simple NFFT-based gridding reconstruction. The reconstruction is invoked by calling

Ireco = reconstruction(acqData, params)

The resulting image is of type AxisArray and has 5 dimensions. One can display the image object by calling

imshow(abs.(Ireco[:,:,1,1,1]))

Alternatively one can store the image into a file, which will be discussed in the section on Images.

The original phantom and the reconstructed image are shown below

Phantom Reconstruction

We will discuss reconstruction in more detail in the sections on Offresonance Correction, Parallel Imaging, and Compressed Sensing

diff --git a/dev/image/index.html b/dev/image/index.html index 087f68e8..a8f48eaa 100644 --- a/dev/image/index.html +++ b/dev/image/index.html @@ -1,2 +1,2 @@ -Images · Julia MRI Package

Images

All reconstructed data is stored as an AxisArray. The AxisArrays package is part of the Images package family, which groups all image processing related functionality together. We note that the term Image does not restrict the dimensionality of the data types to 2D but in fact images can be of arbitrary dimensionality.

The reconstructed MRI image I is an AxisArray and has five dimensions. The first three are the spatial dimension x, y, and z, whereas dimension four encodes the number of echos that have been reconstructed, while dimension five encodes individual coils that may have been reconstructed independently. By using an AxisArray the object does not only consist of the data but it additionally encodes the physical size of the image as well as the echo times. To extract the ordinary Julia array one can simply use Ireco.data.

The advantage of encoding the physical dimensions is the image data can be stored without loosing the dimensions of the data. For instance one can call

saveImage(filename, I)

to store the image and

I = loadImage(filename)

to load the image. Currently, MRIReco does support the NIfTI file format. By default, saveImage stores the data complex valued if the image I is complex valued. To store the magnitude image one can call

saveImage(filename, I, true)
+Images · Julia MRI Package

Images

All reconstructed data is stored as an AxisArray. The AxisArrays package is part of the Images package family, which groups all image processing related functionality together. We note that the term Image does not restrict the dimensionality of the data types to 2D but in fact images can be of arbitrary dimensionality.

The reconstructed MRI image I is an AxisArray and has five dimensions. The first three are the spatial dimension x, y, and z, whereas dimension four encodes the number of echos that have been reconstructed, while dimension five encodes individual coils that may have been reconstructed independently. By using an AxisArray the object does not only consist of the data but it additionally encodes the physical size of the image as well as the echo times. To extract the ordinary Julia array one can simply use Ireco.data.

The advantage of encoding the physical dimensions is the image data can be stored without loosing the dimensions of the data. For instance one can call

saveImage(filename, I)

to store the image and

I = loadImage(filename)

to load the image. Currently, MRIReco does support the NIfTI file format. By default, saveImage stores the data complex valued if the image I is complex valued. To store the magnitude image one can call

saveImage(filename, I, true)
diff --git a/dev/index.html b/dev/index.html index f3c59573..2eca606d 100644 --- a/dev/index.html +++ b/dev/index.html @@ -1,2 +1,2 @@ -Home · Julia MRI Package

MRIReco.jl

Magnetic Resonance Imaging Reconstruction

Introduction

MRIReco is a Julia packet for magnetic resonance imaging. It contains algorithms for the simulation and reconstruction of MRT data and is both easy to use and flexibly expandable.

Both direct and iterative methods are available for image reconstruction. In particular, modern compressed sensing algorithms such as ADMM can be used.

The MRT imaging operator can be set up for a variety of scanning patterns (cartesian, spiral, radial, ...) and can take into account field inhomogeneity as well as the use of coil arrays. The operator can be quickly evaluated using NFFT-based methods.

One strength of the package is that it is strongly modular and uses high quality Julia packages. These are e.g.

  • NFFT.jl and FFTW.jl for fast Fourier transformations
  • Wavelets.jl for sparsification
  • LinearOperators.jl in order to be able to divide the imaging operator modularly into individual parts
  • RegularizedLeastSquares.jl for modern algorithms for solving linear optimization problems

This interaction allows new algorithms to be easily integrated into the software framework. It is not necessary to program in C/C++ but the advantages of the scientific high-level language Julia can be used.

Note

MRIReco.jl is work in progress and in some parts not entirely optimized. In particular the FFT and NFFT implementation are currently limited to the CPU and do not support GPU acceleration yet.

Installation

Start julia and open the package mode by entering ]. Then enter

add MRIReco

This will install MRIReco and all its dependencies. If you want to develop MRIReco itself you can checkout MRIReco by calling

dev MRIReco

More information on how to develop a package can be found in the Julia documentation.

Plotting

On purpose MRIReco is not depending on a particular plotting package since there are various plotting packages in the Julia ecosystem. Within the examples outlined in the tutorial we will use PyPlot for plotting but you may prefer using the Plots package. You can add both packages the same way MRIReco has been added.

Tutorial

There is a Jupyter-based tutorial on MRIReco at

https://github.com/MagneticResonanceImaging/MRIRecoTutorial

that has been presented at the ISMRM conference in Montreal 2019. Since the API has slightly changed, we, however recommend that you read this documentation and in particular execute the example scripts as is described in the Getting Started section.

+Home · Julia MRI Package

MRIReco.jl

Magnetic Resonance Imaging Reconstruction

Introduction

MRIReco is a Julia packet for magnetic resonance imaging. It contains algorithms for the simulation and reconstruction of MRT data and is both easy to use and flexibly expandable.

Both direct and iterative methods are available for image reconstruction. In particular, modern compressed sensing algorithms such as ADMM can be used.

The MRT imaging operator can be set up for a variety of scanning patterns (cartesian, spiral, radial, ...) and can take into account field inhomogeneity as well as the use of coil arrays. The operator can be quickly evaluated using NFFT-based methods.

One strength of the package is that it is strongly modular and uses high quality Julia packages. These are e.g.

  • NFFT.jl and FFTW.jl for fast Fourier transformations
  • Wavelets.jl for sparsification
  • LinearOperators.jl in order to be able to divide the imaging operator modularly into individual parts
  • RegularizedLeastSquares.jl for modern algorithms for solving linear optimization problems

This interaction allows new algorithms to be easily integrated into the software framework. It is not necessary to program in C/C++ but the advantages of the scientific high-level language Julia can be used.

Note

MRIReco.jl is work in progress and in some parts not entirely optimized. In particular the FFT and NFFT implementation are currently limited to the CPU and do not support GPU acceleration yet.

Installation

Start julia and open the package mode by entering ]. Then enter

add MRIReco

This will install MRIReco and all its dependencies. If you want to develop MRIReco itself you can checkout MRIReco by calling

dev MRIReco

More information on how to develop a package can be found in the Julia documentation.

Plotting

On purpose MRIReco is not depending on a particular plotting package since there are various plotting packages in the Julia ecosystem. Within the examples outlined in the tutorial we will use PyPlot for plotting but you may prefer using the Plots package. You can add both packages the same way MRIReco has been added.

Tutorial

There is a Jupyter-based tutorial on MRIReco at

https://github.com/MagneticResonanceImaging/MRIRecoTutorial

that has been presented at the ISMRM conference in Montreal 2019. Since the API has slightly changed, we, however recommend that you read this documentation and in particular execute the example scripts as is described in the Getting Started section.

diff --git a/dev/offresonance/index.html b/dev/offresonance/index.html index df9b0394..5afc73ce 100644 --- a/dev/offresonance/index.html +++ b/dev/offresonance/index.html @@ -29,4 +29,4 @@ params[:K] = 28 # do reconstruction -Ireco = reconstruction(acqData, params)

The considered quadratic fieldmap looks like this:

Fieldmap

The reconstruction without and with offresonance correction are shown below:

NoCorrection Reconstruction

+Ireco = reconstruction(acqData, params)

The considered quadratic fieldmap looks like this:

Fieldmap

The reconstruction without and with offresonance correction are shown below:

NoCorrection Reconstruction

diff --git a/dev/operators/index.html b/dev/operators/index.html index 07bcbd0b..cd81aae5 100644 --- a/dev/operators/index.html +++ b/dev/operators/index.html @@ -1,2 +1,2 @@ -Imaging Operators · Julia MRI Package

Imaging Operators

The mapping between the proton density and the recorded signal is linear in MRI and can be described in the continuous case as an integral equation and in the discrete case as a matrix vector multiplication.

Depending on the imaging scenario, the MRI system matrix can have various different forms. It may encode a Cartesian, or a spiral trajectory. It may take offresonance into account, and it may also encode the sensitivity of the receive coil.

MRIReco implements various MRI imaging operators. In all cases, the operators have a dedicated Julia type that acts as a matrix. The operator E thus can be applied to a vector x by calling E*x. Similarly, the adjoint can be applied by adjoint(E)*x. We note at this point that the adjoint operation is lazy in Julia and thus the matrix adjoint(E) is never explicitly arranged.

MRIReco currently implements the following operators:

  • FFTOp: A multidimensional FFT operator
  • NFFTOp: A multidimensional operator for non-equidistant FFTs
  • FieldmapNFFTOp: An operator that takes complex correction terms into account
  • SensitivityMapOp: An operator for building a SENSE reconstruction. Has to be combined with one of the former encoding operators
  • SamplingOp: An operator that describes the (sub)sampling of full trajectories. The operator is used for Compressed Sensing reconstruction
  • WaveletOp: A multidimensional operator for applying Wavelet transformations

Each of these operators can be build by calling the corresponding constructor. Alternatively one can use the EncodingOp constructor that allows for high-level construction of the imaging operator.

+Imaging Operators · Julia MRI Package

Imaging Operators

The mapping between the proton density and the recorded signal is linear in MRI and can be described in the continuous case as an integral equation and in the discrete case as a matrix vector multiplication.

Depending on the imaging scenario, the MRI system matrix can have various different forms. It may encode a Cartesian, or a spiral trajectory. It may take offresonance into account, and it may also encode the sensitivity of the receive coil.

MRIReco implements various MRI imaging operators. In all cases, the operators have a dedicated Julia type that acts as a matrix. The operator E thus can be applied to a vector x by calling E*x. Similarly, the adjoint can be applied by adjoint(E)*x. We note at this point that the adjoint operation is lazy in Julia and thus the matrix adjoint(E) is never explicitly arranged.

MRIReco currently implements the following operators:

  • FFTOp: A multidimensional FFT operator
  • NFFTOp: A multidimensional operator for non-equidistant FFTs
  • FieldmapNFFTOp: An operator that takes complex correction terms into account
  • SensitivityMapOp: An operator for building a SENSE reconstruction. Has to be combined with one of the former encoding operators
  • SamplingOp: An operator that describes the (sub)sampling of full trajectories. The operator is used for Compressed Sensing reconstruction
  • WaveletOp: A multidimensional operator for applying Wavelet transformations

Each of these operators can be build by calling the corresponding constructor. Alternatively one can use the EncodingOp constructor that allows for high-level construction of the imaging operator.

diff --git a/dev/overview/index.html b/dev/overview/index.html index 82aceeb0..66859bdb 100644 --- a/dev/overview/index.html +++ b/dev/overview/index.html @@ -1,2 +1,2 @@ -Overview · Julia MRI Package

Overview

As outlined in the introduction MRIReco.jl MRIReco has the philosophy to to reuse functionality provided by other Julia package and basically add the MRI specific functionality. This approach is enabled by the Julia package manager that can handle all dependencies automatically. Packages are therefore considered to be cheap in Julia so that modularization can be done across packages. In the following graph, the most important (not all) dependencies of MRIReco are visualized.

Dependencies

Most importantly, all iterative solvers are implemented in RegularizedLeastSquares.jl so that MRIReco can benefit from all improvements made in that package. Gridding is implemented in the NFFT.jl package, which has many applications byond MRI. Sparsifying transformations are usually also not MRI specific and therefore implemented in independent packages (e.g. Wavelets.jl). For storing image data MRIReco.jl uses NiFTI.jl. Dicom data can potentially be saved by the DICOM.jl package, which, however, is not a hard dependency of MRIReco.

Data Types and Flow

An overview about the most important data types and the data flow during recosntruction is given in the following figure.

DataFlow

Raw data is usually obtained from files (discussed in File Handling). Since the data layout of the RawAcquisitionData object is not perfectly suited for reconstruction, we

+Overview · Julia MRI Package

Overview

As outlined in the introduction MRIReco.jl MRIReco has the philosophy to to reuse functionality provided by other Julia package and basically add the MRI specific functionality. This approach is enabled by the Julia package manager that can handle all dependencies automatically. Packages are therefore considered to be cheap in Julia so that modularization can be done across packages. In the following graph, the most important (not all) dependencies of MRIReco are visualized.

Dependencies

Most importantly, all iterative solvers are implemented in RegularizedLeastSquares.jl so that MRIReco can benefit from all improvements made in that package. Gridding is implemented in the NFFT.jl package, which has many applications byond MRI. Sparsifying transformations are usually also not MRI specific and therefore implemented in independent packages (e.g. Wavelets.jl). For storing image data MRIReco.jl uses NiFTI.jl. Dicom data can potentially be saved by the DICOM.jl package, which, however, is not a hard dependency of MRIReco.

Data Types and Flow

An overview about the most important data types and the data flow during recosntruction is given in the following figure.

DataFlow

Raw data is usually obtained from files (discussed in File Handling). Since the data layout of the RawAcquisitionData object is not perfectly suited for reconstruction, we

diff --git a/dev/search/index.html b/dev/search/index.html index 07880a01..c448b7cc 100644 --- a/dev/search/index.html +++ b/dev/search/index.html @@ -1,2 +1,2 @@ -Search · Julia MRI Package

Loading search...

    +Search · Julia MRI Package

    Loading search...

      diff --git a/dev/search_index.js b/dev/search_index.js index 62794e98..274c35fb 100644 --- a/dev/search_index.js +++ b/dev/search_index.js @@ -1,3 +1,3 @@ var documenterSearchIndex = {"docs": -[{"location":"generated/examples/01-binning/","page":"Binning","title":"Binning","text":"EditURL = \"https://github.com/MagneticResonanceImaging/MRIReco.jl/blob/master/docs/lit/examples/01-binning.jl\"","category":"page"},{"location":"generated/examples/01-binning/#binning","page":"Binning","title":"Binning","text":"","category":"section"},{"location":"generated/examples/01-binning/#Description","page":"Binning","title":"Description","text":"","category":"section"},{"location":"generated/examples/01-binning/","page":"Binning","title":"Binning","text":"This example described how to perform data binning with different number of profiles which is generaly used for self-gating acquisition in order to reconstruct images along the cardiac/respiratory cycle :","category":"page"},{"location":"generated/examples/01-binning/","page":"Binning","title":"Binning","text":"Trotier AJ, Castets CR, Lefrançois W, et al. USPIO-enhanced 3D-cine self-gated cardiac MRI based on a stack-of-stars golden angle short echo time sequence: Application on mice with acute myocardial infarction. Journal of Magnetic Resonance Imaging 2016;44:355–365 doi: 10.1002/jmri.25150.\nRibot EJ, Duriez TJ, Trotier AJ, Thiaudiere E, Franconi J-M, Miraux S. Self-gated bSSFP sequences to detect iron-labeled cancer cells and/or metastases in vivo in mouse liver at 7 Tesla. Journal of Magnetic Resonance Imaging 2015;41:1413–1421 doi: 10.1002/jmri.24688.","category":"page"},{"location":"generated/examples/01-binning/","page":"Binning","title":"Binning","text":"Here, we will create a simulated 2D radial acquisition and split the projections in 2 parts along the contrast dimension. The number of projection into each bin will be different to show how MRIReco handle that case.","category":"page"},{"location":"generated/examples/01-binning/#Setup","page":"Binning","title":"Setup","text":"","category":"section"},{"location":"generated/examples/01-binning/","page":"Binning","title":"Binning","text":"using CairoMakie\nusing ImageUtils: shepp_logan\nusing MRIReco, MRISimulation\n\nfunction plot_im2D(im2D;title::String=\"\")\n f = Figure()\n ax = Axis(f[1, 1],aspect = DataAspect(), yreversed = true, title = title)\n image!(ax, im2D')\n hidedecorations!(ax, grid = false)\n f\nend","category":"page"},{"location":"generated/examples/01-binning/#Simulate-a-radial-acquisition","page":"Binning","title":"Simulate a radial acquisition","text":"","category":"section"},{"location":"generated/examples/01-binning/","page":"Binning","title":"Binning","text":"N = 256\nx = shepp_logan(N)\n\nparams = Dict{Symbol, Any}()\nparams[:simulation] = \"fast\"\nparams[:trajName] = \"Radial\"\nparams[:numProfiles] = round(Int64,400)\nparams[:numSamplingPerProfile] = round(Int64,N)\n\nacqRad = simulation(x, params)\nrawRad = RawAcquisitionData(acqRad)","category":"page"},{"location":"generated/examples/01-binning/","page":"Binning","title":"Binning","text":"For real acquisition we first create the RawAcquisitionData structure and then convert into the AcquisitionData.","category":"page"},{"location":"generated/examples/01-binning/#Binning-Data","page":"Binning","title":"Binning Data","text":"","category":"section"},{"location":"generated/examples/01-binning/","page":"Binning","title":"Binning","text":"rawRad2 = deepcopy(rawRad)\nfor i in 1:length(rawRad.profiles)\n if mod(i,4) == 0\n rawRad2.profiles[i].head.idx.contrast = 0\n else\n rawRad2.profiles[i].head.idx.contrast = 1\n end\nend;\nnothing #hide","category":"page"},{"location":"generated/examples/01-binning/","page":"Binning","title":"Binning","text":"We need to tell to MRIReco that our trajectory is a custom one :","category":"page"},{"location":"generated/examples/01-binning/","page":"Binning","title":"Binning","text":"rawRad2.params[\"trajectory\"] = \"custom\";\nnothing #hide","category":"page"},{"location":"generated/examples/01-binning/#Reconstruction","page":"Binning","title":"Reconstruction","text":"","category":"section"},{"location":"generated/examples/01-binning/","page":"Binning","title":"Binning","text":"To perform the reconstruction we need to convert the RawAcquisitionData into and AcquisitionData structure.","category":"page"},{"location":"generated/examples/01-binning/","page":"Binning","title":"Binning","text":"acqRad2 = AcquisitionData(rawRad2)","category":"page"},{"location":"generated/examples/01-binning/","page":"Binning","title":"Binning","text":"We can also plot the number of projection for both bin :","category":"page"},{"location":"generated/examples/01-binning/","page":"Binning","title":"Binning","text":"nPro1 = Int32(length(acqRad2.kdata[1,1,1])/N)\nnPro2 = Int32(length(acqRad2.kdata[2,1,1])/N)\nprintln(\"Number of projection in : \\n\n- Bin 1 = $nPro1\\n\n- Bin 2 = $nPro2\")","category":"page"},{"location":"generated/examples/01-binning/","page":"Binning","title":"Binning","text":"Now we can perform a standard reconstruction","category":"page"},{"location":"generated/examples/01-binning/","page":"Binning","title":"Binning","text":"params = Dict{Symbol, Any}()\nparams[:reco] = \"direct\"\nparams[:reconSize] = (N,N)\n\nIreco = reconstruction(acqRad2, params)\nsize(Ireco)","category":"page"},{"location":"generated/examples/01-binning/","page":"Binning","title":"Binning","text":"let's show the results for first bin","category":"page"},{"location":"generated/examples/01-binning/","page":"Binning","title":"Binning","text":"plot_im2D(abs.(Ireco[:,:,1,1]),title = \"First bin\")","category":"page"},{"location":"generated/examples/01-binning/","page":"Binning","title":"Binning","text":"and the second bin","category":"page"},{"location":"generated/examples/01-binning/","page":"Binning","title":"Binning","text":"plot_im2D(abs.(Ireco[:,:,1,2]),title = \"Second bin\")","category":"page"},{"location":"generated/examples/01-binning/","page":"Binning","title":"Binning","text":"As expected we have more streaking artifacts on the first bin because we reconstruct the image with less projections.","category":"page"},{"location":"generated/examples/01-binning/#Reproducibility","page":"Binning","title":"Reproducibility","text":"","category":"section"},{"location":"generated/examples/01-binning/","page":"Binning","title":"Binning","text":"This page was generated with the following version of Julia:","category":"page"},{"location":"generated/examples/01-binning/","page":"Binning","title":"Binning","text":"io = IOBuffer();\nversioninfo(io);\nsplit(String(take!(io)), '\\n')","category":"page"},{"location":"generated/examples/01-binning/","page":"Binning","title":"Binning","text":"And with the following package versions","category":"page"},{"location":"generated/examples/01-binning/","page":"Binning","title":"Binning","text":"import Pkg; Pkg.status()","category":"page"},{"location":"generated/examples/01-binning/","page":"Binning","title":"Binning","text":"","category":"page"},{"location":"generated/examples/01-binning/","page":"Binning","title":"Binning","text":"This page was generated using Literate.jl.","category":"page"},{"location":"acquisitionData/#Acquisition-Data","page":"Acquisition Data","title":"Acquisition Data","text":"","category":"section"},{"location":"acquisitionData/","page":"Acquisition Data","title":"Acquisition Data","text":"There are two different forms of acquisition data types in MRIReco:","category":"page"},{"location":"acquisitionData/","page":"Acquisition Data","title":"Acquisition Data","text":"RawAcquisitionData\nAcquisitionData","category":"page"},{"location":"acquisitionData/","page":"Acquisition Data","title":"Acquisition Data","text":"While the former is used to hold the data in the form, how it will be written out from the scanner, the later has already performed some data permutations bringing the data into the shape how the reconstruction expects it.","category":"page"},{"location":"acquisitionData/#Raw-Data","page":"Acquisition Data","title":"Raw Data","text":"","category":"section"},{"location":"acquisitionData/","page":"Acquisition Data","title":"Acquisition Data","text":"The RawAcquisitionData is a data type that closely resembles the ISMRMRD data format. It looks like","category":"page"},{"location":"acquisitionData/","page":"Acquisition Data","title":"Acquisition Data","text":"mutable struct RawAcquisitionData\n params::Dict{String, Any}\n profiles::Vector{Profile}\nend","category":"page"},{"location":"acquisitionData/","page":"Acquisition Data","title":"Acquisition Data","text":"with","category":"page"},{"location":"acquisitionData/","page":"Acquisition Data","title":"Acquisition Data","text":"mutable struct Profile\n head::AcquisitionHeader\n traj::Array{Float32,2}\n data::Array{Complex{Float32},2}\nend","category":"page"},{"location":"acquisitionData/","page":"Acquisition Data","title":"Acquisition Data","text":"The params member of RawAcquisitionData is basically the a flattened dictionary derived from the XML part of an ISMRMRD file. A Profile describes the data measured after a single excitation during an MRI experiment. It has members head, traj, and data, which exactly resemble the structures specified by the ISMRMRD file format.","category":"page"},{"location":"acquisitionData/#Preprocessed-Data","page":"Acquisition Data","title":"Preprocessed Data","text":"","category":"section"},{"location":"acquisitionData/","page":"Acquisition Data","title":"Acquisition Data","text":"The RawAcquisitionData can be preprocessed into a form, which makes it more convenient for reconstruction algorithms. The AcquisitionData type looks like","category":"page"},{"location":"acquisitionData/","page":"Acquisition Data","title":"Acquisition Data","text":"mutable struct AcquisitionData\n sequenceInfo::Dict{Symbol,Any}\n traj::Vector{Trajectory}\n kdata::Array{Matrix{ComplexF64},3}\n subsampleIndices::Vector{Array{Int64}}\n encodingSize::Vector{Int64}\n fov::Vector{Float64}\nend","category":"page"},{"location":"acquisitionData/","page":"Acquisition Data","title":"Acquisition Data","text":"It consists of the sequence informations stored in a dictionary, the k-space trajectory, the k-space data, and several parameters describing the dimension of the data and some additional index vectors.","category":"page"},{"location":"acquisitionData/","page":"Acquisition Data","title":"Acquisition Data","text":"The k-space data kdata has three dimensions encoding","category":"page"},{"location":"acquisitionData/","page":"Acquisition Data","title":"Acquisition Data","text":"dim : contrasts/echoes\ndim : slices\ndim : repetitions","category":"page"},{"location":"acquisitionData/","page":"Acquisition Data","title":"Acquisition Data","text":"Each element is a matrix encoding","category":"page"},{"location":"acquisitionData/","page":"Acquisition Data","title":"Acquisition Data","text":"dim : k-space nodes\ndim : channels/coils","category":"page"},{"location":"acquisitionData/","page":"Acquisition Data","title":"Acquisition Data","text":"In case of undersampled data, the subsampling indices are stored in subsampleIndices. One check if the data is undersampled by checking if isempty(subsampleIndices).","category":"page"},{"location":"acquisitionData/","page":"Acquisition Data","title":"Acquisition Data","text":"The encoded space is stored in the field encodingSize. It is especially relevant for non-Cartesian trajectories where it is not clear upfront, how large the grid size for reconstruction should be chosen. Finally fov describes the physical lengths of the encoding grid.","category":"page"},{"location":"trajectories/#Trajectory","page":"Trajectory","title":"Trajectory","text":"","category":"section"},{"location":"trajectories/","page":"Trajectory","title":"Trajectory","text":"Several typical MRI k-space trajectories are available:","category":"page"},{"location":"trajectories/","page":"Trajectory","title":"Trajectory","text":"Cartesian\nEPI\nRadial\nSpiral","category":"page"},{"location":"trajectories/","page":"Trajectory","title":"Trajectory","text":"In addition, it is also possible to define new k-space trajectories. Currently, most of the trajectories are only available in 2D. Each trajectory is of type Trajectory and implements the following functions","category":"page"},{"location":"trajectories/","page":"Trajectory","title":"Trajectory","text":"string(tr::Trajectory)\nkspaceNodes(tr::Trajectory)\nreadoutTimes(tr::Trajectory)","category":"page"},{"location":"trajectories/","page":"Trajectory","title":"Trajectory","text":"For instance we can define a spiral, radial, and cartesian trajectory using","category":"page"},{"location":"trajectories/","page":"Trajectory","title":"Trajectory","text":"tr = trajectory(\"Spiral\", 1, 600, windings=10)\ntr = trajectory(\"Cartesian\", 13, 50, EPI_factor=1)\ntr = trajectory(\"Radial\", 13, 50)","category":"page"},{"location":"trajectories/","page":"Trajectory","title":"Trajectory","text":"A variable density spiral can be generated by","category":"page"},{"location":"trajectories/","page":"Trajectory","title":"Trajectory","text":"tr = trajectory(\"SpiralVarDens\", 3, 200)","category":"page"},{"location":"trajectories/","page":"Trajectory","title":"Trajectory","text":"The k-space nodes can then be accessed by","category":"page"},{"location":"trajectories/","page":"Trajectory","title":"Trajectory","text":"nodes = kspaceNodes(tr)","category":"page"},{"location":"trajectories/","page":"Trajectory","title":"Trajectory","text":"The script generating the following image can be executed by running the following from within the Julia REPL:","category":"page"},{"location":"trajectories/","page":"Trajectory","title":"Trajectory","text":"include(joinpath(dirname(pathof(MRIReco)),\"../docs/src/examples/exampleTrajectories.jl\"))","category":"page"},{"location":"trajectories/","page":"Trajectory","title":"Trajectory","text":"(Image: Trajectories)","category":"page"},{"location":"compressedSensing/#Compressed-Sensing","page":"Compressed Sensing","title":"Compressed Sensing","text":"","category":"section"},{"location":"compressedSensing/","page":"Compressed Sensing","title":"Compressed Sensing","text":"We next consider a compressed sensing reconstruction using one slice of a knee dataset obtained from mridata.org. The example can be run by entering","category":"page"},{"location":"compressedSensing/","page":"Compressed Sensing","title":"Compressed Sensing","text":"include(joinpath(dirname(pathof(MRIReco)),\"../docs/src/examples/exampleCS.jl\"))","category":"page"},{"location":"compressedSensing/","page":"Compressed Sensing","title":"Compressed Sensing","text":"into the Julia REPL.","category":"page"},{"location":"compressedSensing/","page":"Compressed Sensing","title":"Compressed Sensing","text":"We first perform a baseline reconstruction with fully sampled data:","category":"page"},{"location":"compressedSensing/","page":"Compressed Sensing","title":"Compressed Sensing","text":"# load fully sampled data\nf = ISMRMRDFile(\"data/knee_3dFSE_slice170.h5\")\nacqData = AcquisitionData(f);\n\n# reconstruct\nparams = Dict{Symbol, Any}()\nparams[:reco] = \"direct\"\nparams[:reconSize] = (320,320) # this size is also contained in acqData.encodingSize\n\nimg = reconstruction(acqData, params)\nimg = sqrt.(sum(img.^2,dims=5))","category":"page"},{"location":"compressedSensing/","page":"Compressed Sensing","title":"Compressed Sensing","text":"The result looks like this:","category":"page"},{"location":"compressedSensing/","page":"Compressed Sensing","title":"Compressed Sensing","text":"(Image: Knee Original)","category":"page"},{"location":"compressedSensing/","page":"Compressed Sensing","title":"Compressed Sensing","text":"To simulate an undersampled reconstruction, we retrospectively undersample the data using a Poisson disk pattern.","category":"page"},{"location":"compressedSensing/","page":"Compressed Sensing","title":"Compressed Sensing","text":"redFac = 4.0\nacqDataSub = sample_kspace(acqData,redFac,\"poisson\",calsize=30,profiles=false);","category":"page"},{"location":"compressedSensing/","page":"Compressed Sensing","title":"Compressed Sensing","text":"The sampling pattern looks like this:","category":"page"},{"location":"compressedSensing/","page":"Compressed Sensing","title":"Compressed Sensing","text":"(Image: Mask)","category":"page"},{"location":"compressedSensing/","page":"Compressed Sensing","title":"Compressed Sensing","text":"Then, we estimate the coil sensitivities using ESPIRiT","category":"page"},{"location":"compressedSensing/","page":"Compressed Sensing","title":"Compressed Sensing","text":"smaps = espirit(acqData,(6,6),30,eigThresh_1=0.035,eigThresh_2=0.98)","category":"page"},{"location":"compressedSensing/","page":"Compressed Sensing","title":"Compressed Sensing","text":"and perform a simple SENSE reconstruction. We expect a degradation in image quality due to the subsampling:","category":"page"},{"location":"compressedSensing/","page":"Compressed Sensing","title":"Compressed Sensing","text":"params = Dict{Symbol, Any}()\nparams[:reco] = \"multiCoil\"\nparams[:reconSize] = (320,320)\nparams[:senseMaps] = smaps\n\nparams[:solver] = \"cgnr\"\nparams[:regularization] = \"L2\"\nparams[:λ] = 1.e-4\nparams[:iterations] = 5\nparams[:normalizeReg] = true\n\nimg_cg = reconstruction(acqDataSub, params)","category":"page"},{"location":"compressedSensing/","page":"Compressed Sensing","title":"Compressed Sensing","text":"Using TV regularization recquires us to change some parameters:","category":"page"},{"location":"compressedSensing/","page":"Compressed Sensing","title":"Compressed Sensing","text":"params = Dict{Symbol, Any}()\nparams[:reco] = \"multiCoil\"\nparams[:reconSize] = (320,320)\nparams[:senseMaps] = smaps\n\nparams[:solver] = \"admm\"\nparams[:regularization] = \"TV\"\nparams[:λ] = 1.e-1 # 5.e-2\nparams[:iterations] = 50\nparams[:ρ] = 0.1\nparams[:absTol] = 1.e-4\nparams[:relTol] = 1.e-2\nparams[:tolInner] = 1.e-2\nparams[:normalizeReg] = true\n\nimg_tv = reconstruction(acqDataSub, params)","category":"page"},{"location":"compressedSensing/","page":"Compressed Sensing","title":"Compressed Sensing","text":"Lets compare the results, left the regular SENSE reconstruction and right the TV reglarized solution:","category":"page"},{"location":"compressedSensing/","page":"Compressed Sensing","title":"Compressed Sensing","text":"(Image: SENSE) (Image: TV)","category":"page"},{"location":"image/#Images","page":"Images","title":"Images","text":"","category":"section"},{"location":"image/","page":"Images","title":"Images","text":"All reconstructed data is stored as an AxisArray. The AxisArrays package is part of the Images package family, which groups all image processing related functionality together. We note that the term Image does not restrict the dimensionality of the data types to 2D but in fact images can be of arbitrary dimensionality.","category":"page"},{"location":"image/","page":"Images","title":"Images","text":"The reconstructed MRI image I is an AxisArray and has five dimensions. The first three are the spatial dimension x, y, and z, whereas dimension four encodes the number of echos that have been reconstructed, while dimension five encodes individual coils that may have been reconstructed independently. By using an AxisArray the object does not only consist of the data but it additionally encodes the physical size of the image as well as the echo times. To extract the ordinary Julia array one can simply use Ireco.data.","category":"page"},{"location":"image/","page":"Images","title":"Images","text":"The advantage of encoding the physical dimensions is the image data can be stored without loosing the dimensions of the data. For instance one can call","category":"page"},{"location":"image/","page":"Images","title":"Images","text":"saveImage(filename, I)","category":"page"},{"location":"image/","page":"Images","title":"Images","text":"to store the image and","category":"page"},{"location":"image/","page":"Images","title":"Images","text":"I = loadImage(filename)","category":"page"},{"location":"image/","page":"Images","title":"Images","text":"to load the image. Currently, MRIReco does support the NIfTI file format. By default, saveImage stores the data complex valued if the image I is complex valued. To store the magnitude image one can call","category":"page"},{"location":"image/","page":"Images","title":"Images","text":"saveImage(filename, I, true)","category":"page"},{"location":"offresonance/#Offresonance-Correction","page":"Offresonance","title":"Offresonance Correction","text":"","category":"section"},{"location":"offresonance/","page":"Offresonance","title":"Offresonance","text":"For trajectories with long readouts the MRI images are degraded by offresonance artifacts, if the offresonance is not taken into account during reconstruction. We provide fast algorithms that are capable of correcting offresonance artifacts provided that the offresonance map is known. Our framework is also capable of correcting T2* relaxation effects. The later are encoded in the real part of the correction map while the offresoanance is encoded in the imaginary part. The following example shows an example of a simulation and reconstruction of MRI data that takes offresonance due to an inhomogeneous fieldmap into account. The example can be run by entering","category":"page"},{"location":"offresonance/","page":"Offresonance","title":"Offresonance","text":"include(joinpath(dirname(pathof(MRIReco)),\"../docs/src/examples/exampleFieldmap.jl\"))","category":"page"},{"location":"offresonance/","page":"Offresonance","title":"Offresonance","text":"into the Julia REPL.","category":"page"},{"location":"offresonance/","page":"Offresonance","title":"Offresonance","text":"using MRIReco\n\nN = 256\nI = shepp_logan(N)\nI = circularShutterFreq!(I,1)\ncmap = 1im*quadraticFieldmap(N,N,125*2pi)\n\n# simulation parameters\nparams = Dict{Symbol, Any}()\nparams[:simulation] = \"fast\"\nparams[:trajName] = \"Spiral\"\nparams[:numProfiles] = 1\nparams[:numSamplingPerProfile] = N*N\nparams[:windings] = 128\nparams[:AQ] = 3.0e-2\nparams[:correctionMap] = cmap[:,:,1]\n\n# do simulation\nacqData = simulation(I, params)\n\n# reco parameters\nparams = Dict{Symbol, Any}()\nparams[:reco] = \"direct\"\nparams[:reconSize] = (N,N)\nparams[:correctionMap] = cmap\nparams[:alpha] = 1.75\nparams[:m] = 4.0\nparams[:K] = 28\n\n# do reconstruction\nIreco = reconstruction(acqData, params)","category":"page"},{"location":"offresonance/","page":"Offresonance","title":"Offresonance","text":"The considered quadratic fieldmap looks like this:","category":"page"},{"location":"offresonance/","page":"Offresonance","title":"Offresonance","text":"(Image: Fieldmap)","category":"page"},{"location":"offresonance/","page":"Offresonance","title":"Offresonance","text":"The reconstruction without and with offresonance correction are shown below:","category":"page"},{"location":"offresonance/","page":"Offresonance","title":"Offresonance","text":"(Image: NoCorrection) (Image: Reconstruction)","category":"page"},{"location":"custom/#Customization","page":"Customize","title":"Customization","text":"","category":"section"},{"location":"custom/","page":"Customize","title":"Customize","text":"We promised that MRIReco allows for customization. Lets in the following consider a custom data-driven sparsifying transform that is currently not part of MRIReco.jl [S. Ravishankar and Y. Bresler, IEEE Trans. Med. Imaging, 30 (5), 2011].","category":"page"},{"location":"custom/","page":"Customize","title":"Customize","text":"It is based on","category":"page"},{"location":"custom/","page":"Customize","title":"Customize","text":"Learn a dictionary from a reference image (e.g. adjacent slice) using KSVD colorgreencheckmark\nImplement sparsifying transform which analyses the input image in terms of the dictionary","category":"page"},{"location":"custom/","page":"Customize","title":"Customize","text":"(Image: DictTrafo)","category":"page"},{"location":"custom/","page":"Customize","title":"Customize","text":"In order to implement this, we first need the analyze function where we can reuse the matchingpursuit function from Wavelets.jl","category":"page"},{"location":"custom/","page":"Customize","title":"Customize","text":"function analyzeImage(x::Vector{T},D::Matrix{T},xsize::NTuple{2,Int64},\n psize::NTuple{2,Int64};t0::Int64=size(D,2),tol=1e-3) where T\n nx,ny = xsize\n px,py = psize\n x = reshape(x,nx,ny)\n x_pad = repeat(x,2,2)[1:nx+px-1,1:ny+py-1] # pad image using periodic boundary conditions\n α = zeros(T,size(D,2),nx,ny)\n patch = zeros(T,px*py)\n for j=1:ny\n for i=1:nx\n patch[:] .= vec(x_pad[i:i+px-1,j:j+py-1])\n norm(patch)==0 && continue\n # matchingpursuit is contained in Wavelets.jl\n α[:,i,j] .= matchingpursuit(patch, x->D*x, x->transpose(D)*x, tol)\n end\n end\n return vec(α)\nend","category":"page"},{"location":"custom/","page":"Customize","title":"Customize","text":"Synthetization can be done by","category":"page"},{"location":"custom/","page":"Customize","title":"Customize","text":"function synthesizeImage(α::Vector{T},D::Matrix{T},xsize::NTuple{2,Int64},psize::NTuple{2,Int64}) where T\n nx,ny = xsize\n px,py = psize\n x = zeros(T,nx+px-1,ny+py-1)\n α = reshape(α,:,nx,ny)\n for j=1:ny\n for i=1:nx\n x[i:i+px-1,j:j+py-1] .+= reshape(D*α[:,i,j],px,py)\n end\n end\n return vec(x[1:nx,1:ny])/(px*py)\nend","category":"page"},{"location":"custom/","page":"Customize","title":"Customize","text":"Once we have those two operations we can setup up a dictionary operator:","category":"page"},{"location":"custom/","page":"Customize","title":"Customize","text":"function dictOp(D::Matrix{T},xsize::NTuple{2,Int64},psize::NTuple{2,Int64},tol::Float64=1.e-3) where T\n produ = x->analyzeImage(x,D,xsize,psize,tol=tol)\n ctprodu = x->synthesizeImage(x,D,xsize,psize)\n return LinearOperator(prod(xsize)*size(D,2),prod(xsize),false,false\n , produ\n , nothing\n , ctprodu )\nend","category":"page"},{"location":"custom/","page":"Customize","title":"Customize","text":"To test our method, let us load some simulated data and subsample it","category":"page"},{"location":"custom/","page":"Customize","title":"Customize","text":"# phantom\nimg = readdlm(\"data/mribrain100.tsv\")\n\nacqData = AcquisitionData(ISMRMRDFile(\"data/acqDataBrainSim100.h5\"))\nnx,ny = acqData.encodingSize\n\n# undersample kspace data\nacqData = sample_kspace(acqData, 2.0, \"poisson\", calsize=25,profiles=false);","category":"page"},{"location":"custom/","page":"Customize","title":"Customize","text":"Now we load a pre-trained dictionary, build the sparsifying transform and perform the reconstruction","category":"page"},{"location":"custom/","page":"Customize","title":"Customize","text":"# load the dictionary\nD = ComplexF64.(readdlm(\"data/brainDict98.tsv\"))\n\n# some parameters\npx, py = (6,6) # patch size\nK = px*py # number of atoms\n\n# CS reconstruction using Wavelets\nparams = Dict{Symbol,Any}()\nparams[:reco] = \"standard\"\nparams[:reconSize] = (nx,ny)\nparams[:iterations] = 50\nparams[:λ] = 2.e-2\nparams[:regularization] = \"L1\"\nparams[:sparseTrafo] = dictOp(D,(nx,ny),(px,py),2.e-2)\nparams[:ρ] = 0.1\nparams[:solver] = \"admm\"\nparams[:absTol] = 1.e-4\nparams[:relTol] = 1.e-2\n\nimg_d = reconstruction(acqData,params)","category":"page"},{"location":"custom/","page":"Customize","title":"Customize","text":"For comparison, let us perform the same reconstruction as above but with a Wavelet transform","category":"page"},{"location":"custom/","page":"Customize","title":"Customize","text":"delete!(params, :sparseTrafo)\nparams[:sparseTrafoName] = \"Wavelet\"\n\nimg_w = reconstruction(acqData,params)","category":"page"},{"location":"custom/","page":"Customize","title":"Customize","text":"The following pictures shows the wavelet based CS reconstruction on the left and the dictionary based CS reconstruction on the right:","category":"page"},{"location":"custom/","page":"Customize","title":"Customize","text":"(Image: BrainWavelet) (Image: BrainDict)","category":"page"},{"location":"custom/","page":"Customize","title":"Customize","text":"For reference, the original data is shown here:","category":"page"},{"location":"custom/","page":"Customize","title":"Customize","text":"(Image: BrainOrig)","category":"page"},{"location":"custom/","page":"Customize","title":"Customize","text":"One can clearly see that the dictionary approach performs better than a simple Wavelet L1 prior.","category":"page"},{"location":"gettingStarted/#Getting-Started","page":"Getting Started","title":"Getting Started","text":"","category":"section"},{"location":"gettingStarted/","page":"Getting Started","title":"Getting Started","text":"Throughout the entire documentation we assume that you have loaded MRIReco as well as PyPlot via","category":"page"},{"location":"gettingStarted/","page":"Getting Started","title":"Getting Started","text":"using PyPlot, MRIReco","category":"page"},{"location":"gettingStarted/","page":"Getting Started","title":"Getting Started","text":"Its important to load these packages in that order, since otherwise PyPlot will not work correctly on some systems.","category":"page"},{"location":"gettingStarted/","page":"Getting Started","title":"Getting Started","text":"All examples discussed in the documentation can be found in the package source code in the folder","category":"page"},{"location":"gettingStarted/","page":"Getting Started","title":"Getting Started","text":" MRIReco/docs/src/examples","category":"page"},{"location":"gettingStarted/","page":"Getting Started","title":"Getting Started","text":"This folder is located in ~/.julia/packages or ~/.julia/dev depending if you have checked out MRIReco for development or not. You can call the first example by entering into the Julia REPL:","category":"page"},{"location":"gettingStarted/","page":"Getting Started","title":"Getting Started","text":"include(joinpath(dirname(pathof(MRIReco)),\"../docs/src/examples/exampleRadial.jl\"))","category":"page"},{"location":"gettingStarted/","page":"Getting Started","title":"Getting Started","text":"which should open a plotting window as is outlined in the following example.","category":"page"},{"location":"gettingStarted/#Basic-Example","page":"Getting Started","title":"Basic Example","text":"","category":"section"},{"location":"gettingStarted/","page":"Getting Started","title":"Getting Started","text":"We will start with a very simple example and perform simple simulation and reconstruction based on a shepp logan phantom. The program looks like this","category":"page"},{"location":"gettingStarted/","page":"Getting Started","title":"Getting Started","text":"# image\nN = 256\nI = shepp_logan(N)\n\n# simulation parameters\nparams = Dict{Symbol, Any}()\nparams[:simulation] = \"fast\"\nparams[:trajName] = \"Radial\"\nparams[:numProfiles] = floor(Int64, pi/2*N)\nparams[:numSamplingPerProfile] = 2*N\n\n# do simulation\nacqData = simulation(I, params)\n\n# reco parameters\nparams = Dict{Symbol, Any}()\nparams[:reco] = \"direct\"\nparams[:reconSize] = (N,N)\nIreco = reconstruction(acqData, params)","category":"page"},{"location":"gettingStarted/","page":"Getting Started","title":"Getting Started","text":"We will go through the program step by step. First we create a 2D shepp logan phantom of size N=256. Then we setup a dictionary that defines the simulation parameters. Here, we chose a simple radial trajectory with 402 spokes and 512 samples per profile. We use a gridding-based simulator by setting params[:simulation] = \"fast\"","category":"page"},{"location":"gettingStarted/","page":"Getting Started","title":"Getting Started","text":"After setting up the parameter dictionary params, the simulation is performed by calling","category":"page"},{"location":"gettingStarted/","page":"Getting Started","title":"Getting Started","text":"acqData = simulation(I, params)","category":"page"},{"location":"gettingStarted/","page":"Getting Started","title":"Getting Started","text":"The result simulation function outputs an acquisition object that is discussed in more detail in the section Acquisition Data. The acquisition data can also be stored to or loaded from a file, which will be discussed in section File Handling.","category":"page"},{"location":"gettingStarted/","page":"Getting Started","title":"Getting Started","text":"Using the acquisition data we can perform a reconstruction. To this end, again a parameter dictionary is setup and some basic configuration is done. In this case, for instance we specify that we want to apply a simple NFFT-based gridding reconstruction. The reconstruction is invoked by calling","category":"page"},{"location":"gettingStarted/","page":"Getting Started","title":"Getting Started","text":"Ireco = reconstruction(acqData, params)","category":"page"},{"location":"gettingStarted/","page":"Getting Started","title":"Getting Started","text":"The resulting image is of type AxisArray and has 5 dimensions. One can display the image object by calling","category":"page"},{"location":"gettingStarted/","page":"Getting Started","title":"Getting Started","text":"imshow(abs.(Ireco[:,:,1,1,1]))","category":"page"},{"location":"gettingStarted/","page":"Getting Started","title":"Getting Started","text":"Alternatively one can store the image into a file, which will be discussed in the section on Images.","category":"page"},{"location":"gettingStarted/","page":"Getting Started","title":"Getting Started","text":"The original phantom and the reconstructed image are shown below","category":"page"},{"location":"gettingStarted/","page":"Getting Started","title":"Getting Started","text":"(Image: Phantom) (Image: Reconstruction)","category":"page"},{"location":"gettingStarted/","page":"Getting Started","title":"Getting Started","text":"We will discuss reconstruction in more detail in the sections on Offresonance Correction, Parallel Imaging, and Compressed Sensing","category":"page"},{"location":"API/#API","page":"API","title":"API","text":"","category":"section"},{"location":"API/","page":"API","title":"API","text":"This page contains documentation of the public API of MRIReco. In the Julia REPL one can access this documentation by entering the help mode with ? and then writing the function for which the documentation should be shown.","category":"page"},{"location":"API/#Operators","page":"API","title":"Operators","text":"","category":"section"},{"location":"API/","page":"API","title":"API","text":"Operators are implemented as subtypes of AbstractLinearOperator, which is defined in the package LinearOperators.jl. Such operators must provide a function implementing the product and a function implementing the product with the adjoint. Furthermore, the number of rows and columns of the operator must be specified.","category":"page"},{"location":"API/","page":"API","title":"API","text":"MRIReco.encodingOps2d_simple\nMRIReco.encodingOps3d_simple\nMRIReco.encodingOps2d_parallel\nMRIReco.encodingOps3d_parallel\nMRIReco.encodingOp2d_multiEcho\nMRIReco.encodingOp3d_multiEcho\nMRIReco.encodingOp2d_multiEcho_parallel\nMRIReco.encodingOp3d_multiEcho_parallel\nMRIReco.fourierEncodingOp2d\nMRIReco.fourierEncodingOp3d\nMRIReco.ExplicitOp(shape::NTuple{D,Int64}, tr::Trajectory, correctionmap::Array{ComplexF64,D}; MRIReco.echoImage::Bool=false, kargs...) where D\nRegularizedLeastSquares.FFTOp(T::Type, shape::Tuple, shift=true)\nMRIReco.NFFTOp(shape::Tuple, tr::Trajectory; nodes=nothing, kargs...)\nMRIReco.FieldmapNFFTOp(shape::NTuple{D,Int64}, tr::Trajectory,\n correctionmap::Array{ComplexF64,D};\n method::String=\"nfft\",\n echoImage::Bool=true,\n alpha::Float64=1.75,\n m::Float64=3.0,\n K=20,\n kargs...) where D\nMRIReco.SamplingOp\nMRIReco.SensitivityOp\nMRIReco.SparseOp\nMRIReco.RegularizedLeastSquares.WeightingOp","category":"page"},{"location":"API/#Datatypes","page":"API","title":"Datatypes","text":"","category":"section"},{"location":"API/","page":"API","title":"API","text":"MRIReco.AcquisitionData\nMRIReco.AcquisitionData(tr::T,kdata::Array{Matrix{ComplexF64},3}\n ; seqInfo=Dict{Symbol,Any}()\n , idx=nothing\n , encodingSize=Int64[0,0,0]\n , fov=Float64[0,0,0]\n , kargs...) where T <: Union{Trajectory,Vector{Trajectory}}\nMRIReco.trajectory(acqData::AcquisitionData,i::Int64=1)\nMRIReco.numContrasts(acqData::AcquisitionData)\nMRIReco.numChannels\nMRIReco.numSlices\nMRIReco.numRepetitions\nMRIReco.kData\nMRIReco.multiEchoData\nMRIReco.multiCoilData\nMRIReco.multiCoilMultiEchoData\nMRIReco.profileData\nMRIReco.samplingDensity\nMRIReco.changeEncodingSize2D\nMRIReco.convert3dTo2d\nMRIReco.RawAcquisitionData\nMRIReco.trajectory(f::RawAcquisitionData; slice::Int=1, contrast::Int=1)\nMRIReco.rawdata(f::RawAcquisitionData)\nMRIReco.AcquisitionData(f::RawAcquisitionData)\nMRIReco.RawAcquisitionData(f::ISMRMRDFile, dataset=\"dataset\")\nMRIReco.AcquisitionData(f::ISMRMRDFile, dataset=\"dataset\")","category":"page"},{"location":"API/#Trajectories","page":"API","title":"Trajectories","text":"","category":"section"},{"location":"API/","page":"API","title":"API","text":"MRIReco.Trajectory\nMRIReco.trajectory(trajName::AbstractString, numProfiles::Int, numSamplingPerProfile::Int; MRIReco.numSlices::Int64=1, TE::Float64=0.0, AQ::Float64=1.e-3, kargs...)\nMRIReco.string(tr::Trajectory)\nMRIReco.echoTime(tr::Trajectory)\nMRIReco.acqTimePerProfile(tr::Trajectory)\nMRIReco.numProfiles(tr::Trajectory)\nMRIReco.numSamplingPerProfile(tr::Trajectory)\nMRIReco.numSlices(tr::Trajectory)\nMRIReco.isCircular(tr::Trajectory)\nMRIReco.isCartesian(tr::Trajectory)\nMRIReco.dims(tr::Trajectory)\nMRIReco.kspaceNodes(tr::Trajectory)\nMRIReco.readoutTimes(tr::Trajectory)\nMRIReco.CartesianTrajectory\nMRIReco.EPITrajectory\nMRIReco.OneLine2dTrajectory\nMRIReco.RadialTrajectory\nMRIReco.SpiralTrajectory\nMRIReco.SpiralTrajectoryVarDens\nMRIReco.CartesianTrajectory3D\nMRIReco.KooshballTrajectory\nMRIReco.StackOfStarsTrajectory","category":"page"},{"location":"API/#Sequences","page":"API","title":"Sequences","text":"","category":"section"},{"location":"API/","page":"API","title":"API","text":"MRIReco.MESequence\nMRIReco.numContrasts(seq::MESequence)\nMRIReco.echoTimes(seq::MESequence)\nMRIReco.flipAngles(seq::MESequence)\nMRIReco.echoAmplitudes(seq::MESequence, R1::Float64, R2::Float64, numStates=nothing)\nMRIReco.epgAmplitudes(seq::MESequence, R1::Real, R2::Real, numStates=nothing)\nMRIReco.epgRotation\nMRIReco.epgRelaxation\nMRIReco.epgDephasing\nMRIReco.rfRotation","category":"page"},{"location":"API/#Sampling","page":"API","title":"Sampling","text":"","category":"section"},{"location":"API/","page":"API","title":"API","text":"MRIReco.sample\nMRIReco.sample_kspace(data::AbstractArray,redFac::Float64,patFunc::AbstractString;kargs...)\nMRIReco.sample_kspace(acqData::AcquisitionData,redFac::Float64,\n patFunc::AbstractString; rand=true, profiles=true,\n seed = 1234, kargs...)\nMRIReco.sample_regular(shape::Tuple, redFac::Float64; kargs...)\nMRIReco.sample_random(shape::Tuple{Int64,Int64},redFac::Float64;calsize::Int64=0,kargs...)\nMRIReco.sample_poissondisk(shape::Tuple{Int64,Int64},redFac::Float64;calsize::Int64=0, seed::Int64=1234,kargs...)\nMRIReco.sample_vdpoisson(shape::Tuple{Int64,Int64},redFac::Float64; seed::Int64=1234,kargs...)\nMRIReco.sample_lines(shape::Tuple{Int64,Int64},redFac::Float64;sampleFunc=\"random\",kargs...)\nMRIReco.calculateIncoherence(acqData::AcquisitionData, recoParams::Dict, slice=1)","category":"page"},{"location":"API/#Simulation","page":"API","title":"Simulation","text":"","category":"section"},{"location":"API/","page":"API","title":"API","text":"MRIReco.simulation(image::Array{T,3}, simParams::Dict) where T<:Union{ComplexF64,Float64}\nMRIReco.simulation(image::Array{T,3}, simParams::Dict, filename::String;\n force=false) where T<:Union{ComplexF64,Float64}\nMRIReco.simulation(image::Array{T,2}, simParams::Dict) where T<:Union{ComplexF64,Float64}\nMRIReco.simulation(tr::Trajectory\n , image::Array{ComplexF64}\n , correctionMap = []\n ; opName=\"fast\"\n , senseMaps=[]\n , verbose=true\n , kargs...)\nMRIReco.simulation(seq::AbstractSequence, tr::Vector{Trajectory}\n , image::Array{ComplexF64,3}\n ; opName=\"fast\"\n , r1map=[]\n , r2map=[]\n , fmap=[]\n , senseMaps=[]\n , verbose=true\n , kargs...)\nMRIReco.addNoise(x::Vector, snr::Float64, complex= true)\nMRIReco.addNoise(acqData::AcquisitionData, snr::Float64)\nMRIReco.addNoise!(acqData::AcquisitionData, snr::Float64)\nMRIReco.birdcageSensitivity\nMRIReco.quadraticFieldmap","category":"page"},{"location":"API/#Reconstruction","page":"API","title":"Reconstruction","text":"","category":"section"},{"location":"API/","page":"API","title":"API","text":"MRIReco.reconstruction(acqData::AcquisitionData, recoParams::Dict)\nMRIReco.reconstruction(acqData::AcquisitionData, recoParams::Dict, filename::String;force=false)\nMRIReco.setupIterativeReco\nMRIReco.reconstruction_direct_2d\nMRIReco.reconstruction_direct_3d\nMRIReco.reconstruction_simple\nMRIReco.reconstruction_multiEcho\nMRIReco.reconstruction_multiCoil\nMRIReco.reconstruction_multiCoilMultiEcho\nMRIReco.espirit\nMRIReco.nrmsd","category":"page"},{"location":"API/#MRIReco.reconstruction-Tuple{AcquisitionData, Dict}","page":"API","title":"MRIReco.reconstruction","text":"reconstruction(acqData::AcquisitionData, recoParams::Dict)\n\nPerforms image reconstruction of an AcquisitionData object. Parameters are specified in a dictionary.\n\nReconstruction types are specified by the symbol :reco. Valid reconstruction names are:\n\n:direct - direct Fourier reconstruction\n:standard - iterative reconstruction for all contrasts, coils & slices independently\n:multiEcho - iterative joint reconstruction of all echo images\n:multiCoil - SENSE-type iterative reconstruction\n:multiCoilMultiEcho - SENSE-type iterative reconstruction of all echo images\n\n\n\n\n\n","category":"method"},{"location":"API/#MRIReco.reconstruction-Tuple{AcquisitionData, Dict, String}","page":"API","title":"MRIReco.reconstruction","text":"reconstruction(acqData::AcquisitionData, recoParams::Dict,filename::String; force=false)\n\nperforms the same image reconstrucion as reconstruction(acqData::AcquisitionData, recoParams::Dict) and saves the image in a file with name filename. If force=false, the reconstructed image is loaded from the the file filename if the latter is present.\n\n\n\n\n\n","category":"method"},{"location":"API/#MRIReco.setupIterativeReco","page":"API","title":"MRIReco.setupIterativeReco","text":"setupIterativeReco(acqData::AcquisitionData, recoParams::Dict)\n\nbuilds relevant parameters and operators from the entries in recoParams\n\nrelevant parameters\n\nreconSize::NTuple{2,Int64} - size of image to reconstruct\nweights::Vector{Vector{Complex{<:AbstractFloat}}} - sampling density of the trajectories in acqData\nsparseTrafo::AbstractLinearOperator - sparsifying transformation\nreg::Regularization - Regularization to be used\nnormalize::Bool - adjust regularization parameter according to the size of k-space data\nsolvername::String - name of the solver to use\nsenseMaps::Array{Complex{<:AbstractFloat}} - coil sensitivities\ncorrectionMap::Array{Complex{<:AbstractFloat}} - fieldmap for the correction of off-resonance effects\nmethod::String=\"nfft\" - method to use for time-segmentation when correctio field inhomogeneities\n\nsparseTrafo and reg can also be speficied using their names in form of a string.\n\n\n\n\n\n","category":"function"},{"location":"API/#MRIReco.reconstruction_simple","page":"API","title":"MRIReco.reconstruction_simple","text":"Performs iterative image reconstruction independently for the data of all coils, contrasts and slices\n\nArguments\n\nacqData::AcquisitionData - AcquisitionData object\nreconSize::NTuple{2,Int64} - size of image to reconstruct\nreg::Regularization - Regularization to be used\nsparseTrafo::AbstractLinearOperator - sparsifying transformation\nweights::Vector{Vector{Complex{<:AbstractFloat}}} - sampling density of the trajectories in acqData\nsolvername::String - name of the solver to use\n(normalize::Bool=false) - adjust regularization parameter according to the size of k-space data\n(params::Dict{Symbol,Any}) - Dict with additional parameters\n\n\n\n\n\n","category":"function"},{"location":"API/#MRIReco.reconstruction_multiEcho","page":"API","title":"MRIReco.reconstruction_multiEcho","text":"Performs a iterative image reconstruction jointly for all contrasts. Different slices and coil images are reconstructed independently.\n\nArguments\n\nacqData::AcquisitionData - AcquisitionData object\nreconSize::NTuple{2,Int64} - size of image to reconstruct\nreg::Regularization - Regularization to be used\nsparseTrafo::AbstractLinearOperator - sparsifying transformation\nweights::Vector{Vector{Complex{<:AbstractFloat}}} - sampling density of the trajectories in acqData\nsolvername::String - name of the solver to use\n(normalize::Bool=false) - adjust regularization parameter according to the size of k-space data\n(params::Dict{Symbol,Any}) - Dict with additional parameters\n\n\n\n\n\n","category":"function"},{"location":"API/#MRIReco.reconstruction_multiCoil","page":"API","title":"MRIReco.reconstruction_multiCoil","text":"Performs a SENSE-type iterative image reconstruction. Different slices and contrasts images are reconstructed independently.\n\nArguments\n\nacqData::AcquisitionData - AcquisitionData object\nreconSize::NTuple{2,Int64} - size of image to reconstruct\nreg::Regularization - Regularization to be used\nsparseTrafo::AbstractLinearOperator - sparsifying transformation\nweights::Vector{Vector{Complex{<:AbstractFloat}}} - sampling density of the trajectories in acqData\nsolvername::String - name of the solver to use\nsenseMaps::Array{Complex{<:AbstractFloat}} - coil sensitivities\n(normalize::Bool=false) - adjust regularization parameter according to the size of k-space data\n(params::Dict{Symbol,Any}) - Dict with additional parameters\n\n\n\n\n\n","category":"function"},{"location":"API/#MRIReco.reconstruction_multiCoilMultiEcho","page":"API","title":"MRIReco.reconstruction_multiCoilMultiEcho","text":"Performs a SENSE-type iterative image reconstruction which reconstructs all contrasts jointly. Different slices are reconstructed independently.\n\nArguments\n\nacqData::AcquisitionData - AcquisitionData object\nreconSize::NTuple{2,Int64} - size of image to reconstruct\nreg::Regularization - Regularization to be used\nsparseTrafo::AbstractLinearOperator - sparsifying transformation\nweights::Vector{Vector{Complex{<:AbstractFloat}}} - sampling density of the trajectories in acqData\nsolvername::String - name of the solver to use\nsenseMaps::Array{Complex{<:AbstractFloat}} - coil sensitivities\n(normalize::Bool=false) - adjust regularization parameter according to the size of k-space data\n(params::Dict{Symbol,Any}) - Dict with additional parameters\n\n\n\n\n\n","category":"function"},{"location":"API/#MRIReco.nrmsd","page":"API","title":"MRIReco.nrmsd","text":"nrmsd(I,Ireco)\n\ncomputes the normalized root mean squared error of the image Ireco with respect to the image I.\n\n\n\n\n\n","category":"function"},{"location":"operators/#Imaging-Operators","page":"Imaging Operators","title":"Imaging Operators","text":"","category":"section"},{"location":"operators/","page":"Imaging Operators","title":"Imaging Operators","text":"The mapping between the proton density and the recorded signal is linear in MRI and can be described in the continuous case as an integral equation and in the discrete case as a matrix vector multiplication.","category":"page"},{"location":"operators/","page":"Imaging Operators","title":"Imaging Operators","text":"Depending on the imaging scenario, the MRI system matrix can have various different forms. It may encode a Cartesian, or a spiral trajectory. It may take offresonance into account, and it may also encode the sensitivity of the receive coil.","category":"page"},{"location":"operators/","page":"Imaging Operators","title":"Imaging Operators","text":"MRIReco implements various MRI imaging operators. In all cases, the operators have a dedicated Julia type that acts as a matrix. The operator E thus can be applied to a vector x by calling E*x. Similarly, the adjoint can be applied by adjoint(E)*x. We note at this point that the adjoint operation is lazy in Julia and thus the matrix adjoint(E) is never explicitly arranged.","category":"page"},{"location":"operators/","page":"Imaging Operators","title":"Imaging Operators","text":"MRIReco currently implements the following operators:","category":"page"},{"location":"operators/","page":"Imaging Operators","title":"Imaging Operators","text":"FFTOp: A multidimensional FFT operator\nNFFTOp: A multidimensional operator for non-equidistant FFTs\nFieldmapNFFTOp: An operator that takes complex correction terms into account\nSensitivityMapOp: An operator for building a SENSE reconstruction. Has to be combined with one of the former encoding operators\nSamplingOp: An operator that describes the (sub)sampling of full trajectories. The operator is used for Compressed Sensing reconstruction\nWaveletOp: A multidimensional operator for applying Wavelet transformations","category":"page"},{"location":"operators/","page":"Imaging Operators","title":"Imaging Operators","text":"Each of these operators can be build by calling the corresponding constructor. Alternatively one can use the EncodingOp constructor that allows for high-level construction of the imaging operator.","category":"page"},{"location":"SENSE/#Parallel-Imaging","page":"Parallel Imaging","title":"Parallel Imaging","text":"","category":"section"},{"location":"SENSE/","page":"Parallel Imaging","title":"Parallel Imaging","text":"For parallel imaging MRIReco.jl uses an iterative SENSE approach. In the following code example we show how to simulate MRI data with an array of 8 coils and how to reconstruct that data using SENSE. The example can be run by entering","category":"page"},{"location":"SENSE/","page":"Parallel Imaging","title":"Parallel Imaging","text":"include(joinpath(dirname(pathof(MRIReco)),\"../docs/src/examples/exampleSENSE.jl\"))","category":"page"},{"location":"SENSE/","page":"Parallel Imaging","title":"Parallel Imaging","text":"into the Julia REPL.","category":"page"},{"location":"SENSE/","page":"Parallel Imaging","title":"Parallel Imaging","text":"N = 256\nnumCoils = 8\nI = shepp_logan(N)\nI = circularShutterFreq!(I,1)\n\ncoilsens = birdcageSensitivity(N, 8, 1.5)\n\n# simulation parameters\nparams = Dict{Symbol, Any}()\nparams[:simulation] = \"fast\"\nparams[:trajName] = \"Spiral\"\nparams[:numProfiles] = 6\nparams[:numSamplingPerProfile] = div(N*N,16)\nparams[:windings] = div(N,16)\nparams[:AQ] = 2.0e-2\nparams[:senseMaps] = coilsens\n\n# do simulation\nacqData = simulation(I, params)\n\n# reco parameters\nparams = Dict{Symbol, Any}()\nparams[:reco] = \"multiCoil\"\nparams[:reconSize] = (N,N)\nparams[:regularization] = \"L2\"\nparams[:λ] = 1.e-3\nparams[:iterations] = 40\nparams[:solver] = \"cgnr\"\nparams[:senseMaps] = coilsens\n\n# do reconstruction\nIreco = reconstruction(acqData, params)\n","category":"page"},{"location":"SENSE/","page":"Parallel Imaging","title":"Parallel Imaging","text":"Below one can see the orignal phantom on the left and the reconstruction on the right:","category":"page"},{"location":"SENSE/","page":"Parallel Imaging","title":"Parallel Imaging","text":"(Image: Phantom) (Image: Reconstruction)","category":"page"},{"location":"overview/#Overview","page":"Overview","title":"Overview","text":"","category":"section"},{"location":"overview/","page":"Overview","title":"Overview","text":"As outlined in the introduction MRIReco.jl MRIReco has the philosophy to to reuse functionality provided by other Julia package and basically add the MRI specific functionality. This approach is enabled by the Julia package manager that can handle all dependencies automatically. Packages are therefore considered to be cheap in Julia so that modularization can be done across packages. In the following graph, the most important (not all) dependencies of MRIReco are visualized.","category":"page"},{"location":"overview/","page":"Overview","title":"Overview","text":"(Image: Dependencies)","category":"page"},{"location":"overview/","page":"Overview","title":"Overview","text":"Most importantly, all iterative solvers are implemented in RegularizedLeastSquares.jl so that MRIReco can benefit from all improvements made in that package. Gridding is implemented in the NFFT.jl package, which has many applications byond MRI. Sparsifying transformations are usually also not MRI specific and therefore implemented in independent packages (e.g. Wavelets.jl). For storing image data MRIReco.jl uses NiFTI.jl. Dicom data can potentially be saved by the DICOM.jl package, which, however, is not a hard dependency of MRIReco.","category":"page"},{"location":"overview/#Data-Types-and-Flow","page":"Overview","title":"Data Types and Flow","text":"","category":"section"},{"location":"overview/","page":"Overview","title":"Overview","text":"An overview about the most important data types and the data flow during recosntruction is given in the following figure.","category":"page"},{"location":"overview/","page":"Overview","title":"Overview","text":"(Image: DataFlow)","category":"page"},{"location":"overview/","page":"Overview","title":"Overview","text":"Raw data is usually obtained from files (discussed in File Handling). Since the data layout of the RawAcquisitionData object is not perfectly suited for reconstruction, we ","category":"page"},{"location":"#MRIReco.jl","page":"Home","title":"MRIReco.jl","text":"","category":"section"},{"location":"","page":"Home","title":"Home","text":"Magnetic Resonance Imaging Reconstruction","category":"page"},{"location":"#Introduction","page":"Home","title":"Introduction","text":"","category":"section"},{"location":"","page":"Home","title":"Home","text":"MRIReco is a Julia packet for magnetic resonance imaging. It contains algorithms for the simulation and reconstruction of MRT data and is both easy to use and flexibly expandable.","category":"page"},{"location":"","page":"Home","title":"Home","text":"Both direct and iterative methods are available for image reconstruction. In particular, modern compressed sensing algorithms such as ADMM can be used.","category":"page"},{"location":"","page":"Home","title":"Home","text":"The MRT imaging operator can be set up for a variety of scanning patterns (cartesian, spiral, radial, ...) and can take into account field inhomogeneity as well as the use of coil arrays. The operator can be quickly evaluated using NFFT-based methods.","category":"page"},{"location":"","page":"Home","title":"Home","text":"One strength of the package is that it is strongly modular and uses high quality Julia packages. These are e.g.","category":"page"},{"location":"","page":"Home","title":"Home","text":"NFFT.jl and FFTW.jl for fast Fourier transformations\nWavelets.jl for sparsification\nLinearOperators.jl in order to be able to divide the imaging operator modularly into individual parts\nRegularizedLeastSquares.jl for modern algorithms for solving linear optimization problems","category":"page"},{"location":"","page":"Home","title":"Home","text":"This interaction allows new algorithms to be easily integrated into the software framework. It is not necessary to program in C/C++ but the advantages of the scientific high-level language Julia can be used.","category":"page"},{"location":"","page":"Home","title":"Home","text":"note: Note\nMRIReco.jl is work in progress and in some parts not entirely optimized. In particular the FFT and NFFT implementation are currently limited to the CPU and do not support GPU acceleration yet.","category":"page"},{"location":"#Installation","page":"Home","title":"Installation","text":"","category":"section"},{"location":"","page":"Home","title":"Home","text":"Start julia and open the package mode by entering ]. Then enter","category":"page"},{"location":"","page":"Home","title":"Home","text":"add MRIReco","category":"page"},{"location":"","page":"Home","title":"Home","text":"This will install MRIReco and all its dependencies. If you want to develop MRIReco itself you can checkout MRIReco by calling","category":"page"},{"location":"","page":"Home","title":"Home","text":"dev MRIReco","category":"page"},{"location":"","page":"Home","title":"Home","text":"More information on how to develop a package can be found in the Julia documentation.","category":"page"},{"location":"#Plotting","page":"Home","title":"Plotting","text":"","category":"section"},{"location":"","page":"Home","title":"Home","text":"On purpose MRIReco is not depending on a particular plotting package since there are various plotting packages in the Julia ecosystem. Within the examples outlined in the tutorial we will use PyPlot for plotting but you may prefer using the Plots package. You can add both packages the same way MRIReco has been added.","category":"page"},{"location":"#Tutorial","page":"Home","title":"Tutorial","text":"","category":"section"},{"location":"","page":"Home","title":"Home","text":"There is a Jupyter-based tutorial on MRIReco at","category":"page"},{"location":"","page":"Home","title":"Home","text":"https://github.com/MagneticResonanceImaging/MRIRecoTutorial","category":"page"},{"location":"","page":"Home","title":"Home","text":"that has been presented at the ISMRM conference in Montreal 2019. Since the API has slightly changed, we, however recommend that you read this documentation and in particular execute the example scripts as is described in the Getting Started section.","category":"page"},{"location":"filehandling/#File-Handling","page":"File Handling","title":"File Handling","text":"","category":"section"},{"location":"filehandling/","page":"File Handling","title":"File Handling","text":"MRI Acquisition Data can not only be generated from simulation but also from files. Currently, MRIReco supports the ISMRMRD file format the Bruker file format (at least partially).","category":"page"},{"location":"filehandling/","page":"File Handling","title":"File Handling","text":"The ISMRMRD is fully supported with proper read and write support. For the Bruker file format only reading of data is supported.","category":"page"},{"location":"filehandling/","page":"File Handling","title":"File Handling","text":"The example discussed in the following can be run by entering","category":"page"},{"location":"filehandling/","page":"File Handling","title":"File Handling","text":"include(joinpath(dirname(pathof(MRIReco)),\"../docs/src/examples/exampleIO.jl\"))","category":"page"},{"location":"filehandling/","page":"File Handling","title":"File Handling","text":"into the Julia REPL.","category":"page"},{"location":"filehandling/","page":"File Handling","title":"File Handling","text":"We start by loading a file handle to a Bruker dataset using","category":"page"},{"location":"filehandling/","page":"File Handling","title":"File Handling","text":"f = BrukerFile(\"brukerfileCart\")","category":"page"},{"location":"filehandling/","page":"File Handling","title":"File Handling","text":"This file handle does not yet contain the data. To load the data we call","category":"page"},{"location":"filehandling/","page":"File Handling","title":"File Handling","text":"raw = RawAcquisitionData(f)","category":"page"},{"location":"filehandling/","page":"File Handling","title":"File Handling","text":"which will load all data that can be encoded into a RawAcquisitionData object. For reconstruction we can then convert it to the preprocessed data format and call","category":"page"},{"location":"filehandling/","page":"File Handling","title":"File Handling","text":"acq = AcquisitionData(raw)\n\nparams = Dict{Symbol, Any}()\nparams[:reco] = \"direct\"\nparams[:reconSize] = (acq.encodingSize[1],acq.encodingSize[2])\n\nimg = reconstruction(acq, params)","category":"page"},{"location":"filehandling/","page":"File Handling","title":"File Handling","text":"This will result in the following image:","category":"page"},{"location":"filehandling/","page":"File Handling","title":"File Handling","text":"(Image: BrukerReco)","category":"page"},{"location":"filehandling/#Saving","page":"File Handling","title":"Saving","text":"","category":"section"},{"location":"filehandling/","page":"File Handling","title":"File Handling","text":"But loading the data is only one important operation. Lets suppose that you have performed an expensive simulation resulting in a raw data object raw. To store this data one can simply run","category":"page"},{"location":"filehandling/","page":"File Handling","title":"File Handling","text":"fout = ISMRMRDFile(\"outputfile.h5\")\nsave(fout, raw)","category":"page"},{"location":"filehandling/","page":"File Handling","title":"File Handling","text":"which will generate an ISMRMRD file containing the data.","category":"page"},{"location":"filehandling/#Conversion","page":"File Handling","title":"Conversion","text":"","category":"section"},{"location":"filehandling/","page":"File Handling","title":"File Handling","text":"It should now be no surprise that MRIReco.jl does also allow for file conversion:","category":"page"},{"location":"filehandling/","page":"File Handling","title":"File Handling","text":"f = BrukerFile(\"brukerfileCart\")\nraw = RawAcquisitionData(f)\nfout = ISMRMRDFile(\"outputfile.h5\")\nsave(fout, raw)","category":"page"},{"location":"filehandling/","page":"File Handling","title":"File Handling","text":"Currently, this is only limited to converting Bruker files into ISMRMRD files but the infrastructure is not limited to that.","category":"page"}] +[{"location":"generated/examples/01-binning/","page":"Binning","title":"Binning","text":"EditURL = \"https://github.com/MagneticResonanceImaging/MRIReco.jl/blob/master/docs/lit/examples/01-binning.jl\"","category":"page"},{"location":"generated/examples/01-binning/#binning","page":"Binning","title":"Binning","text":"","category":"section"},{"location":"generated/examples/01-binning/#Description","page":"Binning","title":"Description","text":"","category":"section"},{"location":"generated/examples/01-binning/","page":"Binning","title":"Binning","text":"This example described how to perform data binning with different number of profiles which is generaly used for self-gating acquisition in order to reconstruct images along the cardiac/respiratory cycle :","category":"page"},{"location":"generated/examples/01-binning/","page":"Binning","title":"Binning","text":"Trotier AJ, Castets CR, Lefrançois W, et al. USPIO-enhanced 3D-cine self-gated cardiac MRI based on a stack-of-stars golden angle short echo time sequence: Application on mice with acute myocardial infarction. Journal of Magnetic Resonance Imaging 2016;44:355–365 doi: 10.1002/jmri.25150.\nRibot EJ, Duriez TJ, Trotier AJ, Thiaudiere E, Franconi J-M, Miraux S. Self-gated bSSFP sequences to detect iron-labeled cancer cells and/or metastases in vivo in mouse liver at 7 Tesla. Journal of Magnetic Resonance Imaging 2015;41:1413–1421 doi: 10.1002/jmri.24688.","category":"page"},{"location":"generated/examples/01-binning/","page":"Binning","title":"Binning","text":"Here, we will create a simulated 2D radial acquisition and split the projections in 2 parts along the contrast dimension. The number of projection into each bin will be different to show how MRIReco handle that case.","category":"page"},{"location":"generated/examples/01-binning/#Setup","page":"Binning","title":"Setup","text":"","category":"section"},{"location":"generated/examples/01-binning/","page":"Binning","title":"Binning","text":"using CairoMakie\nusing ImageUtils: shepp_logan\nusing MRIReco, MRISimulation\n\nfunction plot_im2D(im2D;title::String=\"\")\n f = Figure()\n ax = Axis(f[1, 1],aspect = DataAspect(), yreversed = true, title = title)\n image!(ax, im2D')\n hidedecorations!(ax, grid = false)\n f\nend","category":"page"},{"location":"generated/examples/01-binning/#Simulate-a-radial-acquisition","page":"Binning","title":"Simulate a radial acquisition","text":"","category":"section"},{"location":"generated/examples/01-binning/","page":"Binning","title":"Binning","text":"N = 256\nx = shepp_logan(N)\n\nparams = Dict{Symbol, Any}()\nparams[:simulation] = \"fast\"\nparams[:trajName] = \"Radial\"\nparams[:numProfiles] = round(Int64,400)\nparams[:numSamplingPerProfile] = round(Int64,N)\n\nacqRad = simulation(x, params)\nrawRad = RawAcquisitionData(acqRad)","category":"page"},{"location":"generated/examples/01-binning/","page":"Binning","title":"Binning","text":"For real acquisition we first create the RawAcquisitionData structure and then convert into the AcquisitionData.","category":"page"},{"location":"generated/examples/01-binning/#Binning-Data","page":"Binning","title":"Binning Data","text":"","category":"section"},{"location":"generated/examples/01-binning/","page":"Binning","title":"Binning","text":"rawRad2 = deepcopy(rawRad)\nfor i in 1:length(rawRad.profiles)\n if mod(i,4) == 0\n rawRad2.profiles[i].head.idx.contrast = 0\n else\n rawRad2.profiles[i].head.idx.contrast = 1\n end\nend;\nnothing #hide","category":"page"},{"location":"generated/examples/01-binning/","page":"Binning","title":"Binning","text":"We need to tell to MRIReco that our trajectory is a custom one :","category":"page"},{"location":"generated/examples/01-binning/","page":"Binning","title":"Binning","text":"rawRad2.params[\"trajectory\"] = \"custom\";\nnothing #hide","category":"page"},{"location":"generated/examples/01-binning/#Reconstruction","page":"Binning","title":"Reconstruction","text":"","category":"section"},{"location":"generated/examples/01-binning/","page":"Binning","title":"Binning","text":"To perform the reconstruction we need to convert the RawAcquisitionData into and AcquisitionData structure.","category":"page"},{"location":"generated/examples/01-binning/","page":"Binning","title":"Binning","text":"acqRad2 = AcquisitionData(rawRad2)","category":"page"},{"location":"generated/examples/01-binning/","page":"Binning","title":"Binning","text":"We can also plot the number of projection for both bin :","category":"page"},{"location":"generated/examples/01-binning/","page":"Binning","title":"Binning","text":"nPro1 = Int32(length(acqRad2.kdata[1,1,1])/N)\nnPro2 = Int32(length(acqRad2.kdata[2,1,1])/N)\nprintln(\"Number of projection in : \\n\n- Bin 1 = $nPro1\\n\n- Bin 2 = $nPro2\")","category":"page"},{"location":"generated/examples/01-binning/","page":"Binning","title":"Binning","text":"Now we can perform a standard reconstruction","category":"page"},{"location":"generated/examples/01-binning/","page":"Binning","title":"Binning","text":"params = Dict{Symbol, Any}()\nparams[:reco] = \"direct\"\nparams[:reconSize] = (N,N)\n\nIreco = reconstruction(acqRad2, params)\nsize(Ireco)","category":"page"},{"location":"generated/examples/01-binning/","page":"Binning","title":"Binning","text":"let's show the results for first bin","category":"page"},{"location":"generated/examples/01-binning/","page":"Binning","title":"Binning","text":"plot_im2D(abs.(Ireco[:,:,1,1]),title = \"First bin\")","category":"page"},{"location":"generated/examples/01-binning/","page":"Binning","title":"Binning","text":"and the second bin","category":"page"},{"location":"generated/examples/01-binning/","page":"Binning","title":"Binning","text":"plot_im2D(abs.(Ireco[:,:,1,2]),title = \"Second bin\")","category":"page"},{"location":"generated/examples/01-binning/","page":"Binning","title":"Binning","text":"As expected we have more streaking artifacts on the first bin because we reconstruct the image with less projections.","category":"page"},{"location":"generated/examples/01-binning/#Reproducibility","page":"Binning","title":"Reproducibility","text":"","category":"section"},{"location":"generated/examples/01-binning/","page":"Binning","title":"Binning","text":"This page was generated with the following version of Julia:","category":"page"},{"location":"generated/examples/01-binning/","page":"Binning","title":"Binning","text":"io = IOBuffer();\nversioninfo(io);\nsplit(String(take!(io)), '\\n')","category":"page"},{"location":"generated/examples/01-binning/","page":"Binning","title":"Binning","text":"And with the following package versions","category":"page"},{"location":"generated/examples/01-binning/","page":"Binning","title":"Binning","text":"import Pkg; Pkg.status()","category":"page"},{"location":"generated/examples/01-binning/","page":"Binning","title":"Binning","text":"","category":"page"},{"location":"generated/examples/01-binning/","page":"Binning","title":"Binning","text":"This page was generated using Literate.jl.","category":"page"},{"location":"acquisitionData/#Acquisition-Data","page":"Acquisition Data","title":"Acquisition Data","text":"","category":"section"},{"location":"acquisitionData/","page":"Acquisition Data","title":"Acquisition Data","text":"There are two different forms of acquisition data types in MRIReco:","category":"page"},{"location":"acquisitionData/","page":"Acquisition Data","title":"Acquisition Data","text":"RawAcquisitionData\nAcquisitionData","category":"page"},{"location":"acquisitionData/","page":"Acquisition Data","title":"Acquisition Data","text":"While the former is used to hold the data in the form, how it will be written out from the scanner, the later has already performed some data permutations bringing the data into the shape how the reconstruction expects it.","category":"page"},{"location":"acquisitionData/#Raw-Data","page":"Acquisition Data","title":"Raw Data","text":"","category":"section"},{"location":"acquisitionData/","page":"Acquisition Data","title":"Acquisition Data","text":"The RawAcquisitionData is a data type that closely resembles the ISMRMRD data format. It looks like","category":"page"},{"location":"acquisitionData/","page":"Acquisition Data","title":"Acquisition Data","text":"mutable struct RawAcquisitionData\n params::Dict{String, Any}\n profiles::Vector{Profile}\nend","category":"page"},{"location":"acquisitionData/","page":"Acquisition Data","title":"Acquisition Data","text":"with","category":"page"},{"location":"acquisitionData/","page":"Acquisition Data","title":"Acquisition Data","text":"mutable struct Profile\n head::AcquisitionHeader\n traj::Array{Float32,2}\n data::Array{Complex{Float32},2}\nend","category":"page"},{"location":"acquisitionData/","page":"Acquisition Data","title":"Acquisition Data","text":"The params member of RawAcquisitionData is basically the a flattened dictionary derived from the XML part of an ISMRMRD file. A Profile describes the data measured after a single excitation during an MRI experiment. It has members head, traj, and data, which exactly resemble the structures specified by the ISMRMRD file format.","category":"page"},{"location":"acquisitionData/#Preprocessed-Data","page":"Acquisition Data","title":"Preprocessed Data","text":"","category":"section"},{"location":"acquisitionData/","page":"Acquisition Data","title":"Acquisition Data","text":"The RawAcquisitionData can be preprocessed into a form, which makes it more convenient for reconstruction algorithms. The AcquisitionData type looks like","category":"page"},{"location":"acquisitionData/","page":"Acquisition Data","title":"Acquisition Data","text":"mutable struct AcquisitionData\n sequenceInfo::Dict{Symbol,Any}\n traj::Vector{Trajectory}\n kdata::Array{Matrix{ComplexF64},3}\n subsampleIndices::Vector{Array{Int64}}\n encodingSize::Vector{Int64}\n fov::Vector{Float64}\nend","category":"page"},{"location":"acquisitionData/","page":"Acquisition Data","title":"Acquisition Data","text":"It consists of the sequence informations stored in a dictionary, the k-space trajectory, the k-space data, and several parameters describing the dimension of the data and some additional index vectors.","category":"page"},{"location":"acquisitionData/","page":"Acquisition Data","title":"Acquisition Data","text":"The k-space data kdata has three dimensions encoding","category":"page"},{"location":"acquisitionData/","page":"Acquisition Data","title":"Acquisition Data","text":"dim : contrasts/echoes\ndim : slices\ndim : repetitions","category":"page"},{"location":"acquisitionData/","page":"Acquisition Data","title":"Acquisition Data","text":"Each element is a matrix encoding","category":"page"},{"location":"acquisitionData/","page":"Acquisition Data","title":"Acquisition Data","text":"dim : k-space nodes\ndim : channels/coils","category":"page"},{"location":"acquisitionData/","page":"Acquisition Data","title":"Acquisition Data","text":"In case of undersampled data, the subsampling indices are stored in subsampleIndices. One check if the data is undersampled by checking if isempty(subsampleIndices).","category":"page"},{"location":"acquisitionData/","page":"Acquisition Data","title":"Acquisition Data","text":"The encoded space is stored in the field encodingSize. It is especially relevant for non-Cartesian trajectories where it is not clear upfront, how large the grid size for reconstruction should be chosen. Finally fov describes the physical lengths of the encoding grid.","category":"page"},{"location":"trajectories/#Trajectory","page":"Trajectory","title":"Trajectory","text":"","category":"section"},{"location":"trajectories/","page":"Trajectory","title":"Trajectory","text":"Several typical MRI k-space trajectories are available:","category":"page"},{"location":"trajectories/","page":"Trajectory","title":"Trajectory","text":"Cartesian\nEPI\nRadial\nSpiral","category":"page"},{"location":"trajectories/","page":"Trajectory","title":"Trajectory","text":"In addition, it is also possible to define new k-space trajectories. Currently, most of the trajectories are only available in 2D. Each trajectory is of type Trajectory and implements the following functions","category":"page"},{"location":"trajectories/","page":"Trajectory","title":"Trajectory","text":"string(tr::Trajectory)\nkspaceNodes(tr::Trajectory)\nreadoutTimes(tr::Trajectory)","category":"page"},{"location":"trajectories/","page":"Trajectory","title":"Trajectory","text":"For instance we can define a spiral, radial, and cartesian trajectory using","category":"page"},{"location":"trajectories/","page":"Trajectory","title":"Trajectory","text":"tr = trajectory(\"Spiral\", 1, 600, windings=10)\ntr = trajectory(\"Cartesian\", 13, 50, EPI_factor=1)\ntr = trajectory(\"Radial\", 13, 50)","category":"page"},{"location":"trajectories/","page":"Trajectory","title":"Trajectory","text":"A variable density spiral can be generated by","category":"page"},{"location":"trajectories/","page":"Trajectory","title":"Trajectory","text":"tr = trajectory(\"SpiralVarDens\", 3, 200)","category":"page"},{"location":"trajectories/","page":"Trajectory","title":"Trajectory","text":"The k-space nodes can then be accessed by","category":"page"},{"location":"trajectories/","page":"Trajectory","title":"Trajectory","text":"nodes = kspaceNodes(tr)","category":"page"},{"location":"trajectories/","page":"Trajectory","title":"Trajectory","text":"The script generating the following image can be executed by running the following from within the Julia REPL:","category":"page"},{"location":"trajectories/","page":"Trajectory","title":"Trajectory","text":"include(joinpath(dirname(pathof(MRIReco)),\"../docs/src/examples/exampleTrajectories.jl\"))","category":"page"},{"location":"trajectories/","page":"Trajectory","title":"Trajectory","text":"(Image: Trajectories)","category":"page"},{"location":"compressedSensing/#Compressed-Sensing","page":"Compressed Sensing","title":"Compressed Sensing","text":"","category":"section"},{"location":"compressedSensing/","page":"Compressed Sensing","title":"Compressed Sensing","text":"We next consider a compressed sensing reconstruction using one slice of a knee dataset obtained from mridata.org. The example can be run by entering","category":"page"},{"location":"compressedSensing/","page":"Compressed Sensing","title":"Compressed Sensing","text":"include(joinpath(dirname(pathof(MRIReco)),\"../docs/src/examples/exampleCS.jl\"))","category":"page"},{"location":"compressedSensing/","page":"Compressed Sensing","title":"Compressed Sensing","text":"into the Julia REPL.","category":"page"},{"location":"compressedSensing/","page":"Compressed Sensing","title":"Compressed Sensing","text":"We first perform a baseline reconstruction with fully sampled data:","category":"page"},{"location":"compressedSensing/","page":"Compressed Sensing","title":"Compressed Sensing","text":"# load fully sampled data\nf = ISMRMRDFile(\"data/knee_3dFSE_slice170.h5\")\nacqData = AcquisitionData(f);\n\n# reconstruct\nparams = Dict{Symbol, Any}()\nparams[:reco] = \"direct\"\nparams[:reconSize] = (320,320) # this size is also contained in acqData.encodingSize\n\nimg = reconstruction(acqData, params)\nimg = sqrt.(sum(img.^2,dims=5))","category":"page"},{"location":"compressedSensing/","page":"Compressed Sensing","title":"Compressed Sensing","text":"The result looks like this:","category":"page"},{"location":"compressedSensing/","page":"Compressed Sensing","title":"Compressed Sensing","text":"(Image: Knee Original)","category":"page"},{"location":"compressedSensing/","page":"Compressed Sensing","title":"Compressed Sensing","text":"To simulate an undersampled reconstruction, we retrospectively undersample the data using a Poisson disk pattern.","category":"page"},{"location":"compressedSensing/","page":"Compressed Sensing","title":"Compressed Sensing","text":"redFac = 4.0\nacqDataSub = sample_kspace(acqData,redFac,\"poisson\",calsize=30,profiles=false);","category":"page"},{"location":"compressedSensing/","page":"Compressed Sensing","title":"Compressed Sensing","text":"The sampling pattern looks like this:","category":"page"},{"location":"compressedSensing/","page":"Compressed Sensing","title":"Compressed Sensing","text":"(Image: Mask)","category":"page"},{"location":"compressedSensing/","page":"Compressed Sensing","title":"Compressed Sensing","text":"Then, we estimate the coil sensitivities using ESPIRiT","category":"page"},{"location":"compressedSensing/","page":"Compressed Sensing","title":"Compressed Sensing","text":"smaps = espirit(acqData,(6,6),30,eigThresh_1=0.035,eigThresh_2=0.98)","category":"page"},{"location":"compressedSensing/","page":"Compressed Sensing","title":"Compressed Sensing","text":"and perform a simple SENSE reconstruction. We expect a degradation in image quality due to the subsampling:","category":"page"},{"location":"compressedSensing/","page":"Compressed Sensing","title":"Compressed Sensing","text":"params = Dict{Symbol, Any}()\nparams[:reco] = \"multiCoil\"\nparams[:reconSize] = (320,320)\nparams[:senseMaps] = smaps\n\nparams[:solver] = \"cgnr\"\nparams[:regularization] = \"L2\"\nparams[:λ] = 1.e-4\nparams[:iterations] = 5\nparams[:normalizeReg] = true\n\nimg_cg = reconstruction(acqDataSub, params)","category":"page"},{"location":"compressedSensing/","page":"Compressed Sensing","title":"Compressed Sensing","text":"Using TV regularization recquires us to change some parameters:","category":"page"},{"location":"compressedSensing/","page":"Compressed Sensing","title":"Compressed Sensing","text":"params = Dict{Symbol, Any}()\nparams[:reco] = \"multiCoil\"\nparams[:reconSize] = (320,320)\nparams[:senseMaps] = smaps\n\nparams[:solver] = \"admm\"\nparams[:regularization] = \"TV\"\nparams[:λ] = 1.e-1 # 5.e-2\nparams[:iterations] = 50\nparams[:ρ] = 0.1\nparams[:absTol] = 1.e-4\nparams[:relTol] = 1.e-2\nparams[:tolInner] = 1.e-2\nparams[:normalizeReg] = true\n\nimg_tv = reconstruction(acqDataSub, params)","category":"page"},{"location":"compressedSensing/","page":"Compressed Sensing","title":"Compressed Sensing","text":"Lets compare the results, left the regular SENSE reconstruction and right the TV reglarized solution:","category":"page"},{"location":"compressedSensing/","page":"Compressed Sensing","title":"Compressed Sensing","text":"(Image: SENSE) (Image: TV)","category":"page"},{"location":"image/#Images","page":"Images","title":"Images","text":"","category":"section"},{"location":"image/","page":"Images","title":"Images","text":"All reconstructed data is stored as an AxisArray. The AxisArrays package is part of the Images package family, which groups all image processing related functionality together. We note that the term Image does not restrict the dimensionality of the data types to 2D but in fact images can be of arbitrary dimensionality.","category":"page"},{"location":"image/","page":"Images","title":"Images","text":"The reconstructed MRI image I is an AxisArray and has five dimensions. The first three are the spatial dimension x, y, and z, whereas dimension four encodes the number of echos that have been reconstructed, while dimension five encodes individual coils that may have been reconstructed independently. By using an AxisArray the object does not only consist of the data but it additionally encodes the physical size of the image as well as the echo times. To extract the ordinary Julia array one can simply use Ireco.data.","category":"page"},{"location":"image/","page":"Images","title":"Images","text":"The advantage of encoding the physical dimensions is the image data can be stored without loosing the dimensions of the data. For instance one can call","category":"page"},{"location":"image/","page":"Images","title":"Images","text":"saveImage(filename, I)","category":"page"},{"location":"image/","page":"Images","title":"Images","text":"to store the image and","category":"page"},{"location":"image/","page":"Images","title":"Images","text":"I = loadImage(filename)","category":"page"},{"location":"image/","page":"Images","title":"Images","text":"to load the image. Currently, MRIReco does support the NIfTI file format. By default, saveImage stores the data complex valued if the image I is complex valued. To store the magnitude image one can call","category":"page"},{"location":"image/","page":"Images","title":"Images","text":"saveImage(filename, I, true)","category":"page"},{"location":"offresonance/#Offresonance-Correction","page":"Offresonance","title":"Offresonance Correction","text":"","category":"section"},{"location":"offresonance/","page":"Offresonance","title":"Offresonance","text":"For trajectories with long readouts the MRI images are degraded by offresonance artifacts, if the offresonance is not taken into account during reconstruction. We provide fast algorithms that are capable of correcting offresonance artifacts provided that the offresonance map is known. Our framework is also capable of correcting T2* relaxation effects. The later are encoded in the real part of the correction map while the offresoanance is encoded in the imaginary part. The following example shows an example of a simulation and reconstruction of MRI data that takes offresonance due to an inhomogeneous fieldmap into account. The example can be run by entering","category":"page"},{"location":"offresonance/","page":"Offresonance","title":"Offresonance","text":"include(joinpath(dirname(pathof(MRIReco)),\"../docs/src/examples/exampleFieldmap.jl\"))","category":"page"},{"location":"offresonance/","page":"Offresonance","title":"Offresonance","text":"into the Julia REPL.","category":"page"},{"location":"offresonance/","page":"Offresonance","title":"Offresonance","text":"using MRIReco\n\nN = 256\nI = shepp_logan(N)\nI = circularShutterFreq!(I,1)\ncmap = 1im*quadraticFieldmap(N,N,125*2pi)\n\n# simulation parameters\nparams = Dict{Symbol, Any}()\nparams[:simulation] = \"fast\"\nparams[:trajName] = \"Spiral\"\nparams[:numProfiles] = 1\nparams[:numSamplingPerProfile] = N*N\nparams[:windings] = 128\nparams[:AQ] = 3.0e-2\nparams[:correctionMap] = cmap[:,:,1]\n\n# do simulation\nacqData = simulation(I, params)\n\n# reco parameters\nparams = Dict{Symbol, Any}()\nparams[:reco] = \"direct\"\nparams[:reconSize] = (N,N)\nparams[:correctionMap] = cmap\nparams[:alpha] = 1.75\nparams[:m] = 4.0\nparams[:K] = 28\n\n# do reconstruction\nIreco = reconstruction(acqData, params)","category":"page"},{"location":"offresonance/","page":"Offresonance","title":"Offresonance","text":"The considered quadratic fieldmap looks like this:","category":"page"},{"location":"offresonance/","page":"Offresonance","title":"Offresonance","text":"(Image: Fieldmap)","category":"page"},{"location":"offresonance/","page":"Offresonance","title":"Offresonance","text":"The reconstruction without and with offresonance correction are shown below:","category":"page"},{"location":"offresonance/","page":"Offresonance","title":"Offresonance","text":"(Image: NoCorrection) (Image: Reconstruction)","category":"page"},{"location":"custom/#Customization","page":"Customize","title":"Customization","text":"","category":"section"},{"location":"custom/","page":"Customize","title":"Customize","text":"We promised that MRIReco allows for customization. Lets in the following consider a custom data-driven sparsifying transform that is currently not part of MRIReco.jl [S. Ravishankar and Y. Bresler, IEEE Trans. Med. Imaging, 30 (5), 2011].","category":"page"},{"location":"custom/","page":"Customize","title":"Customize","text":"It is based on","category":"page"},{"location":"custom/","page":"Customize","title":"Customize","text":"Learn a dictionary from a reference image (e.g. adjacent slice) using KSVD colorgreencheckmark\nImplement sparsifying transform which analyses the input image in terms of the dictionary","category":"page"},{"location":"custom/","page":"Customize","title":"Customize","text":"(Image: DictTrafo)","category":"page"},{"location":"custom/","page":"Customize","title":"Customize","text":"In order to implement this, we first need the analyze function where we can reuse the matchingpursuit function from Wavelets.jl","category":"page"},{"location":"custom/","page":"Customize","title":"Customize","text":"function analyzeImage(x::Vector{T},D::Matrix{T},xsize::NTuple{2,Int64},\n psize::NTuple{2,Int64};t0::Int64=size(D,2),tol=1e-3) where T\n nx,ny = xsize\n px,py = psize\n x = reshape(x,nx,ny)\n x_pad = repeat(x,2,2)[1:nx+px-1,1:ny+py-1] # pad image using periodic boundary conditions\n α = zeros(T,size(D,2),nx,ny)\n patch = zeros(T,px*py)\n for j=1:ny\n for i=1:nx\n patch[:] .= vec(x_pad[i:i+px-1,j:j+py-1])\n norm(patch)==0 && continue\n # matchingpursuit is contained in Wavelets.jl\n α[:,i,j] .= matchingpursuit(patch, x->D*x, x->transpose(D)*x, tol)\n end\n end\n return vec(α)\nend","category":"page"},{"location":"custom/","page":"Customize","title":"Customize","text":"Synthetization can be done by","category":"page"},{"location":"custom/","page":"Customize","title":"Customize","text":"function synthesizeImage(α::Vector{T},D::Matrix{T},xsize::NTuple{2,Int64},psize::NTuple{2,Int64}) where T\n nx,ny = xsize\n px,py = psize\n x = zeros(T,nx+px-1,ny+py-1)\n α = reshape(α,:,nx,ny)\n for j=1:ny\n for i=1:nx\n x[i:i+px-1,j:j+py-1] .+= reshape(D*α[:,i,j],px,py)\n end\n end\n return vec(x[1:nx,1:ny])/(px*py)\nend","category":"page"},{"location":"custom/","page":"Customize","title":"Customize","text":"Once we have those two operations we can setup up a dictionary operator:","category":"page"},{"location":"custom/","page":"Customize","title":"Customize","text":"function dictOp(D::Matrix{T},xsize::NTuple{2,Int64},psize::NTuple{2,Int64},tol::Float64=1.e-3) where T\n produ = x->analyzeImage(x,D,xsize,psize,tol=tol)\n ctprodu = x->synthesizeImage(x,D,xsize,psize)\n return LinearOperator(prod(xsize)*size(D,2),prod(xsize),false,false\n , produ\n , nothing\n , ctprodu )\nend","category":"page"},{"location":"custom/","page":"Customize","title":"Customize","text":"To test our method, let us load some simulated data and subsample it","category":"page"},{"location":"custom/","page":"Customize","title":"Customize","text":"# phantom\nimg = readdlm(\"data/mribrain100.tsv\")\n\nacqData = AcquisitionData(ISMRMRDFile(\"data/acqDataBrainSim100.h5\"))\nnx,ny = acqData.encodingSize\n\n# undersample kspace data\nacqData = sample_kspace(acqData, 2.0, \"poisson\", calsize=25,profiles=false);","category":"page"},{"location":"custom/","page":"Customize","title":"Customize","text":"Now we load a pre-trained dictionary, build the sparsifying transform and perform the reconstruction","category":"page"},{"location":"custom/","page":"Customize","title":"Customize","text":"# load the dictionary\nD = ComplexF64.(readdlm(\"data/brainDict98.tsv\"))\n\n# some parameters\npx, py = (6,6) # patch size\nK = px*py # number of atoms\n\n# CS reconstruction using Wavelets\nparams = Dict{Symbol,Any}()\nparams[:reco] = \"standard\"\nparams[:reconSize] = (nx,ny)\nparams[:iterations] = 50\nparams[:λ] = 2.e-2\nparams[:regularization] = \"L1\"\nparams[:sparseTrafo] = dictOp(D,(nx,ny),(px,py),2.e-2)\nparams[:ρ] = 0.1\nparams[:solver] = \"admm\"\nparams[:absTol] = 1.e-4\nparams[:relTol] = 1.e-2\n\nimg_d = reconstruction(acqData,params)","category":"page"},{"location":"custom/","page":"Customize","title":"Customize","text":"For comparison, let us perform the same reconstruction as above but with a Wavelet transform","category":"page"},{"location":"custom/","page":"Customize","title":"Customize","text":"delete!(params, :sparseTrafo)\nparams[:sparseTrafoName] = \"Wavelet\"\n\nimg_w = reconstruction(acqData,params)","category":"page"},{"location":"custom/","page":"Customize","title":"Customize","text":"The following pictures shows the wavelet based CS reconstruction on the left and the dictionary based CS reconstruction on the right:","category":"page"},{"location":"custom/","page":"Customize","title":"Customize","text":"(Image: BrainWavelet) (Image: BrainDict)","category":"page"},{"location":"custom/","page":"Customize","title":"Customize","text":"For reference, the original data is shown here:","category":"page"},{"location":"custom/","page":"Customize","title":"Customize","text":"(Image: BrainOrig)","category":"page"},{"location":"custom/","page":"Customize","title":"Customize","text":"One can clearly see that the dictionary approach performs better than a simple Wavelet L1 prior.","category":"page"},{"location":"gettingStarted/#Getting-Started","page":"Getting Started","title":"Getting Started","text":"","category":"section"},{"location":"gettingStarted/","page":"Getting Started","title":"Getting Started","text":"Throughout the entire documentation we assume that you have loaded MRIReco as well as PyPlot via","category":"page"},{"location":"gettingStarted/","page":"Getting Started","title":"Getting Started","text":"using PyPlot, MRIReco","category":"page"},{"location":"gettingStarted/","page":"Getting Started","title":"Getting Started","text":"Its important to load these packages in that order, since otherwise PyPlot will not work correctly on some systems.","category":"page"},{"location":"gettingStarted/","page":"Getting Started","title":"Getting Started","text":"All examples discussed in the documentation can be found in the package source code in the folder","category":"page"},{"location":"gettingStarted/","page":"Getting Started","title":"Getting Started","text":" MRIReco/docs/src/examples","category":"page"},{"location":"gettingStarted/","page":"Getting Started","title":"Getting Started","text":"This folder is located in ~/.julia/packages or ~/.julia/dev depending if you have checked out MRIReco for development or not. You can call the first example by entering into the Julia REPL:","category":"page"},{"location":"gettingStarted/","page":"Getting Started","title":"Getting Started","text":"include(joinpath(dirname(pathof(MRIReco)),\"../docs/src/examples/exampleRadial.jl\"))","category":"page"},{"location":"gettingStarted/","page":"Getting Started","title":"Getting Started","text":"which should open a plotting window as is outlined in the following example.","category":"page"},{"location":"gettingStarted/#Basic-Example","page":"Getting Started","title":"Basic Example","text":"","category":"section"},{"location":"gettingStarted/","page":"Getting Started","title":"Getting Started","text":"We will start with a very simple example and perform simple simulation and reconstruction based on a shepp logan phantom. The program looks like this","category":"page"},{"location":"gettingStarted/","page":"Getting Started","title":"Getting Started","text":"# image\nN = 256\nI = shepp_logan(N)\n\n# simulation parameters\nparams = Dict{Symbol, Any}()\nparams[:simulation] = \"fast\"\nparams[:trajName] = \"Radial\"\nparams[:numProfiles] = floor(Int64, pi/2*N)\nparams[:numSamplingPerProfile] = 2*N\n\n# do simulation\nacqData = simulation(I, params)\n\n# reco parameters\nparams = Dict{Symbol, Any}()\nparams[:reco] = \"direct\"\nparams[:reconSize] = (N,N)\nIreco = reconstruction(acqData, params)","category":"page"},{"location":"gettingStarted/","page":"Getting Started","title":"Getting Started","text":"We will go through the program step by step. First we create a 2D shepp logan phantom of size N=256. Then we setup a dictionary that defines the simulation parameters. Here, we chose a simple radial trajectory with 402 spokes and 512 samples per profile. We use a gridding-based simulator by setting params[:simulation] = \"fast\"","category":"page"},{"location":"gettingStarted/","page":"Getting Started","title":"Getting Started","text":"After setting up the parameter dictionary params, the simulation is performed by calling","category":"page"},{"location":"gettingStarted/","page":"Getting Started","title":"Getting Started","text":"acqData = simulation(I, params)","category":"page"},{"location":"gettingStarted/","page":"Getting Started","title":"Getting Started","text":"The result simulation function outputs an acquisition object that is discussed in more detail in the section Acquisition Data. The acquisition data can also be stored to or loaded from a file, which will be discussed in section File Handling.","category":"page"},{"location":"gettingStarted/","page":"Getting Started","title":"Getting Started","text":"Using the acquisition data we can perform a reconstruction. To this end, again a parameter dictionary is setup and some basic configuration is done. In this case, for instance we specify that we want to apply a simple NFFT-based gridding reconstruction. The reconstruction is invoked by calling","category":"page"},{"location":"gettingStarted/","page":"Getting Started","title":"Getting Started","text":"Ireco = reconstruction(acqData, params)","category":"page"},{"location":"gettingStarted/","page":"Getting Started","title":"Getting Started","text":"The resulting image is of type AxisArray and has 5 dimensions. One can display the image object by calling","category":"page"},{"location":"gettingStarted/","page":"Getting Started","title":"Getting Started","text":"imshow(abs.(Ireco[:,:,1,1,1]))","category":"page"},{"location":"gettingStarted/","page":"Getting Started","title":"Getting Started","text":"Alternatively one can store the image into a file, which will be discussed in the section on Images.","category":"page"},{"location":"gettingStarted/","page":"Getting Started","title":"Getting Started","text":"The original phantom and the reconstructed image are shown below","category":"page"},{"location":"gettingStarted/","page":"Getting Started","title":"Getting Started","text":"(Image: Phantom) (Image: Reconstruction)","category":"page"},{"location":"gettingStarted/","page":"Getting Started","title":"Getting Started","text":"We will discuss reconstruction in more detail in the sections on Offresonance Correction, Parallel Imaging, and Compressed Sensing","category":"page"},{"location":"API/#API","page":"API","title":"API","text":"","category":"section"},{"location":"API/","page":"API","title":"API","text":"This page contains documentation of the public API of MRIReco. In the Julia REPL one can access this documentation by entering the help mode with ? and then writing the function for which the documentation should be shown.","category":"page"},{"location":"API/#Operators","page":"API","title":"Operators","text":"","category":"section"},{"location":"API/","page":"API","title":"API","text":"Operators are implemented as subtypes of AbstractLinearOperator, which is defined in the package LinearOperators.jl. Such operators must provide a function implementing the product and a function implementing the product with the adjoint. Furthermore, the number of rows and columns of the operator must be specified.","category":"page"},{"location":"API/","page":"API","title":"API","text":"MRIReco.encodingOps2d_simple\nMRIReco.encodingOps3d_simple\nMRIReco.encodingOps2d_parallel\nMRIReco.encodingOps3d_parallel\nMRIReco.encodingOp2d_multiEcho\nMRIReco.encodingOp3d_multiEcho\nMRIReco.encodingOp2d_multiEcho_parallel\nMRIReco.encodingOp3d_multiEcho_parallel\nMRIReco.fourierEncodingOp2d\nMRIReco.fourierEncodingOp3d\nMRIReco.ExplicitOp(shape::NTuple{D,Int64}, tr::Trajectory, correctionmap::Array{ComplexF64,D}; MRIReco.echoImage::Bool=false, kargs...) where D\nRegularizedLeastSquares.FFTOp(T::Type, shape::Tuple, shift=true)\nMRIReco.NFFTOp(shape::Tuple, tr::Trajectory; nodes=nothing, kargs...)\nMRIReco.FieldmapNFFTOp(shape::NTuple{D,Int64}, tr::Trajectory,\n correctionmap::Array{ComplexF64,D};\n method::String=\"nfft\",\n echoImage::Bool=true,\n alpha::Float64=1.75,\n m::Float64=3.0,\n K=20,\n kargs...) where D\nMRIReco.SamplingOp\nMRIReco.SensitivityOp\nMRIReco.SparseOp\nMRIReco.RegularizedLeastSquares.WeightingOp","category":"page"},{"location":"API/#Datatypes","page":"API","title":"Datatypes","text":"","category":"section"},{"location":"API/","page":"API","title":"API","text":"MRIReco.AcquisitionData\nMRIReco.AcquisitionData(tr::T,kdata::Array{Matrix{ComplexF64},3}\n ; seqInfo=Dict{Symbol,Any}()\n , idx=nothing\n , encodingSize=Int64[0,0,0]\n , fov=Float64[0,0,0]\n , kargs...) where T <: Union{Trajectory,Vector{Trajectory}}\nMRIReco.trajectory(acqData::AcquisitionData,i::Int64=1)\nMRIReco.numContrasts(acqData::AcquisitionData)\nMRIReco.numChannels\nMRIReco.numSlices\nMRIReco.numRepetitions\nMRIReco.kData\nMRIReco.multiEchoData\nMRIReco.multiCoilData\nMRIReco.multiCoilMultiEchoData\nMRIReco.profileData\nMRIReco.samplingDensity\nMRIReco.changeEncodingSize2D\nMRIReco.convert3dTo2d\nMRIReco.RawAcquisitionData\nMRIReco.trajectory(f::RawAcquisitionData; slice::Int=1, contrast::Int=1)\nMRIReco.rawdata(f::RawAcquisitionData)\nMRIReco.AcquisitionData(f::RawAcquisitionData)\nMRIReco.RawAcquisitionData(f::ISMRMRDFile, dataset=\"dataset\")\nMRIReco.AcquisitionData(f::ISMRMRDFile, dataset=\"dataset\")","category":"page"},{"location":"API/#Trajectories","page":"API","title":"Trajectories","text":"","category":"section"},{"location":"API/","page":"API","title":"API","text":"MRIReco.Trajectory\nMRIReco.trajectory(trajName::AbstractString, numProfiles::Int, numSamplingPerProfile::Int; MRIReco.numSlices::Int64=1, TE::Float64=0.0, AQ::Float64=1.e-3, kargs...)\nMRIReco.string(tr::Trajectory)\nMRIReco.echoTime(tr::Trajectory)\nMRIReco.acqTimePerProfile(tr::Trajectory)\nMRIReco.numProfiles(tr::Trajectory)\nMRIReco.numSamplingPerProfile(tr::Trajectory)\nMRIReco.numSlices(tr::Trajectory)\nMRIReco.isCircular(tr::Trajectory)\nMRIReco.isCartesian(tr::Trajectory)\nMRIReco.dims(tr::Trajectory)\nMRIReco.kspaceNodes(tr::Trajectory)\nMRIReco.readoutTimes(tr::Trajectory)\nMRIReco.CartesianTrajectory\nMRIReco.EPITrajectory\nMRIReco.OneLine2dTrajectory\nMRIReco.RadialTrajectory\nMRIReco.SpiralTrajectory\nMRIReco.SpiralTrajectoryVarDens\nMRIReco.CartesianTrajectory3D\nMRIReco.KooshballTrajectory\nMRIReco.StackOfStarsTrajectory","category":"page"},{"location":"API/#Sequences","page":"API","title":"Sequences","text":"","category":"section"},{"location":"API/","page":"API","title":"API","text":"MRIReco.MESequence\nMRIReco.numContrasts(seq::MESequence)\nMRIReco.echoTimes(seq::MESequence)\nMRIReco.flipAngles(seq::MESequence)\nMRIReco.echoAmplitudes(seq::MESequence, R1::Float64, R2::Float64, numStates=nothing)\nMRIReco.epgAmplitudes(seq::MESequence, R1::Real, R2::Real, numStates=nothing)\nMRIReco.epgRotation\nMRIReco.epgRelaxation\nMRIReco.epgDephasing\nMRIReco.rfRotation","category":"page"},{"location":"API/#Sampling","page":"API","title":"Sampling","text":"","category":"section"},{"location":"API/","page":"API","title":"API","text":"MRIReco.sample\nMRIReco.sample_kspace(data::AbstractArray,redFac::Float64,patFunc::AbstractString;kargs...)\nMRIReco.sample_kspace(acqData::AcquisitionData,redFac::Float64,\n patFunc::AbstractString; rand=true, profiles=true,\n seed = 1234, kargs...)\nMRIReco.sample_regular(shape::Tuple, redFac::Float64; kargs...)\nMRIReco.sample_random(shape::Tuple{Int64,Int64},redFac::Float64;calsize::Int64=0,kargs...)\nMRIReco.sample_poissondisk(shape::Tuple{Int64,Int64},redFac::Float64;calsize::Int64=0, seed::Int64=1234,kargs...)\nMRIReco.sample_vdpoisson(shape::Tuple{Int64,Int64},redFac::Float64; seed::Int64=1234,kargs...)\nMRIReco.sample_lines(shape::Tuple{Int64,Int64},redFac::Float64;sampleFunc=\"random\",kargs...)\nMRIReco.calculateIncoherence(acqData::AcquisitionData, recoParams::Dict, slice=1)","category":"page"},{"location":"API/#Simulation","page":"API","title":"Simulation","text":"","category":"section"},{"location":"API/","page":"API","title":"API","text":"MRIReco.simulation(image::Array{T,3}, simParams::Dict) where T<:Union{ComplexF64,Float64}\nMRIReco.simulation(image::Array{T,3}, simParams::Dict, filename::String;\n force=false) where T<:Union{ComplexF64,Float64}\nMRIReco.simulation(image::Array{T,2}, simParams::Dict) where T<:Union{ComplexF64,Float64}\nMRIReco.simulation(tr::Trajectory\n , image::Array{ComplexF64}\n , correctionMap = []\n ; opName=\"fast\"\n , senseMaps=[]\n , verbose=true\n , kargs...)\nMRIReco.simulation(seq::AbstractSequence, tr::Vector{Trajectory}\n , image::Array{ComplexF64,3}\n ; opName=\"fast\"\n , r1map=[]\n , r2map=[]\n , fmap=[]\n , senseMaps=[]\n , verbose=true\n , kargs...)\nMRIReco.addNoise(x::Vector, snr::Float64, complex= true)\nMRIReco.addNoise(acqData::AcquisitionData, snr::Float64)\nMRIReco.addNoise!(acqData::AcquisitionData, snr::Float64)\nMRIReco.birdcageSensitivity\nMRIReco.quadraticFieldmap","category":"page"},{"location":"API/#Reconstruction","page":"API","title":"Reconstruction","text":"","category":"section"},{"location":"API/","page":"API","title":"API","text":"MRIReco.reconstruction(acqData::AcquisitionData, recoParams::Dict)\nMRIReco.reconstruction(acqData::AcquisitionData, recoParams::Dict, filename::String;force=false)\nMRIReco.setupIterativeReco\nMRIReco.reconstruction_direct_2d\nMRIReco.reconstruction_direct_3d\nMRIReco.reconstruction_simple\nMRIReco.reconstruction_multiEcho\nMRIReco.reconstruction_multiCoil\nMRIReco.reconstruction_multiCoilMultiEcho\nMRIReco.espirit\nMRIReco.nrmsd","category":"page"},{"location":"API/#MRIReco.reconstruction-Tuple{AcquisitionData, Dict}","page":"API","title":"MRIReco.reconstruction","text":"reconstruction(acqData::AcquisitionData, recoParams::Dict)\n\nPerforms image reconstruction of an AcquisitionData object. Parameters are specified in a dictionary.\n\nReconstruction types are specified by the symbol :reco. Valid reconstruction names are:\n\n:direct - direct Fourier reconstruction\n:standard - iterative reconstruction for all contrasts, coils & slices independently\n:multiEcho - iterative joint reconstruction of all echo images\n:multiCoil - SENSE-type iterative reconstruction\n:multiCoilMultiEcho - SENSE-type iterative reconstruction of all echo images\n\n\n\n\n\n","category":"method"},{"location":"API/#MRIReco.reconstruction-Tuple{AcquisitionData, Dict, String}","page":"API","title":"MRIReco.reconstruction","text":"reconstruction(acqData::AcquisitionData, recoParams::Dict,filename::String; force=false)\n\nperforms the same image reconstrucion as reconstruction(acqData::AcquisitionData, recoParams::Dict) and saves the image in a file with name filename. If force=false, the reconstructed image is loaded from the the file filename if the latter is present.\n\n\n\n\n\n","category":"method"},{"location":"API/#MRIReco.setupIterativeReco","page":"API","title":"MRIReco.setupIterativeReco","text":"setupIterativeReco(acqData::AcquisitionData, recoParams::Dict)\n\nbuilds relevant parameters and operators from the entries in recoParams\n\nrelevant parameters\n\nreconSize::NTuple{2,Int64} - size of image to reconstruct\nweights::Vector{Vector{Complex{<:AbstractFloat}}} - sampling density of the trajectories in acqData\nsparseTrafo::AbstractLinearOperator - sparsifying transformation\nreg::Regularization - Regularization to be used\nnormalize::Bool - adjust regularization parameter according to the size of k-space data\nsolvername::String - name of the solver to use\nsenseMaps::Array{Complex{<:AbstractFloat}} - coil sensitivities\ncorrectionMap::Array{Complex{<:AbstractFloat}} - fieldmap for the correction of off-resonance effects\nmethod::String=\"nfft\" - method to use for time-segmentation when correctio field inhomogeneities\nnoiseData::Array{ComplexF64} - noise acquisition for noise decorelation\n\nsparseTrafo and reg can also be speficied using their names in form of a string.\n\n\n\n\n\n","category":"function"},{"location":"API/#MRIReco.reconstruction_simple","page":"API","title":"MRIReco.reconstruction_simple","text":"Performs iterative image reconstruction independently for the data of all coils, contrasts and slices\n\nArguments\n\nacqData::AcquisitionData - AcquisitionData object\nreconSize::NTuple{2,Int64} - size of image to reconstruct\nreg::Regularization - Regularization to be used\nsparseTrafo::AbstractLinearOperator - sparsifying transformation\nweights::Vector{Vector{Complex{<:AbstractFloat}}} - sampling density of the trajectories in acqData\nsolvername::String - name of the solver to use\n(normalize::Bool=false) - adjust regularization parameter according to the size of k-space data\n(params::Dict{Symbol,Any}) - Dict with additional parameters\n\n\n\n\n\n","category":"function"},{"location":"API/#MRIReco.reconstruction_multiEcho","page":"API","title":"MRIReco.reconstruction_multiEcho","text":"Performs a iterative image reconstruction jointly for all contrasts. Different slices and coil images are reconstructed independently.\n\nArguments\n\nacqData::AcquisitionData - AcquisitionData object\nreconSize::NTuple{2,Int64} - size of image to reconstruct\nreg::Regularization - Regularization to be used\nsparseTrafo::AbstractLinearOperator - sparsifying transformation\nweights::Vector{Vector{Complex{<:AbstractFloat}}} - sampling density of the trajectories in acqData\nsolvername::String - name of the solver to use\n(normalize::Bool=false) - adjust regularization parameter according to the size of k-space data\n(params::Dict{Symbol,Any}) - Dict with additional parameters\n\n\n\n\n\n","category":"function"},{"location":"API/#MRIReco.reconstruction_multiCoil","page":"API","title":"MRIReco.reconstruction_multiCoil","text":"Performs a SENSE-type iterative image reconstruction. Different slices and contrasts images are reconstructed independently.\n\nArguments\n\nacqData::AcquisitionData - AcquisitionData object\nreconSize::NTuple{2,Int64} - size of image to reconstruct\nreg::Regularization - Regularization to be used\nsparseTrafo::AbstractLinearOperator - sparsifying transformation\nweights::Vector{Vector{Complex{<:AbstractFloat}}} - sampling density of the trajectories in acqData\nL_inv::Array{Complex{<:AbstractFloat}} - noise decorrelation matrix\nsolvername::String - name of the solver to use\nsenseMaps::Array{Complex{<:AbstractFloat}} - coil sensitivities\n(normalize::Bool=false) - adjust regularization parameter according to the size of k-space data\n(params::Dict{Symbol,Any}) - Dict with additional parameters\n\n\n\n\n\n","category":"function"},{"location":"API/#MRIReco.reconstruction_multiCoilMultiEcho","page":"API","title":"MRIReco.reconstruction_multiCoilMultiEcho","text":"Performs a SENSE-type iterative image reconstruction which reconstructs all contrasts jointly. Different slices are reconstructed independently.\n\nArguments\n\nacqData::AcquisitionData - AcquisitionData object\nreconSize::NTuple{2,Int64} - size of image to reconstruct\nreg::Regularization - Regularization to be used\nsparseTrafo::AbstractLinearOperator - sparsifying transformation\nweights::Vector{Vector{Complex{<:AbstractFloat}}} - sampling density of the trajectories in acqData\nsolvername::String - name of the solver to use\nsenseMaps::Array{Complex{<:AbstractFloat}} - coil sensitivities\n(normalize::Bool=false) - adjust regularization parameter according to the size of k-space data\n(params::Dict{Symbol,Any}) - Dict with additional parameters\n\n\n\n\n\n","category":"function"},{"location":"API/#MRIReco.nrmsd","page":"API","title":"MRIReco.nrmsd","text":"nrmsd(I,Ireco)\n\ncomputes the normalized root mean squared error of the image Ireco with respect to the image I.\n\n\n\n\n\n","category":"function"},{"location":"operators/#Imaging-Operators","page":"Imaging Operators","title":"Imaging Operators","text":"","category":"section"},{"location":"operators/","page":"Imaging Operators","title":"Imaging Operators","text":"The mapping between the proton density and the recorded signal is linear in MRI and can be described in the continuous case as an integral equation and in the discrete case as a matrix vector multiplication.","category":"page"},{"location":"operators/","page":"Imaging Operators","title":"Imaging Operators","text":"Depending on the imaging scenario, the MRI system matrix can have various different forms. It may encode a Cartesian, or a spiral trajectory. It may take offresonance into account, and it may also encode the sensitivity of the receive coil.","category":"page"},{"location":"operators/","page":"Imaging Operators","title":"Imaging Operators","text":"MRIReco implements various MRI imaging operators. In all cases, the operators have a dedicated Julia type that acts as a matrix. The operator E thus can be applied to a vector x by calling E*x. Similarly, the adjoint can be applied by adjoint(E)*x. We note at this point that the adjoint operation is lazy in Julia and thus the matrix adjoint(E) is never explicitly arranged.","category":"page"},{"location":"operators/","page":"Imaging Operators","title":"Imaging Operators","text":"MRIReco currently implements the following operators:","category":"page"},{"location":"operators/","page":"Imaging Operators","title":"Imaging Operators","text":"FFTOp: A multidimensional FFT operator\nNFFTOp: A multidimensional operator for non-equidistant FFTs\nFieldmapNFFTOp: An operator that takes complex correction terms into account\nSensitivityMapOp: An operator for building a SENSE reconstruction. Has to be combined with one of the former encoding operators\nSamplingOp: An operator that describes the (sub)sampling of full trajectories. The operator is used for Compressed Sensing reconstruction\nWaveletOp: A multidimensional operator for applying Wavelet transformations","category":"page"},{"location":"operators/","page":"Imaging Operators","title":"Imaging Operators","text":"Each of these operators can be build by calling the corresponding constructor. Alternatively one can use the EncodingOp constructor that allows for high-level construction of the imaging operator.","category":"page"},{"location":"SENSE/#Parallel-Imaging","page":"Parallel Imaging","title":"Parallel Imaging","text":"","category":"section"},{"location":"SENSE/","page":"Parallel Imaging","title":"Parallel Imaging","text":"For parallel imaging MRIReco.jl uses an iterative SENSE approach. In the following code example we show how to simulate MRI data with an array of 8 coils and how to reconstruct that data using SENSE. The example can be run by entering","category":"page"},{"location":"SENSE/","page":"Parallel Imaging","title":"Parallel Imaging","text":"include(joinpath(dirname(pathof(MRIReco)),\"../docs/src/examples/exampleSENSE.jl\"))","category":"page"},{"location":"SENSE/","page":"Parallel Imaging","title":"Parallel Imaging","text":"into the Julia REPL.","category":"page"},{"location":"SENSE/","page":"Parallel Imaging","title":"Parallel Imaging","text":"N = 256\nnumCoils = 8\nI = shepp_logan(N)\nI = circularShutterFreq!(I,1)\n\ncoilsens = birdcageSensitivity(N, 8, 1.5)\n\n# simulation parameters\nparams = Dict{Symbol, Any}()\nparams[:simulation] = \"fast\"\nparams[:trajName] = \"Spiral\"\nparams[:numProfiles] = 6\nparams[:numSamplingPerProfile] = div(N*N,16)\nparams[:windings] = div(N,16)\nparams[:AQ] = 2.0e-2\nparams[:senseMaps] = coilsens\n\n# do simulation\nacqData = simulation(I, params)\n\n# reco parameters\nparams = Dict{Symbol, Any}()\nparams[:reco] = \"multiCoil\"\nparams[:reconSize] = (N,N)\nparams[:regularization] = \"L2\"\nparams[:λ] = 1.e-3\nparams[:iterations] = 40\nparams[:solver] = \"cgnr\"\nparams[:senseMaps] = coilsens\n\n# do reconstruction\nIreco = reconstruction(acqData, params)\n","category":"page"},{"location":"SENSE/","page":"Parallel Imaging","title":"Parallel Imaging","text":"Below one can see the orignal phantom on the left and the reconstruction on the right:","category":"page"},{"location":"SENSE/","page":"Parallel Imaging","title":"Parallel Imaging","text":"(Image: Phantom) (Image: Reconstruction)","category":"page"},{"location":"overview/#Overview","page":"Overview","title":"Overview","text":"","category":"section"},{"location":"overview/","page":"Overview","title":"Overview","text":"As outlined in the introduction MRIReco.jl MRIReco has the philosophy to to reuse functionality provided by other Julia package and basically add the MRI specific functionality. This approach is enabled by the Julia package manager that can handle all dependencies automatically. Packages are therefore considered to be cheap in Julia so that modularization can be done across packages. In the following graph, the most important (not all) dependencies of MRIReco are visualized.","category":"page"},{"location":"overview/","page":"Overview","title":"Overview","text":"(Image: Dependencies)","category":"page"},{"location":"overview/","page":"Overview","title":"Overview","text":"Most importantly, all iterative solvers are implemented in RegularizedLeastSquares.jl so that MRIReco can benefit from all improvements made in that package. Gridding is implemented in the NFFT.jl package, which has many applications byond MRI. Sparsifying transformations are usually also not MRI specific and therefore implemented in independent packages (e.g. Wavelets.jl). For storing image data MRIReco.jl uses NiFTI.jl. Dicom data can potentially be saved by the DICOM.jl package, which, however, is not a hard dependency of MRIReco.","category":"page"},{"location":"overview/#Data-Types-and-Flow","page":"Overview","title":"Data Types and Flow","text":"","category":"section"},{"location":"overview/","page":"Overview","title":"Overview","text":"An overview about the most important data types and the data flow during recosntruction is given in the following figure.","category":"page"},{"location":"overview/","page":"Overview","title":"Overview","text":"(Image: DataFlow)","category":"page"},{"location":"overview/","page":"Overview","title":"Overview","text":"Raw data is usually obtained from files (discussed in File Handling). Since the data layout of the RawAcquisitionData object is not perfectly suited for reconstruction, we ","category":"page"},{"location":"#MRIReco.jl","page":"Home","title":"MRIReco.jl","text":"","category":"section"},{"location":"","page":"Home","title":"Home","text":"Magnetic Resonance Imaging Reconstruction","category":"page"},{"location":"#Introduction","page":"Home","title":"Introduction","text":"","category":"section"},{"location":"","page":"Home","title":"Home","text":"MRIReco is a Julia packet for magnetic resonance imaging. It contains algorithms for the simulation and reconstruction of MRT data and is both easy to use and flexibly expandable.","category":"page"},{"location":"","page":"Home","title":"Home","text":"Both direct and iterative methods are available for image reconstruction. In particular, modern compressed sensing algorithms such as ADMM can be used.","category":"page"},{"location":"","page":"Home","title":"Home","text":"The MRT imaging operator can be set up for a variety of scanning patterns (cartesian, spiral, radial, ...) and can take into account field inhomogeneity as well as the use of coil arrays. The operator can be quickly evaluated using NFFT-based methods.","category":"page"},{"location":"","page":"Home","title":"Home","text":"One strength of the package is that it is strongly modular and uses high quality Julia packages. These are e.g.","category":"page"},{"location":"","page":"Home","title":"Home","text":"NFFT.jl and FFTW.jl for fast Fourier transformations\nWavelets.jl for sparsification\nLinearOperators.jl in order to be able to divide the imaging operator modularly into individual parts\nRegularizedLeastSquares.jl for modern algorithms for solving linear optimization problems","category":"page"},{"location":"","page":"Home","title":"Home","text":"This interaction allows new algorithms to be easily integrated into the software framework. It is not necessary to program in C/C++ but the advantages of the scientific high-level language Julia can be used.","category":"page"},{"location":"","page":"Home","title":"Home","text":"note: Note\nMRIReco.jl is work in progress and in some parts not entirely optimized. In particular the FFT and NFFT implementation are currently limited to the CPU and do not support GPU acceleration yet.","category":"page"},{"location":"#Installation","page":"Home","title":"Installation","text":"","category":"section"},{"location":"","page":"Home","title":"Home","text":"Start julia and open the package mode by entering ]. Then enter","category":"page"},{"location":"","page":"Home","title":"Home","text":"add MRIReco","category":"page"},{"location":"","page":"Home","title":"Home","text":"This will install MRIReco and all its dependencies. If you want to develop MRIReco itself you can checkout MRIReco by calling","category":"page"},{"location":"","page":"Home","title":"Home","text":"dev MRIReco","category":"page"},{"location":"","page":"Home","title":"Home","text":"More information on how to develop a package can be found in the Julia documentation.","category":"page"},{"location":"#Plotting","page":"Home","title":"Plotting","text":"","category":"section"},{"location":"","page":"Home","title":"Home","text":"On purpose MRIReco is not depending on a particular plotting package since there are various plotting packages in the Julia ecosystem. Within the examples outlined in the tutorial we will use PyPlot for plotting but you may prefer using the Plots package. You can add both packages the same way MRIReco has been added.","category":"page"},{"location":"#Tutorial","page":"Home","title":"Tutorial","text":"","category":"section"},{"location":"","page":"Home","title":"Home","text":"There is a Jupyter-based tutorial on MRIReco at","category":"page"},{"location":"","page":"Home","title":"Home","text":"https://github.com/MagneticResonanceImaging/MRIRecoTutorial","category":"page"},{"location":"","page":"Home","title":"Home","text":"that has been presented at the ISMRM conference in Montreal 2019. Since the API has slightly changed, we, however recommend that you read this documentation and in particular execute the example scripts as is described in the Getting Started section.","category":"page"},{"location":"filehandling/#File-Handling","page":"File Handling","title":"File Handling","text":"","category":"section"},{"location":"filehandling/","page":"File Handling","title":"File Handling","text":"MRI Acquisition Data can not only be generated from simulation but also from files. Currently, MRIReco supports the ISMRMRD file format the Bruker file format (at least partially).","category":"page"},{"location":"filehandling/","page":"File Handling","title":"File Handling","text":"The ISMRMRD is fully supported with proper read and write support. For the Bruker file format only reading of data is supported.","category":"page"},{"location":"filehandling/","page":"File Handling","title":"File Handling","text":"The example discussed in the following can be run by entering","category":"page"},{"location":"filehandling/","page":"File Handling","title":"File Handling","text":"include(joinpath(dirname(pathof(MRIReco)),\"../docs/src/examples/exampleIO.jl\"))","category":"page"},{"location":"filehandling/","page":"File Handling","title":"File Handling","text":"into the Julia REPL.","category":"page"},{"location":"filehandling/","page":"File Handling","title":"File Handling","text":"We start by loading a file handle to a Bruker dataset using","category":"page"},{"location":"filehandling/","page":"File Handling","title":"File Handling","text":"f = BrukerFile(\"brukerfileCart\")","category":"page"},{"location":"filehandling/","page":"File Handling","title":"File Handling","text":"This file handle does not yet contain the data. To load the data we call","category":"page"},{"location":"filehandling/","page":"File Handling","title":"File Handling","text":"raw = RawAcquisitionData(f)","category":"page"},{"location":"filehandling/","page":"File Handling","title":"File Handling","text":"which will load all data that can be encoded into a RawAcquisitionData object. For reconstruction we can then convert it to the preprocessed data format and call","category":"page"},{"location":"filehandling/","page":"File Handling","title":"File Handling","text":"acq = AcquisitionData(raw)\n\nparams = Dict{Symbol, Any}()\nparams[:reco] = \"direct\"\nparams[:reconSize] = (acq.encodingSize[1],acq.encodingSize[2])\n\nimg = reconstruction(acq, params)","category":"page"},{"location":"filehandling/","page":"File Handling","title":"File Handling","text":"This will result in the following image:","category":"page"},{"location":"filehandling/","page":"File Handling","title":"File Handling","text":"(Image: BrukerReco)","category":"page"},{"location":"filehandling/#Saving","page":"File Handling","title":"Saving","text":"","category":"section"},{"location":"filehandling/","page":"File Handling","title":"File Handling","text":"But loading the data is only one important operation. Lets suppose that you have performed an expensive simulation resulting in a raw data object raw. To store this data one can simply run","category":"page"},{"location":"filehandling/","page":"File Handling","title":"File Handling","text":"fout = ISMRMRDFile(\"outputfile.h5\")\nsave(fout, raw)","category":"page"},{"location":"filehandling/","page":"File Handling","title":"File Handling","text":"which will generate an ISMRMRD file containing the data.","category":"page"},{"location":"filehandling/#Conversion","page":"File Handling","title":"Conversion","text":"","category":"section"},{"location":"filehandling/","page":"File Handling","title":"File Handling","text":"It should now be no surprise that MRIReco.jl does also allow for file conversion:","category":"page"},{"location":"filehandling/","page":"File Handling","title":"File Handling","text":"f = BrukerFile(\"brukerfileCart\")\nraw = RawAcquisitionData(f)\nfout = ISMRMRDFile(\"outputfile.h5\")\nsave(fout, raw)","category":"page"},{"location":"filehandling/","page":"File Handling","title":"File Handling","text":"Currently, this is only limited to converting Bruker files into ISMRMRD files but the infrastructure is not limited to that.","category":"page"}] } diff --git a/dev/sequences/index.html b/dev/sequences/index.html index ded6be7d..dbc26993 100644 --- a/dev/sequences/index.html +++ b/dev/sequences/index.html @@ -1,2 +1,2 @@ -- · Julia MRI Package
      +- · Julia MRI Package
      diff --git a/dev/trajectories/index.html b/dev/trajectories/index.html index 51d990d8..bfd19bea 100644 --- a/dev/trajectories/index.html +++ b/dev/trajectories/index.html @@ -3,4 +3,4 @@ kspaceNodes(tr::Trajectory) readoutTimes(tr::Trajectory)

      For instance we can define a spiral, radial, and cartesian trajectory using

      tr = trajectory("Spiral", 1, 600, windings=10)
       tr = trajectory("Cartesian", 13, 50, EPI_factor=1)
      -tr = trajectory("Radial", 13, 50)

      A variable density spiral can be generated by

      tr = trajectory("SpiralVarDens", 3, 200)

      The k-space nodes can then be accessed by

      nodes = kspaceNodes(tr)

      The script generating the following image can be executed by running the following from within the Julia REPL:

      include(joinpath(dirname(pathof(MRIReco)),"../docs/src/examples/exampleTrajectories.jl"))

      Trajectories

      +tr = trajectory("Radial", 13, 50)

      A variable density spiral can be generated by

      tr = trajectory("SpiralVarDens", 3, 200)

      The k-space nodes can then be accessed by

      nodes = kspaceNodes(tr)

      The script generating the following image can be executed by running the following from within the Julia REPL:

      include(joinpath(dirname(pathof(MRIReco)),"../docs/src/examples/exampleTrajectories.jl"))

      Trajectories