mirror of
https://gitlab.tugraz.at/ibi/projects/julia-pfitzer/esmrmb-educational.git
synced 2024-11-21 17:22:24 +00:00
Different basic undersampling methods.
This commit is contained in:
commit
6c719eaad2
12 changed files with 1791 additions and 0 deletions
8
.gitignore
vendored
Normal file
8
.gitignore
vendored
Normal file
|
@ -0,0 +1,8 @@
|
|||
venv/
|
||||
*.cfl
|
||||
*.hdr
|
||||
fig/
|
||||
.ipynb_checkpoints/
|
||||
data/
|
||||
__pycache__/
|
||||
*.mat
|
1355
ESMRMB_Educational.ipynb
Normal file
1355
ESMRMB_Educational.ipynb
Normal file
File diff suppressed because it is too large
Load diff
3
README.md
Normal file
3
README.md
Normal file
|
@ -0,0 +1,3 @@
|
|||
# ESMRMB Educational
|
||||
|
||||
Testing different reconstruction methods.
|
0
__init__.py
Normal file
0
__init__.py
Normal file
114
cfl.py
Normal file
114
cfl.py
Normal file
|
@ -0,0 +1,114 @@
|
|||
# Copyright 2013-2015. The Regents of the University of California.
|
||||
# Copyright 2021. Uecker Lab. University Center Göttingen.
|
||||
# All rights reserved. Use of this source code is governed by
|
||||
# a BSD-style license which can be found in the LICENSE file.
|
||||
#
|
||||
# Authors:
|
||||
# 2013 Martin Uecker <uecker@eecs.berkeley.edu>
|
||||
# 2015 Jonathan Tamir <jtamir@eecs.berkeley.edu>
|
||||
|
||||
from __future__ import print_function
|
||||
from __future__ import with_statement
|
||||
|
||||
import numpy as np
|
||||
import mmap
|
||||
import os
|
||||
|
||||
|
||||
def readcfl(name):
|
||||
# get dims from .hdr
|
||||
with open(name + ".hdr", "rt") as h:
|
||||
h.readline() # skip
|
||||
l = h.readline()
|
||||
dims = [int(i) for i in l.split()]
|
||||
|
||||
# remove singleton dimensions from the end
|
||||
n = np.prod(dims)
|
||||
dims_prod = np.cumprod(dims)
|
||||
dims = dims[:np.searchsorted(dims_prod, n)+1]
|
||||
|
||||
# load data and reshape into dims
|
||||
with open(name + ".cfl", "rb") as d:
|
||||
a = np.fromfile(d, dtype=np.complex64, count=n);
|
||||
return a.reshape(dims, order='F') # column-major
|
||||
|
||||
def readmulticfl(name):
|
||||
# get dims from .hdr
|
||||
with open(name + ".hdr", "rt") as h:
|
||||
lines = h.read().splitlines()
|
||||
|
||||
index_dim = 1 + lines.index('# Dimensions')
|
||||
total_size = int(lines[index_dim])
|
||||
index_sizes = 1 + lines.index('# SizesDimensions')
|
||||
sizes = [int(i) for i in lines[index_sizes].split()]
|
||||
index_dims = 1 + lines.index('# MultiDimensions')
|
||||
|
||||
with open(name + ".cfl", "rb") as d:
|
||||
a = np.fromfile(d, dtype=np.complex64, count=total_size)
|
||||
|
||||
offset = 0
|
||||
result = []
|
||||
for i in range(len(sizes)):
|
||||
dims = ([int(i) for i in lines[index_dims + i].split()])
|
||||
n = np.prod(dims)
|
||||
result.append(a[offset:offset+n].reshape(dims, order='F'))
|
||||
offset += n
|
||||
|
||||
if total_size != offset:
|
||||
print("Error")
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def writecfl(name, array):
|
||||
with open(name + ".hdr", "wt") as h:
|
||||
h.write('# Dimensions\n')
|
||||
for i in (array.shape):
|
||||
h.write("%d " % i)
|
||||
h.write('\n')
|
||||
|
||||
size = np.prod(array.shape) * np.dtype(np.complex64).itemsize
|
||||
|
||||
with open(name + ".cfl", "a+b") as d:
|
||||
os.ftruncate(d.fileno(), size)
|
||||
mm = mmap.mmap(d.fileno(), size, flags=mmap.MAP_SHARED, prot=mmap.PROT_WRITE)
|
||||
if array.dtype != np.complex64:
|
||||
array = array.astype(np.complex64)
|
||||
mm.write(np.ascontiguousarray(array.T))
|
||||
mm.close()
|
||||
#with mmap.mmap(d.fileno(), size, flags=mmap.MAP_SHARED, prot=mmap.PROT_WRITE) as mm:
|
||||
# mm.write(array.astype(np.complex64).tobytes(order='F'))
|
||||
|
||||
def writemulticfl(name, arrays):
|
||||
size = 0
|
||||
dims = []
|
||||
|
||||
for array in arrays:
|
||||
size += array.size
|
||||
dims.append(array.shape)
|
||||
|
||||
with open(name + ".hdr", "wt") as h:
|
||||
h.write('# Dimensions\n')
|
||||
h.write("%d\n" % size)
|
||||
|
||||
h.write('# SizesDimensions\n')
|
||||
for dim in dims:
|
||||
h.write("%d " % len(dim))
|
||||
h.write('\n')
|
||||
|
||||
h.write('# MultiDimensions\n')
|
||||
for dim in dims:
|
||||
for i in dim:
|
||||
h.write("%d " % i)
|
||||
h.write('\n')
|
||||
|
||||
size = size * np.dtype(np.complex64).itemsize
|
||||
|
||||
with open(name + ".cfl", "a+b") as d:
|
||||
os.ftruncate(d.fileno(), size)
|
||||
mm = mmap.mmap(d.fileno(), size, flags=mmap.MAP_SHARED, prot=mmap.PROT_WRITE)
|
||||
for array in arrays:
|
||||
if array.dtype != np.complex64:
|
||||
array = array.astype(np.complex64)
|
||||
mm.write(np.ascontiguousarray(array.T))
|
||||
mm.close()
|
48
plotBoMap.py
Normal file
48
plotBoMap.py
Normal file
|
@ -0,0 +1,48 @@
|
|||
import scipy.io as sio
|
||||
import matplotlib.pyplot as plt
|
||||
import numpy as np
|
||||
import matplotlib.gridspec as gridspec
|
||||
import matplotlib.cm as cm
|
||||
from mpl_toolkits.axes_grid1 import make_axes_locatable
|
||||
|
||||
# Bo Map
|
||||
mat_data_0=sio.loadmat('bo.mat')
|
||||
tmap = mat_data_0['boMap']
|
||||
print(np.min(tmap))
|
||||
print(np.max(tmap))
|
||||
vmin = -0.3
|
||||
vmax = 0.3
|
||||
|
||||
def multiSlicePlot(data,nRow, nCol, nSlrep, vmin, vmax, sliceInit = 0):
|
||||
"""""
|
||||
data = imageMatrix3D [sl,ph,rd]
|
||||
nRow, nCol dimensions of the multislicePlot
|
||||
nSlRep = number of slices to represent
|
||||
sliceInit = slice in wihich we start representing
|
||||
"""""
|
||||
images = []
|
||||
fig = plt.figure(figsize=(nRow, nCol), dpi=500)
|
||||
gs1 = gridspec.GridSpec(nRow, nCol)
|
||||
gs1.update(wspace=0.020, hspace=0.020) # set the spacing between axes.
|
||||
for i in range(nSlrep):
|
||||
ii = i + sliceInit
|
||||
# print(ii)
|
||||
ax1 = plt.subplot(gs1[i])
|
||||
# plt.axis('off')
|
||||
ax1.set_xticklabels([])
|
||||
ax1.set_yticklabels([])
|
||||
ax1.set_aspect('equal')
|
||||
dataAux = data[int(ii), :, :]
|
||||
imgPlot = ax1.imshow(dataAux,vmin=vmin, vmax=vmax)
|
||||
images.append(imgPlot)
|
||||
ax1.axis('off')
|
||||
return fig
|
||||
|
||||
fig = multiSlicePlot(tmap*1e3,3,6,16,vmin,vmax,0)
|
||||
|
||||
cbar_ax = fig.add_axes([0.92, 0.15, 0.01, 0.7])
|
||||
norm = plt.Normalize(vmin=vmin, vmax=vmax)
|
||||
cbar = plt.colorbar(cm.ScalarMappable(norm=norm, cmap=cm.viridis), cax=cbar_ax)
|
||||
cbar.set_label('Bo [mT]', fontsize=2)
|
||||
cbar.ax.tick_params(labelsize=2)
|
||||
plt.show()
|
39
plotComparativeTimes.py
Normal file
39
plotComparativeTimes.py
Normal file
|
@ -0,0 +1,39 @@
|
|||
import scipy.io as sio
|
||||
import matplotlib.pyplot as plt
|
||||
import numpy as np
|
||||
import matplotlib.gridspec as gridspec
|
||||
import matplotlib.cm as cm
|
||||
from mpl_toolkits.axes_grid1 import make_axes_locatable
|
||||
|
||||
imagesPath=['T2_CPMG','T2_APCPMG', 'T2_APCP', 'T2_CP', 'T1']
|
||||
sliceRep = 12
|
||||
vmin = 0
|
||||
vmax = 200
|
||||
|
||||
nMaps = len(imagesPath)
|
||||
fig = plt.figure(figsize=(1, 5), dpi=500)
|
||||
gs1 = gridspec.GridSpec(1, nMaps)
|
||||
gs1.update(wspace=0.020, hspace=0.020)
|
||||
for i in range(nMaps):
|
||||
if 'T1' in imagesPath[i]:
|
||||
mat_data = sio.loadmat(imagesPath[i]+'.mat')
|
||||
data = mat_data['t1map']
|
||||
print(data.shape)
|
||||
else:
|
||||
mat_data = sio.loadmat(imagesPath[i]+'.mat')
|
||||
data = mat_data['t2map']
|
||||
print(data.shape)
|
||||
ax1 = plt.subplot(gs1[i])
|
||||
ax1.set_xticklabels([])
|
||||
ax1.set_yticklabels([])
|
||||
ax1.set_aspect('equal')
|
||||
dataAux = data[sliceRep, :, :]
|
||||
imgPlot = ax1.imshow(abs(dataAux),vmin=vmin, vmax=vmax)
|
||||
ax1.axis('off')
|
||||
ax1.set_title(imagesPath[i], fontsize=4)
|
||||
cbar_ax = fig.add_axes([0.92, 0.35, 0.01, 0.30])
|
||||
norm = plt.Normalize(vmin=vmin, vmax=vmax)
|
||||
cbar = plt.colorbar(cm.ScalarMappable(norm=norm, cmap=cm.viridis), cax=cbar_ax)
|
||||
cbar.set_label('Time [ms]', fontsize=2)
|
||||
cbar.ax.tick_params(labelsize=2)
|
||||
plt.show()
|
46
plotPDMap.py
Normal file
46
plotPDMap.py
Normal file
|
@ -0,0 +1,46 @@
|
|||
import scipy.io as sio
|
||||
import matplotlib.pyplot as plt
|
||||
import numpy as np
|
||||
import matplotlib.gridspec as gridspec
|
||||
import matplotlib.cm as cm
|
||||
from mpl_toolkits.axes_grid1 import make_axes_locatable
|
||||
|
||||
# PD
|
||||
mat_data_0=sio.loadmat('PD.mat')
|
||||
img = mat_data_0['image3D']
|
||||
vmin = np.min(np.abs(img))
|
||||
vmax = np.max(np.abs(img))
|
||||
|
||||
def multiSlicePlot(data,nRow, nCol, nSlrep, vmin, vmax, sliceInit = 0):
|
||||
"""""
|
||||
data = imageMatrix3D [sl,ph,rd]
|
||||
nRow, nCol dimensions of the multislicePlot
|
||||
nSlRep = number of slices to represent
|
||||
sliceInit = slice in wihich we start representing
|
||||
"""""
|
||||
images = []
|
||||
fig = plt.figure(figsize=(nRow, nCol), dpi=500)
|
||||
gs1 = gridspec.GridSpec(nRow, nCol)
|
||||
gs1.update(wspace=0.020, hspace=0.020) # set the spacing between axes.
|
||||
for i in range(nSlrep):
|
||||
ii = i + sliceInit
|
||||
# print(ii)
|
||||
ax1 = plt.subplot(gs1[i])
|
||||
# plt.axis('off')
|
||||
ax1.set_xticklabels([])
|
||||
ax1.set_yticklabels([])
|
||||
ax1.set_aspect('equal')
|
||||
dataAux = data[int(ii), :, :]
|
||||
imgPlot = ax1.imshow(dataAux,vmin=vmin, vmax=vmax)
|
||||
images.append(imgPlot)
|
||||
ax1.axis('off')
|
||||
return fig
|
||||
|
||||
fig = multiSlicePlot(np.abs(img),3,6,16,vmin,vmax,0)
|
||||
|
||||
cbar_ax = fig.add_axes([0.92, 0.15, 0.01, 0.7])
|
||||
norm = plt.Normalize(vmin=vmin, vmax=vmax)
|
||||
cbar = plt.colorbar(cm.ScalarMappable(norm=norm, cmap=cm.viridis), cax=cbar_ax)
|
||||
cbar.set_label('PD [a.u.]', fontsize=2)
|
||||
cbar.ax.tick_params(labelsize=2)
|
||||
plt.show()
|
12
plotT1Map.py
Normal file
12
plotT1Map.py
Normal file
|
@ -0,0 +1,12 @@
|
|||
import scipy.io as sio
|
||||
import matplotlib.pyplot as plt
|
||||
import numpy as np
|
||||
from bart import bart
|
||||
|
||||
# T1 dict
|
||||
T1_dict = sio.loadmat('T1.mat')
|
||||
|
||||
rawName = 'T2_CPMG.mat'
|
||||
mat_data_0=sio.loadmat(rawName)
|
||||
|
||||
print(mat_data_0.keys())
|
52
plotTimesMap.py
Normal file
52
plotTimesMap.py
Normal file
|
@ -0,0 +1,52 @@
|
|||
import scipy.io as sio
|
||||
import matplotlib.pyplot as plt
|
||||
import numpy as np
|
||||
import matplotlib.gridspec as gridspec
|
||||
import matplotlib.cm as cm
|
||||
from mpl_toolkits.axes_grid1 import make_axes_locatable
|
||||
|
||||
# Map
|
||||
rawName = 'T2_CPMG.mat'
|
||||
mat_data_0=sio.loadmat(rawName)
|
||||
if 'T1' in rawName:
|
||||
tmap = mat_data_0['t1map']
|
||||
else:
|
||||
tmap = mat_data_0['t2map']
|
||||
print(np.min(tmap))
|
||||
print(np.max(tmap))
|
||||
vmin = 0
|
||||
vmax = 200
|
||||
|
||||
def multiSlicePlot(data,nRow, nCol, nSlrep, vmin, vmax, sliceInit = 0):
|
||||
"""""
|
||||
data = imageMatrix3D [sl,ph,rd]
|
||||
nRow, nCol dimensions of the multislicePlot
|
||||
nSlRep = number of slices to represent
|
||||
sliceInit = slice in wihich we start representing
|
||||
"""""
|
||||
images = []
|
||||
fig = plt.figure(figsize=(nRow, nCol), dpi=500)
|
||||
gs1 = gridspec.GridSpec(nRow, nCol)
|
||||
gs1.update(wspace=0.020, hspace=0.020) # set the spacing between axes.
|
||||
for i in range(nSlrep):
|
||||
ii = i + sliceInit
|
||||
# print(ii)
|
||||
ax1 = plt.subplot(gs1[i])
|
||||
# plt.axis('off')
|
||||
ax1.set_xticklabels([])
|
||||
ax1.set_yticklabels([])
|
||||
ax1.set_aspect('equal')
|
||||
dataAux = data[int(ii), :, :]
|
||||
imgPlot = ax1.imshow(dataAux,vmin=vmin, vmax=vmax)
|
||||
images.append(imgPlot)
|
||||
ax1.axis('off')
|
||||
return fig
|
||||
|
||||
fig = multiSlicePlot(tmap,3,6,16,vmin,vmax,0)
|
||||
|
||||
cbar_ax = fig.add_axes([0.92, 0.15, 0.01, 0.7])
|
||||
norm = plt.Normalize(vmin=vmin, vmax=vmax)
|
||||
cbar = plt.colorbar(cm.ScalarMappable(norm=norm, cmap=cm.viridis), cax=cbar_ax)
|
||||
cbar.set_label(rawName+ '[ms]', fontsize=2)
|
||||
cbar.ax.tick_params(labelsize=2)
|
||||
plt.show()
|
36
rawDatasExplanation.txt
Normal file
36
rawDatasExplanation.txt
Normal file
|
@ -0,0 +1,36 @@
|
|||
|
||||
# T2 Maps
|
||||
t2maps_dict = {
|
||||
'kSpaces3D': sampled, # kSpace [kRd, kPh, kSl, kSpace_echo_1, kSpace_echo_2, ..., kSpace_echo_nETL]
|
||||
'images3D': imgMSE, # images [nSl, nPh, nETL, nRD]
|
||||
'echoSpacing': echoSpacing, # Echo spacing
|
||||
'FOV': fov, # FOV [sl,ph,rd]
|
||||
't2map': t2Map # t2Map (ms) [nSl, nPh, nRD]
|
||||
}
|
||||
|
||||
# T1 Map
|
||||
t1map_dict = {
|
||||
'kSpaces3D': sampled, # kSpace [kRd, kPh, kSl, kSpace_echo_1, kSpace_echo_2, ..., kSpace_echo_nETL]
|
||||
'images3D': imgAll, # images [nSl, nPh, nImg, nRD]
|
||||
'inversionTimes': tI_vector, # Inversion times corresponding each image
|
||||
'FOV': fov, # FOV [sl,ph,rd]
|
||||
't1map': t1Map # t2Map (ms) [nSl, nPh, nRD]
|
||||
}
|
||||
|
||||
# Bo Map
|
||||
bomap_dict = {
|
||||
'kSpace3D_0': sampled_0, # kSpace delay 0 [kRd, kPh, kSl, kSpace]
|
||||
'image3D_0': img0, # images delay 0 [nSl, nPh, nRD]
|
||||
'kSpace3D_delay': sampled_delay, # kSpace delay [kRd, kPh, kSl, kSpace]
|
||||
'image3D_delay': img80, # images delay [nSl, nPh, nRD]
|
||||
'delay': delay, # delay (s)
|
||||
'FOV': fov, # FOV [sl,ph,rd]
|
||||
'boMap': boCeros # boMap (T) [nSl, nPh, nRD]
|
||||
}
|
||||
|
||||
# PD
|
||||
pd_dict = {
|
||||
'kSpace3D': sampled_0, # kSpace [kRd, kPh, kSl, kSpace]
|
||||
'image3D': img0, # images [nSl, nPh, nRD]
|
||||
'FOV': fov, # FOV [sl,ph,rd]
|
||||
}
|
78
reco.py
Normal file
78
reco.py
Normal file
|
@ -0,0 +1,78 @@
|
|||
import scipy.io as sio
|
||||
import matplotlib.pyplot as plt
|
||||
import numpy as np
|
||||
from scipy.optimize import curve_fit
|
||||
import sys,os
|
||||
from cfl import writecfl
|
||||
|
||||
os.environ['TOOLBOX_PATH'] = '/home/jpfitzer/bart-0.9.00'
|
||||
os.environ['BART_TOOLBOX_PATH'] = '/home/jpfitzer/bart-0.9.00'
|
||||
sys.path.append('/home/jpfitzer/bart-0.9.00/bart/python')
|
||||
|
||||
rawName = 'T2_CPMG.mat'
|
||||
mat_data_0=sio.loadmat(rawName)
|
||||
|
||||
# Format: sampled, # kSpace [kRd, kPh, kSl, kSpace_echo_1, kSpace_echo_2, ..., kSpace_echo_nETL] (102400, 23)
|
||||
# So the first three are the coordinates of the kspace, and the rest are the echoes
|
||||
print(mat_data_0['kSpaces3D'].shape)
|
||||
|
||||
kSpaces3D = mat_data_0['kSpaces3D']
|
||||
# self.mapVals['sampled'] = np.concatenate((kRD, kPH, kSL, dataAll_sampled), axis=1)
|
||||
|
||||
# nReadout, nPhase, nSlice
|
||||
nPoints = (80, 80, 16)
|
||||
|
||||
echo_train_length = mat_data_0['kSpaces3D'].shape[1] - 3 # Because the first 3 are kRD, kPH, kSL -> should give 20
|
||||
print(f"Echo train length: {echo_train_length}")
|
||||
|
||||
echo_spacing = mat_data_0['echoSpacing'][0][0]
|
||||
print(f"Echo spacing: {echo_spacing}")
|
||||
|
||||
k_readout = kSpaces3D[:, 0]
|
||||
k_phase = kSpaces3D[:, 1]
|
||||
k_slice = kSpaces3D[:, 2]
|
||||
|
||||
# The rest of the data is the echoes
|
||||
echos = kSpaces3D[:, 3:]
|
||||
|
||||
# Reshape the kspace data for bart
|
||||
kSpace = echos.reshape(nPoints[2], nPoints[1], nPoints[0], echo_train_length)
|
||||
|
||||
|
||||
|
||||
print(kSpace.shape)
|
||||
|
||||
# cfl = writecfl('kSpace', kSpace)
|
||||
|
||||
# Create the image with bart fft -i 7 kSpace fft -> three dimensional
|
||||
# Put the echos on the fifth dimension:
|
||||
# bart transpose 3 5
|
||||
# Put the slices on the correct dimension
|
||||
# bart transpose 0 2
|
||||
|
||||
# traj = writecfl('traj', np.stack((k_readout, k_phase, k_slice), axis=1))
|
||||
|
||||
# Echo times with echo spacing
|
||||
TE = np.linspace(echo_spacing, echo_spacing * echo_train_length, echo_train_length, endpoint=True)
|
||||
print("TE: ", TE)
|
||||
|
||||
# Create the echotimes file:
|
||||
# bart vec ... echo_times
|
||||
# bart scale 0.001 echo_times echo_times_scaled
|
||||
# Move the echo_times to the correct dimension:
|
||||
# bart transpose 0 5 echo_times_scaled echo_times_final
|
||||
|
||||
# Fit the model:
|
||||
# bart mobafit -T echo_times_final fft_transposed fit
|
||||
|
||||
# Now some values will be very large so we can apply a threshold to obtain a mask
|
||||
# bart threshold -M 1000 reco/fit reco/mask
|
||||
|
||||
# Multiply the fit with the mask
|
||||
# bart fmac reco/fit reco/fit reco/fit_mask
|
||||
|
||||
# Select slice
|
||||
# bart slice 6 1 reco/fit_mask reco/R2_map
|
||||
|
||||
# Invert the data to get T2
|
||||
# bart invert reco/R2_map reco/T2_map
|
Loading…
Reference in a new issue