Additional examples

[1]:
import ivim
import os
import tempfile
import numpy as np
import matplotlib.pyplot as plt

# Define output folder (can be any valid folder)
folder = os.path.join(tempfile.gettempdir(),'ivim_example')
if not os.path.exists(folder):
    os.mkdir(folder)

Comparison of model fitting algorithms

Start by generating synthetic data

[2]:
b = [0,10,20,30,40,50,75,100,200,400,600,800]
bval_file = os.path.join(folder,'example.bval')
ivim.io.base.write_bval(bval_file, b)

D = [0.8e-3, 1.0e-3]
f = [0.1, 0.15]
Dstar = [20e-3, 15e-3]
regime = ivim.models.DIFFUSIVE_REGIME

sz = [20,20,10]
pars = ['D','f','Dstar']
files_sim = {}
for par, vals in zip(pars, [D, f, Dstar]):
    im = vals[0] * np.ones(sz)
    im[sz[0]//4:3*sz[0]//4,sz[1]//4:3*sz[1]//4,:] = vals[1]
    files_sim[par] = os.path.join(folder, f'sim_{par}.nii.gz')
    ivim.io.base.write_im(files_sim[par], im)

noise_sigma = 1/40 # SNR = 40, given S0 = 1 as default
outbase_sim = os.path.join(folder,'ivim_sim')
ivim.sim.noise(files_sim['D'], files_sim['f'], regime, bval_file, noise_sigma, outbase_sim, Dstar_file = files_sim['Dstar'])
im_file = outbase_sim + '.nii.gz'
[3]:
im = ivim.io.base.read_im(im_file)

fig,axes = plt.subplots(len(b)//6,6,figsize=(6*1.2,len(b)//6*1.2))
for i,ax in enumerate(axes.flatten()):
    ax.imshow(im[...,0,i], cmap='gray', vmin=0, vmax=1.2)
    ax.axis('off')
    ax.set_title(f'b({i+1}) = {int(b[i]):d} s/mm$^2$', fontsize = 6)
_images/examples_additional_4_0.png

Apply model fitting algorithms

[4]:
outbase_nlls = os.path.join(folder,'nlls')
ivim.fit.nlls(im_file, bval_file, regime, outbase=outbase_nlls)

outbase_seg = os.path.join(folder,'seg')
bthr = 200
ivim.fit.seg(im_file, bval_file, regime, bthr, outbase=outbase_seg)

outbase_bayes = os.path.join(folder,'bayes')
ivim.fit.bayes(im_file, bval_file, regime, outbase=outbase_bayes)

outbase_bayessp = os.path.join(folder,'bayes_sp')
mask_file = os.path.join(folder,'mask.nii.gz')
ivim.io.base.write_im(mask_file,np.ones(sz),imref_file=im_file)
ivim.fit.bayes(im_file, bval_file, regime, outbase=outbase_bayessp, spatial_prior=True, roi_file=mask_file)
/home/oscar/programming/ivim/ivim/fit.py:536: RuntimeWarning: overflow encountered in square
  ssq_new = np.sum((Y[mask, :] - fn(X, thetanew))**2, axis=1)
/home/oscar/programming/ivim/ivim/models.py:29: RuntimeWarning: overflow encountered in exp
  S = np.exp(-np.outer(D, b))
/home/oscar/programming/ivim/ivim/fit.py:539: RuntimeWarning: overflow encountered in divide
  post_ratio[nonzero] = ((ssq_new[nonzero] / ssq_old[nonzero])**(-X.shape[0]/2)

Display parameter maps

[5]:
fig,axes = plt.subplots(5,3,figsize=(3*2,5*2))
for par,plotpar,axs in zip(pars,['D*' if par == 'Dstar' else par for par in pars],axes.T):
    maps = [ivim.io.base.read_im(files_sim[par])]
    for outbase in [outbase_nlls, outbase_seg, outbase_bayes, outbase_bayessp]:
        maps += [ivim.io.base.read_im(outbase+f'_{par}.nii.gz')]

    for im,ax in zip(maps,axs):
        ax.imshow(im[...,0], cmap='gray', vmin=0, vmax=1.5*np.max(maps[0]))
        ax.set_xticks([])
        ax.set_yticks([])
        if ax == axs[0]:
            ax.set_title(plotpar)
    if axs[0] is axes[0][0]:
        axs[0].set_ylabel('Ground truth')
        axs[1].set_ylabel('NLLS')
        axs[2].set_ylabel('Segmented')
        axs[3].set_ylabel('Bayesian')
        axs[4].set_ylabel('Bayesian\nSpatial prior')
_images/examples_additional_8_0.png

Compare distribution of parameter estimates

[6]:
fig,axes = plt.subplots(2,3,figsize=(3*4,2*3))
for par,scale,unit,plotpar,axs in zip(pars,[1e3,1e2,1e3],[r'µm$^2$/ms','%',r'µm$^2$/ms'],['D*' if par == 'Dstar' else par for par in pars],axes.T):
    truemap = ivim.io.base.read_im(files_sim[par])
    maps = []
    for outbase in [outbase_nlls, outbase_seg, outbase_bayes, outbase_bayessp]:
        maps += [ivim.io.base.read_im(outbase+f'_{par}.nii.gz')]

    for par_val,ax in zip(np.unique(truemap),axs):
        data = [im[truemap==par_val]*scale for im in maps]
        ax.plot([0.5,len(data)+0.5],2*[par_val*scale],'--k')
        ax.boxplot(data,whis=np.inf,tick_labels=['NLLS','Seg','Bayes','Bayes SP'])
        if ax == axs[0]:
            ax.set_title(plotpar+' ['+unit+']')
_images/examples_additional_10_0.png

The Bayesian algorithm with spatial priors has the overall best performance with low bias and high precision for all parameters.

Langevin equation

Comparison of velocity autocorrelation function obtained from simulations and the theoretical one.

[7]:
sigma_v = 2e-3
tau = 100e-3
dt = 1e-3
m = 300
n = 10000

v = ivim.sim.langevin(sigma_v,tau,dt,m,n)

vacf_sim = np.zeros((m,3))
vacf_sim[0,:] = np.mean(np.var(v,axis=0),axis=0)
for i in range(1,m):
    vacf_sim[i,:] = np.mean(np.mean(v[:,:-i,:]*v[:,i:,:],axis=0),axis=0)

t = np.arange(m)*dt
vacf_an = sigma_v**2 * np.exp(-t/tau)
plt.plot(t*1e3,vacf_sim[:,0]*1e6,'.',label='Simulated')
plt.plot(t*1e3,vacf_an*1e6,'k-',label='Theoretical')
plt.xlabel("t - t' [ms]")
plt.ylabel(r"$\langle v(t)v(t') \rangle$ [mm$^2$/s$^2$]")
plt.legend();

_images/examples_additional_14_0.png

Trajectories in a 1x1x1 mm3 cube.

[8]:
walkers = 50
r = 1e-3*(np.random.rand(walkers,3)-0.5)[:,np.newaxis,:] + np.cumsum(v[:walkers,:,:],axis=1)*dt

fig,ax = plt.subplots(1,1,subplot_kw={'projection': '3d'})
for i in range(walkers):
    ax.plot(r[i,:,0],r[i,:,1],r[i,:,2],'r')
ax.set_xlim([-0.5e-3,0.5e-3])
ax.set_ylim([-0.5e-3,0.5e-3])
ax.set_zlim([-0.5e-3,0.5e-3]);
_images/examples_additional_16_0.png