ESPIRiT Maps Demo

This is a demo on how to generate ESPIRiT maps. It is based on the paper Uecker et. al, MRM 2013 DOI 10.1002/mrm.24751. ESPIRiT is a method that finds the subspace of multi-coil data from a calibration region in k-space using a series of eigen-value decompositions in k-space and image space.

Contents

Set parameters

load brain_8ch

[sx,sy,Nc] = size(DATA);
ncalib = 24; % use 24 calibration lines to compute compression
ksize = [6,6]; % kernel size


% Threshold for picking singular vercors of the calibration matrix
% (relative to largest singlular value.

eigThresh_1 = 0.02;

% threshold of eigen vector decomposition in image space.
eigThresh_2 = 0.95;

% crop a calibration area
calib = crop(DATA,[ncalib,ncalib,Nc]);

Display coil images:

im = ifft2c(DATA);

figure, imshow3(abs(im),[],[1,8]);
title('magnitude of physical coil images');
colormap((gray(256))); colorbar;

figure, imshow3(angle(im),[],[1,8]);
title('phase of physical coil images');
colormap('default'); colorbar;

Compute ESPIRiT EigenVectors

Here we perform calibration in k-space followed by an eigen-decomposition in image space to produce the EigenMaps.

% compute Calibration matrix, perform 1st SVD and convert singular vectors
% into k-space kernels

[k,S] = dat2Kernel(calib,ksize);
idx = max(find(S >= S(1)*eigThresh_1));

This shows that the calibration matrix has a null space as shown in the paper.

kdisp = reshape(k,[ksize(1)*ksize(2)*Nc,ksize(1)*ksize(2)*Nc]);
figure, subplot(211), plot([1:ksize(1)*ksize(2)*Nc],S,'LineWidth',2);
hold on,
plot([1:ksize(1)*ksize(2)*Nc],S(1)*eigThresh_1,'r-','LineWidth',2);
plot([idx,idx],[0,S(1)],'g--','LineWidth',2)
legend('signular vector value','threshold')
title('Singular Vectors')
subplot(212), imagesc(abs(kdisp)), colormap(gray(256));
xlabel('Singular value #');
title('Singular vectors')

crop kernels and compute eigen-value decomposition in image space to get maps

[M,W] = kernelEig(k(:,:,:,1:idx),[sx,sy]);

show eigen-values and eigen-vectors. The last set of eigen-vectors corresponding to eigen-values 1 look like sensitivity maps

figure, imshow3(abs(W),[],[1,8]);
title('Eigen Values in Image space');
colormap((gray(256))); colorbar;

figure, imshow3(abs(M),[],[8,8]);
title('Magnitude of Eigen Vectors');
colormap(gray(256)); colorbar;

figure, imshow3(angle(M),[],[8,8]);
title('Magnitude of Eigen Vectors');
colormap(jet(256)); colorbar;
Warning: Image is too big to fit on screen; displaying at 67% 
Warning: Image is too big to fit on screen; displaying at 67% 

project onto the eigenvectors. This shows that all the signal energy lives in the subspace spanned by the eigenvectors with eigenvalue 1. These look like sensitivity maps.

% alternate way to compute projection is:
% ESP = ESPIRiT(M);
% P = ESP'*im;

P = sum(repmat(im,[1,1,1,Nc]).*conj(M),3);
figure, imshow3(abs(P),[],[1,8]);
title('Magnitude of Eigen Vectors');
colormap(sqrt(gray(256))); colorbar;

figure, imshow3(angle(P),[],[1,8]);
title('Magnitude of Eigen Vectors');
colormap((jet(256))); colorbar;

crop sensitivity maps

maps = M(:,:,:,end).*repmat(W(:,:,end)>eigThresh_2,[1,1,Nc]);

figure, imshow3(abs(maps),[],[1,8]);
title('Absolute sensitivity maps');
colormap((gray(256))); colorbar;

figure, imshow3(angle (maps),[],[1,8]);
title('Phase of sensitivity maps');
colormap((jet(256))); colorbar;

ESPIRiT with Aliased Calibration

Here we perform ESPIRiT calibration on data which has strong aliasing in the phase-encode direction. SENSE often fails with this type of data.

load brain_alias_8ch

ncalib = 24; % use 24 calibration lines to compute compression
ksize = [6,6];
eigThresh_1 = 0.02;
eigThresh_2 = 0.95;
[sx,sy,Nc] = size(DATA);
calib = crop(DATA,[ncalib,ncalib,Nc]);

Display coil images:

im = ifft2c(DATA);

figure, imshow3(abs(im),[],[1,8]);
title('magnitude of physical coil images');
colormap((gray(256))); colorbar;

figure, imshow3(angle(im),[],[1,8]);
title('phase of physical coil images');
colormap('default'); colorbar;

Compute Aliased ESPIRiT Maps

% compute Calibration matrix, perform 1st SVD and convert singular vectors
% into k-space kernels

[k,S] = dat2Kernel(calib,ksize);
idx = max(find(S >= S(1)*eigThresh_1));

This shows that the calibration matrix has a null space as shown in the paper. However the signal subspace is bigger because of the aliasin and the tighter FOV of the imaged object.

kdisp = reshape(k,[ksize(1)*ksize(2)*Nc,ksize(1)*ksize(2)*Nc]);
figure, subplot(211), plot([1:ksize(1)*ksize(2)*Nc],S,'LineWidth',2);
hold on,
plot([1:ksize(1)*ksize(2)*Nc],S(1)*eigThresh_1,'r-','LineWidth',2);
plot([idx,idx],[0,S(1)],'g--','LineWidth',2)
legend('signular vector value','threshold')
title('Singular Vectors')
subplot(212), imagesc(abs(kdisp)), colormap(gray(256));
xlabel('Singular value #');
title('Singular vectors')

crop kernels and compute eigen-value decomposition in image space to get maps

[M,W] = kernelEig(k(:,:,:,1:idx),[sx,sy]);

show eigen-values and eigen-vectors. The last set of eigen-vectors corresponding to eigen-values 1 look like sensitivity maps

figure, imshow3(abs(W),[],[1,8]);
title('Eigen Values in Image space');
colormap((gray(256))); colorbar;

figure, imshow3(abs(M),[],[8,8]);
title('Magnitude of Eigen Vectors');
colormap(gray(256)); colorbar;

figure, imshow3(angle(M),[],[8,8]);
title('Magnitude of Eigen Vectors');
colormap(jet(256)); colorbar;
Warning: Image is too big to fit on screen; displaying at 33% 
Warning: Image is too big to fit on screen; displaying at 33% 

project onto the eigenvectors. This shows that all the signal energy lives in the subspace spanned by the eigenvectors with eigenvalue 1. These look like sensitivity maps -- Note that where there's aliasing there are multiplicities of eigenvalues ==1, so there is a second component.

P = sum(repmat(im,[1,1,1,Nc]).*conj(M),3);
figure, imshow3(abs(P),[],[1,8]);
title('Magnitude of Projection onto Eigen Vectors');
colormap(sqrt(gray(256))); colorbar;

figure, imshow3(angle(P),[],[1,8]);
title('Phase of projection onto Eigen Vectors');
colormap((jet(256))); colorbar;

crop sensitivity maps according to eigenvalues==1. Note that we have to use 2 sets of maps.

maps = M(:,:,:,end-1:end).*repmat(permute(W(:,:,end-1:end)>eigThresh_2,[1,2,4,3]),[1,1,Nc,1]);

figure, imshow3(abs(maps),[],[2,8]);
title('Absolute sensitivity maps');
colormap((gray(256))); colorbar;

figure, imshow3(angle (maps),[],[2,8]);
title('Phase of sensitivity maps');
colormap((jet(256))); colorbar;