Skip to content

Using Labels for Cartesian Multi-Slice Reconstruction

julia script jupyter notebook launch binder

In Cartesian imaging, ADC labels tell the reconstruction algorithm where each k-space line was acquired, and also which contrast, slice, repetition, etc., that line belongs to. In this tutorial, we will build a compact multi-slice acquisition using LIN for the phase-encoding line and SLC for the slice each readout belongs to 🧭.

julia
Nx = 64
Ny = 64
Nslices = 2

Creating a sequence with ADC labels

The sequence loops over slices and phase-encoding lines. The label extensions go in the readout block, next to the ADC, so the profile leaves the sequence with the metadata the reconstruction algorithm will use later.

⚠️ ADC labels must remain non-negative. KomaMRI checks the labels before simulation, so avoid negative LabelSet values or LabelInc patterns that push a label below zero.

julia
function cartesian_label_sequence()
    seq = Sequence()
    adc = ADC(Nx, Tadc)
    readout = Grad(Gx, Tadc)
    prewinder = Grad(-Gx / 2, Tadc)
    @addblocks for slc in 0:(Nslices - 1), lin in 0:(Ny - 1)
        pe = phase_encode(lin)
        seq += rf[slc + 1]
        seq += (x=prewinder, y=pe)
        seq += (x=readout, adc, LabelSet(slc, "SLC"), LabelSet(lin, "LIN"))
        seq += Delay(TR)
    end
    return seq
end

seq = cartesian_label_sequence();

Checking labels in the raw data metadata

After simulation, KomaMRI has copied those labels into the raw data headers. Let's inspect the first and last readout of each slice. The jump from profile 64 to 65 is the useful part: SLC advances and LIN resets.

julia
raw = @suppress simulate(obj, seq, sys)

for p in [1, Ny, Ny + 1, Nslices * Ny]
    slc = raw.profiles[p].head.idx.slice |> Int
    lin = raw.profiles[p].head.idx.kspace_encode_step_1 |> Int
    println("Profile $p: SLC=$slc, LIN=$lin")
end
Profile 1: SLC=0, LIN=0
Profile 64: SLC=0, LIN=63
Profile 65: SLC=1, LIN=0
Profile 128: SLC=1, LIN=63

Reconstructing using ADC labels

At this point the labels stop being just annotations. Setting the trajectory to "cartesian" lets the reconstruction use the profile headers directly: LIN orders the phase-encoding lines and SLC separates the slice stack. MRIReco will then reconstruct one image per slice.

julia
raw.params["trajectory"] = "cartesian";
raw.params["encodedSize"] = [Nx, Ny, 1];
raw.params["reconSize"] = [Nx, Ny, 1];

This readout is symmetric, so estimating the center sample is enough here. For asymmetric readouts, set center_sample in the profile headers and pass estimateProfileCenter=false.

julia
acqData = AcquisitionData(raw; estimateProfileCenter=true);
rec = reconstruction(acqData, Dict{Symbol,Any}());
image = abs.(rec);

p1 = plot_image(image_display[:, :, 1]; height=360, title="Slice 1", zmin=0, zmax=1)
p2 = plot_image(image_display[:, :, 2]; height=360, title="Slice 2", zmin=0, zmax=1)

KomaMRI tries to pass every supported label/flag through to the MRD raw data. This path is still new, so let us know if you find a case that is not mapped correctly; the goal is to stay as close as possible to what the scanner writes 🙂.


This page was generated using Literate.jl.