File size: 5,465 Bytes
b51cd04
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
import pydicom
import numpy as np
import scipy

class MRimage:

  def __init__(self):
    self.SeriesInstanceUID = ""
    self.PatientInfo = {}
    self.StudyInfo = {}
    self.FrameOfReferenceUID = ""
    self.ImgName = ""
    self.SOPClassUID = ""
            
    self.DcmFiles = []
    self.isLoaded = 0
    
    
    
  def print_MR_info(self, prefix=""):
    print(prefix + "MR series: " + self.SeriesInstanceUID)
    for mr_slice in self.DcmFiles:
      print(prefix + "   " + mr_slice)
      
  def resample_MR(self, newvoxelsize):
    mr = self.Image
    # Rescaling to the newvoxelsize if given in parameter

    source_shape = self.GridSize
    voxelsize = self.PixelSpacing
    VoxelX_source = self.ImagePositionPatient[0] + np.arange(source_shape[0])*voxelsize[0]
    VoxelY_source = self.ImagePositionPatient[1] + np.arange(source_shape[1])*voxelsize[1]
    VoxelZ_source = self.ImagePositionPatient[2] + np.arange(source_shape[2])*voxelsize[2]
    
    target_shape = np.ceil(np.array(source_shape).astype(float)*np.array(voxelsize).astype(float)/newvoxelsize).astype(int)
    VoxelX_target = self.ImagePositionPatient[0] + np.arange(target_shape[0])*newvoxelsize[0]
    VoxelY_target = self.ImagePositionPatient[1] + np.arange(target_shape[1])*newvoxelsize[1]
    VoxelZ_target = self.ImagePositionPatient[2] + np.arange(target_shape[2])*newvoxelsize[2]
    print("source_shape",source_shape,"target_shape",target_shape)
    if(all(source_shape == target_shape) and np.linalg.norm(np.subtract(voxelsize, newvoxelsize) < 0.001)):
      print("Image does not need filtering")
    else:
      # anti-aliasing filter
      sigma = [0, 0, 0]
      if(newvoxelsize[0] > voxelsize[0]): sigma[0] = 0.4 * (newvoxelsize[0]/voxelsize[0])
      if(newvoxelsize[1] > voxelsize[1]): sigma[1] = 0.4 * (newvoxelsize[1]/voxelsize[1])
      if(newvoxelsize[2] > voxelsize[2]): sigma[2] = 0.4 * (newvoxelsize[2]/voxelsize[2])
      
      if(sigma != [0, 0, 0]):
          print("Image is filtered before downsampling")
          mr = scipy.ndimage.gaussian_filter(mr, sigma)      
          
      xi = np.array(np.meshgrid(VoxelX_target, VoxelY_target, VoxelZ_target))
      xi = np.rollaxis(xi, 0, 4)
      xi = xi.reshape((xi.size // 3, 3))
      
      # get resized mr
      mr = scipy.interpolate.interpn((VoxelX_source,VoxelY_source,VoxelZ_source), mr, xi, method='linear', fill_value=0, bounds_error=False).reshape(target_shape).transpose(1,0,2)
    
    self.PixelSpacing = newvoxelsize
      
    self.GridSize = list(mr.shape) 
    self.NumVoxels = self.GridSize[0] * self.GridSize[1] * self.GridSize[2]
    self.Image = mr
    self.VoxelX = self.ImagePositionPatient[0] + np.arange(self.GridSize[0])*self.PixelSpacing[0]
    self.VoxelY = self.ImagePositionPatient[1] + np.arange(self.GridSize[1])*self.PixelSpacing[1]
    self.VoxelZ = self.ImagePositionPatient[2] + np.arange(self.GridSize[2])*self.PixelSpacing[2]
    self.isLoaded = 1    
      
  def import_Dicom_MR(self):
    
    if(self.isLoaded == 1):
      print("Warning: CT series " + self.SeriesInstanceUID + " is already loaded")
      return
  
    images = []
    SOPInstanceUIDs = []
    SliceLocation = np.zeros(len(self.DcmFiles), dtype='float')

    for i in range(len(self.DcmFiles)):
      file_path = self.DcmFiles[i]
      dcm = pydicom.dcmread(file_path)

      if(hasattr(dcm, 'SliceLocation') and abs(dcm.SliceLocation - dcm.ImagePositionPatient[2]) > 0.001):
        print("WARNING: SliceLocation (" + str(dcm.SliceLocation) + ") is different than ImagePositionPatient[2] (" + str(dcm.ImagePositionPatient[2]) + ") for " + file_path)

      SliceLocation[i] = float(dcm.ImagePositionPatient[2])
      images.append(dcm.pixel_array)# * dcm.RescaleSlope + dcm.RescaleIntercept)
      SOPInstanceUIDs.append(dcm.SOPInstanceUID)

    # sort slices according to their location in order to reconstruct the 3d image
    sort_index = np.argsort(SliceLocation)
    SliceLocation = SliceLocation[sort_index]
    SOPInstanceUIDs = [SOPInstanceUIDs[n] for n in sort_index]
    images = [images[n] for n in sort_index]
    mr = np.dstack(images).astype("float32")

    if mr.shape[0:2] != (dcm.Rows, dcm.Columns):
      print("WARNING: GridSize " + str(mr.shape[0:2]) + " different from Dicom Rows (" + str(dcm.Rows) + ") and Columns (" + str(dcm.Columns) + ")")

    MeanSliceDistance = (SliceLocation[-1] - SliceLocation[0]) / (len(images)-1)
    if(abs(MeanSliceDistance - dcm.SliceThickness) > 0.001):
      print("WARNING: MeanSliceDistance (" + str(MeanSliceDistance) + ") is different from SliceThickness (" + str(dcm.SliceThickness) + ")")    

    self.FrameOfReferenceUID = dcm.FrameOfReferenceUID
    self.ImagePositionPatient = [float(dcm.ImagePositionPatient[0]), float(dcm.ImagePositionPatient[1]), SliceLocation[0]]
    self.PixelSpacing = [float(dcm.PixelSpacing[0]), float(dcm.PixelSpacing[1]), MeanSliceDistance]
    self.GridSize = list(mr.shape)
    self.NumVoxels = self.GridSize[0] * self.GridSize[1] * self.GridSize[2]
    self.Image = mr
    self.SeriesDescription = dcm.SeriesDescription
    self.SOPInstanceUIDs = SOPInstanceUIDs
    self.VoxelX = self.ImagePositionPatient[0] + np.arange(self.GridSize[0])*self.PixelSpacing[0]
    self.VoxelY = self.ImagePositionPatient[1] + np.arange(self.GridSize[1])*self.PixelSpacing[1]
    self.VoxelZ = self.ImagePositionPatient[2] + np.arange(self.GridSize[2])*self.PixelSpacing[2]
    self.isLoaded = 1