|
a |
|
b/cmac/aux_dicom.py |
|
|
1 |
import os |
|
|
2 |
import glob |
|
|
3 |
import pydicom |
|
|
4 |
import numpy as np |
|
|
5 |
import nibabel as nib |
|
|
6 |
from dipy.align.reslice import reslice |
|
|
7 |
from dipy.align.imaffine import AffineMap |
|
|
8 |
|
|
|
9 |
def extract_cosines(ImageOrientationPatient): |
|
|
10 |
row_cosine = np.array(ImageOrientationPatient[:3]) |
|
|
11 |
column_cosine = np.array(ImageOrientationPatient[3:]) |
|
|
12 |
slice_cosine = np.cross(row_cosine, column_cosine) |
|
|
13 |
return row_cosine, column_cosine, slice_cosine |
|
|
14 |
|
|
|
15 |
def read_RefDs(dicom_folder_path): |
|
|
16 |
cine_dicom_files = glob.glob(dicom_folder_path) |
|
|
17 |
SliceLocations = [pydicom.read_file(cine_dicom_file).SliceLocation |
|
|
18 |
for cine_dicom_file in cine_dicom_files] |
|
|
19 |
SliceOriginID = np.array(SliceLocations, dtype=float).argmin() |
|
|
20 |
|
|
|
21 |
RefDs = pydicom.read_file(cine_dicom_files[SliceOriginID]) |
|
|
22 |
ImageOrientationPatient = RefDs.ImageOrientationPatient |
|
|
23 |
ImagePositionPatient = np.array(list(RefDs.ImagePositionPatient), dtype=float) |
|
|
24 |
Zooms = np.array(list(RefDs.PixelSpacing) + [RefDs.SliceThickness], dtype=float) |
|
|
25 |
|
|
|
26 |
return ImageOrientationPatient, ImagePositionPatient, Zooms |
|
|
27 |
|
|
|
28 |
def read_affine_info(dicom_folder_path, viewer='slicer'): |
|
|
29 |
|
|
|
30 |
ImageOrientationPatient, ImagePositionPatient, Zooms = read_RefDs(dicom_folder_path) |
|
|
31 |
|
|
|
32 |
affine_axial = np.diag(list(Zooms)+[1]) |
|
|
33 |
affine_axial[:3,3] += ImagePositionPatient |
|
|
34 |
|
|
|
35 |
row_cos, column_cos, slice_cos = extract_cosines(ImageOrientationPatient) |
|
|
36 |
|
|
|
37 |
ijk2ras = np.stack((row_cos, column_cos, slice_cos)) |
|
|
38 |
if viewer == "slicer": |
|
|
39 |
ijk2ras = (ijk2ras*np.array([-1,-1,1])).T |
|
|
40 |
ImagePositionPatient = ImagePositionPatient*np.array([-1,-1,1]) |
|
|
41 |
|
|
|
42 |
affine = np.stack((ijk2ras[:,0]*Zooms[0], |
|
|
43 |
ijk2ras[:,1]*Zooms[1], |
|
|
44 |
ijk2ras[:,2]*Zooms[2], |
|
|
45 |
ImagePositionPatient), axis=1) |
|
|
46 |
|
|
|
47 |
return ijk2ras, np.vstack((affine,[[0,0,0,1]])), affine_axial |
|
|
48 |
|
|
|
49 |
def reslice_3d(domain_nifti, codomain_nifti, mode='linear'): |
|
|
50 |
|
|
|
51 |
affine_map = AffineMap(affine=np.eye(4), |
|
|
52 |
domain_grid_shape=domain_nifti.shape, domain_grid2world=domain_nifti.affine, |
|
|
53 |
codomain_grid_shape=codomain_nifti.shape, codomain_grid2world=codomain_nifti.affine) |
|
|
54 |
|
|
|
55 |
return nib.Nifti1Image(affine_map.transform(codomain_nifti.get_fdata(),mode),domain_nifti.affine) |
|
|
56 |
|
|
|
57 |
def reslice_4d(domain_nifti, codomain_nifti, mode='linear'): |
|
|
58 |
|
|
|
59 |
reslice_arr = np.zeros(domain_nifti.shape[:3]+(codomain_nifti.shape[-1],)) |
|
|
60 |
affine_map = AffineMap(affine=np.eye(4), |
|
|
61 |
domain_grid_shape=domain_nifti.shape[:3], domain_grid2world=domain_nifti.affine, |
|
|
62 |
codomain_grid_shape=codomain_nifti.shape[:3], codomain_grid2world=codomain_nifti.affine) |
|
|
63 |
|
|
|
64 |
for frame_id in range(reslice_arr.shape[-1]): |
|
|
65 |
reslice_arr[:,:,:,frame_id] += affine_map.transform(codomain_nifti.get_fdata()[:,:,:,frame_id],mode) |
|
|
66 |
|
|
|
67 |
return nib.Nifti1Image(reslice_arr, domain_nifti.affine) |
|
|
68 |
|
|
|
69 |
|
|
|
70 |
def resample_nifti(subject_nifti, resolution=(1.5, 1.5), Nz=16, order=1, mode='nearest'): |
|
|
71 |
"""Resample a 3D or 4D (3D+time) cine-MRI nifti to a new in-plane `resolution` with `Nz` slices.""" |
|
|
72 |
|
|
|
73 |
data = subject_nifti.get_fdata() |
|
|
74 |
affine = subject_nifti.affine |
|
|
75 |
zooms = subject_nifti.header.get_zooms()[:3] |
|
|
76 |
|
|
|
77 |
new_zooms = (resolution[0], resolution[1], (zooms[2] * data.shape[2]) / Nz) |
|
|
78 |
|
|
|
79 |
data_resampled, affine_resampled = reslice(data, affine, zooms, new_zooms, order=order, mode=mode) |
|
|
80 |
subject_nifti_resampled = nib.Nifti1Image(data_resampled, affine_resampled) |
|
|
81 |
|
|
|
82 |
x=subject_nifti_resampled.header.get_zooms()[:3] |
|
|
83 |
y=new_zooms |
|
|
84 |
if not np.allclose(x,y, rtol=1e-02): |
|
|
85 |
print(subject_nifti.affine,affine) |
|
|
86 |
print(zooms) |
|
|
87 |
print(x,y) |
|
|
88 |
warnings.warn('Output resolutions are different than expected!') |
|
|
89 |
|
|
|
90 |
return subject_nifti_resampled |