-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmha.py
executable file
·191 lines (152 loc) · 6.33 KB
/
mha.py
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
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
"""
This class reads and writes mha files (images or vector fields)
Author: Paolo Zaffino ([email protected])
Rev 19
NOT TESTED ON PYTHON 3
"""
import numpy as np
class new():
"""
PUBLIC PARAMETERS:
data=3D/4D matrix
size=3D/4D matrix size
spacing=voxel size
offset=spatial offset of data data
data_type='short', 'float' or 'uchar'
direction_cosines=direction cosines of the raw image/vf
num_components=number of components in the image/vf
CONSTRUCTOR OVERLOADING:
img=mha.new() # All the public parameters will be set to None
img=mha.new(input_file='img.mha')
img=mha.new(data=matrix, size=[512, 512, 80], spacing=[0.9, 0.9, 5], offset=[-240, -240, -160], data_type='short', direction_cosines=[1, 0, 0, 0, 1, 0, 0, 0, 1], num_components=1)
PUBLIC METHODS:
img.read_mha('file_name.mha')
img.write_mha('file_name.mha')
"""
data=None
size=None
spacing=None
offset=None
data_type=None
direction_cosines=None
num_components=None
######################## CONSTRUCTOR - START - #########################
def __init__ (self, input_file=None, data=None, size=None, spacing=None, offset=None, data_type=None, direction_cosines=None, num_components=None):
if input_file!=None and data==None and size==None and spacing==None and offset==None and data_type==None and direction_cosines==None and num_components==None:
self.read_mha(input_file)
elif input_file==None and data!=None and size!=None and spacing!=None and offset!=None and data_type!=None and direction_cosines!=None and num_components==None:
self.data=data
self.size=size
self.spacing=spacing
self.offset=offset
self.data_type=data_type
self.direction_cosines=direction_cosines
self.num_components=num_components
elif input_file==None and data==None and size==None and spacing==None and offset==None and data_type==None and direction_cosines==None:
pass
######################## CONSTRUCTOR - END - ###########################
######################## READ_MHA - START - ############################
def read_mha(self, fn):
"""
This method reads a mha file and assigns the data to the object parameters
INPUT PARAMETER:
fn=file name
"""
if fn.endswith('.mha'): ## Check if the file extension is ".mha"
f = open(fn,'rb')
## Read mha header
self.num_components=1 ## On default the matrix is considered to be an image
while True:
row=f.readline()
if row.startswith('TransformMatrix ='):
row=row.split('=')[1].strip()
self.direction_cosines=self._cast2int(map(float, row.split()))
elif row.startswith('Offset ='):
row=row.split('=')[1].strip()
self.offset=self._cast2int(map(float, row.split()))
elif row.startswith('ElementSpacing ='):
row=row.split('=')[1].strip()
self.spacing=self._cast2int(map(float, row.split()))
elif row.startswith('DimSize ='):
row=row.split('=')[1].strip()
self.size=map(int, row.split())
elif row.startswith('ElementNumberOfChannels ='):
row=row.split('=')[1].strip()
self.num_components=int(row)
elif row.startswith('ElementType ='):
data_type=row.split('=')[1].strip()
elif row.startswith('ElementDataFile ='):
break
## Read raw data
self.data=''.join(f.readlines())
f.close()
## Raw data from string to array
if data_type == 'MET_SHORT':
self.data=np.fromstring(self.data, dtype=np.int16)
self.data_type = 'short'
elif data_type == 'MET_FLOAT':
self.data=np.fromstring(self.data, dtype=np.float32)
self.data_type = 'float'
elif data_type == 'MET_UCHAR':
self.data=np.fromstring(self.data, dtype=np.uint8)
self.data_type = 'uchar'
else:
raise Exception("Unknown Data Type: %s"%(data_type))
## Reshape array
if self.num_components==1:
self.data=self.data.reshape(self.size[2],self.size[1],self.size[0])
else:
self.data=self.data.reshape(self.size[2],self.size[1],self.size[0],self.num_components)
elif not fn.endswith('.mha'): ## Extension file is not ".mha". It returns all null values
raise NameError('The input file is not a mha file!')
######################### READ_MHA - END - #############################
######################## WRITE_MHA - START - ###########################
def write_mha (self,fn):
"""
This method writes the object parameters in a mha file
INPUT PARAMETER:
fn=file name
"""
if fn.endswith('.mha'): ## Check if the file extension is ".mha"
## Order the matrix in the proper way
self.data = np.array(self.data, order = "F")
f=open(fn, 'wb')
## Write mha header
f.write('ObjectType = Image\n')
f.write('NDims = 3\n')
f.write('BinaryData = True\n')
f.write('BinaryDataByteOrderMSB = False\n')
f.write('CompressedData = False\n')
f.write('TransformMatrix = '+str(self.direction_cosines).strip('()[]').replace(',','')+'\n')
f.write('Offset = '+str(self.offset).strip('()[]').replace(',','')+'\n')
f.write('CenterOfRotation = 0 0 0\n')
f.write('AnatomicalOrientation = RAI\n')
f.write('ElementSpacing = '+str(self.spacing).strip('()[]').replace(',','')+'\n')
f.write('DimSize = '+str(self.size).strip('()[]').replace(',','')+'\n')
if self.num_components != 1:
f.write('ElementNumberOfChannels = %d\n'%(self.num_components))
# self.data=self._shiftdim(self.data, 3) ## Shift dimensions if the input matrix is a vf
if self.data_type == 'short':
f.write('ElementType = MET_SHORT\n')
elif self.data_type == 'float':
f.write('ElementType = MET_FLOAT\n')
elif self.data_type == 'uchar':
f.write('ElementType = MET_UCHAR\n')
else:
raise Exception("Unknown Data Type: %s"%(self.data_type))
f.write('ElementDataFile = LOCAL\n')
## Write matrix
f.write(self.data.ravel())
f.close()
elif not fn.endswith('.mha'): ## File extension is not ".mha"
raise NameError('The input file name is not a mha file!')
######################## WRITE_MHA - END - #############################
############ UTILITY FUNCTIONS, NOT FOR PUBLIC USE - START - ###########
def _cast2int (self, l):
l_new=[]
for i in l:
if i.is_integer(): l_new.append(int(i))
else: l_new.append(i)
return l_new
_shiftdim = lambda self, x, n: x.transpose(np.roll(range(x.ndim), -n))
############# UTILITY FUNCTIONS, NOT FOR PUBLIC USE - END - ############