Correction of Slab/Slice Profile

Here, we show how to correct the errors generated by the slice/slab profile of the excitation pulse.

Corrupted MP2RAGE image

using QuantitativeMRI
using JLD2, CairoMakie
d = load(joinpath(pwd(),"../..","data","corrupted.jld2"))

MP2RAGE = d["MP2RAGE"]
T1map = d["T1map"]
p_MP2 = d["params_MP2RAGE"]
angle_profile = d["angle_profile"]
TI1 = d["im_reco"][:,:,1]
TI2 = d["im_reco"][:,:,2]

f=Figure(size=(300,300))
ax = Axis(f[1,1], title="Corrupted MP2RAGE image",xlabel="phase encoding direction", ylabel="partition encoding direction",aspect = 1)
heatmap!(ax,MP2RAGE,colormap=:grays)
hidedecorations!(ax,label=false)
f
Example block output

You can see that the image is corrupted by the slab profile of the excitation pulse along the Y axis, which corresponds to the partition encoding direction.

This is due to an inappropriate choice of excitation pulse—here, a Hermite shape. We can take a look at the corresponding excitation profile:

f=Figure(size=(300,200))
ax = Axis(f[1,1], title="Corrupted MP2RAGE image",xlabel="partition encoding direction", ylabel="effective flip angle [degrees]")
lines!(ax,angle_profile)
f
Example block output

Fixing the T1 Map

Fortunately, if we know the effective flip angle profile, we can correct the resulting T1 map.

p = deepcopy(p_MP2)

T1corr = similar(MP2RAGE)
T1,range_T1,LUT = mp2rage_T1maps(MP2RAGE,p_MP2)

LUT_vec = []
range_T1_vec = []
for i=1:size(MP2RAGE,2)
  p.α₁ = d["angle_profile"][i]
  p.α₂ = d["angle_profile"][i] ./ p_MP2.α₁ .* p_MP2.α₂

  T1corr[:,i], range_T1, LUT= mp2rage_T1maps(MP2RAGE[:,i],p)
  push!(LUT_vec,LUT)
  push!(range_T1_vec,range_T1)
end

f=Figure(size=(400,300))
ax = Axis(f[1,1], title="Initial T1 map",aspect = 1)
heatmap!(ax,T1,colorrange = (800,2000))
hidedecorations!(ax)
ax = Axis(f[1,2], title="Corrected T1 map",aspect = 1)
h=heatmap!(ax,T1corr,colorrange = (800,2000))
hidedecorations!(ax)
Colorbar(f[1,3], h, label="T1 [ms]",tellheight=true)
rowsize!(f.layout, 1, ax.scene.px_area[].widths[2])
f
Example block output

The idea is to compute a different lookup table (LUT) for each partition position, using the effective flip angle profile. This allows us to correct the T1 map for the slab profile effect.

Let's take a look at two different LUTs:

f=Figure(size=(400,300))
ax = Axis(f[1,1], title="LUT for partition position 1 and 96")
xlims!(ax,0,range_T1_vec[96][end])
ylims!(ax,-0.5,0.5)

lines!(ax,range_T1_vec[1],LUT_vec[1],label="angle = $(angle_profile[1])",color=:blue)
lines!(ax,range_T1_vec[96],LUT_vec[96],label="angle = $(angle_profile[96])",color=:green)

val_MP2 = 0.1
idxFirst1 = searchsortedfirst(LUT_vec[1], val_MP2,lt= >=)
idxFirst2 = searchsortedfirst(LUT_vec[96], val_MP2,lt= >=)
hlines!(ax,val_MP2,xmax=range_T1_vec[96][idxFirst2]/range_T1_vec[96][end],color=:red,linestyle=:dot)

vlines!(ax,range_T1_vec[1][idxFirst1],color=:blue,linestyle=:dash)
vlines!(ax,range_T1_vec[96][idxFirst2],color=:green,linestyle=:dash)
f
Example block output

You can see that the different effective flip angle profiles lead to different LUTs, which allows us to correct the T1 map for the slab profile effect.

Correcting the MP2RAGE Image

We can also correct the MP2RAGE image using the corrected T1 map.

res = QuantitativeMRI.T1maps_mp2rage(T1corr,p_MP2)


begin
  sl=[:,:]
  f = Figure()

  ax=Axis(f[1,1],title="Initial MP2RAGE",aspect = 1)
  h=heatmap!(ax,MP2RAGE,colormap=:grays)

  ax=Axis(f[1,2],title="corrected MP2RAGE",aspect = 1)
  h=heatmap!(ax,res[1], colormap=:grays)

  for ax in f.content   # hide decoration befor adding colorbar
    hidedecorations!(ax)
  end

  f
end
Example block output

As you can see, the corrected MP2RAGE image is now free of the slab profile effect.

Unfortunately, we cannot generate the corrected TI₁ and TI₂ images from the corrected T1 map. Even if we are able to generate the signal equation knowing the T1 map, we would also need to know the T2*, B1-, and proton density for each voxel.