bzr branch
http://darksoft.org/webbzr/tomo/pyhst
4
by csa
Initial import |
1 |
"""
|
2 |
EdfFile.py
|
|
3 |
Generic class for Edf files manipulation.
|
|
4 |
||
5 |
Interface:
|
|
6 |
===========================
|
|
7 |
class EdfFile:
|
|
8 |
__init__(self,FileName)
|
|
9 |
GetNumImages(self)
|
|
10 |
def GetData(self,Index, DataType="",Pos=None,Size=None):
|
|
11 |
GetPixel(self,Index,Position)
|
|
12 |
GetHeader(self,Index)
|
|
13 |
GetStaticHeader(self,Index)
|
|
14 |
WriteImage (self,Header,Data,Append=1,DataType="",WriteAsUnsigened=0,ByteOrder="")
|
|
15 |
||
16 |
||
17 |
Edf format assumptions:
|
|
18 |
===========================
|
|
19 |
The following details were assumed for this implementation:
|
|
20 |
- Each Edf file contains a certain number of data blocks.
|
|
21 |
- Each data block represents data stored in an one, two or three-dimensional array.
|
|
22 |
- Each data block contains a header section, written in ASCII, and a data section of
|
|
23 |
binary information.
|
|
24 |
- The size of the header section in bytes is a multiple of 1024. The header is
|
|
25 |
padded with spaces (0x20). If the header is not padded to a multiple of 1024,
|
|
26 |
the file is recognized, but the output is always made in this format.
|
|
27 |
- The header section starts by '{' and finishes by '}'. It is composed by several
|
|
28 |
pairs 'keyword = value;'. The keywords are case insensitive, but the values are case
|
|
29 |
sensitive. Each pair is put in a new line (they are separeted by 0x0A). In the
|
|
30 |
end of each line, a semicolon (;) separes the pair of a comment, not interpreted.
|
|
31 |
Exemple:
|
|
32 |
{
|
|
33 |
; Exemple Header
|
|
34 |
HeaderID = EH:000001:000000:000000 ; automatically generated
|
|
35 |
ByteOrder = LowByteFirst ;
|
|
36 |
DataType = FloatValue ; 4 bytes per pixel
|
|
37 |
Size = 4000000 ; size of data section
|
|
38 |
Dim_1= 1000 ; x coordinates
|
|
39 |
Dim_2 = 1000 ; y coordinates
|
|
40 |
|
|
41 |
(padded with spaces to complete 1024 bytes)
|
|
42 |
}
|
|
43 |
- There are some fields in the header that are required for this implementation. If any of
|
|
44 |
these is missing, or inconsistent, it will be generated an error:
|
|
45 |
Size: Represents size of data block
|
|
46 |
Dim_1: size of x coordinates (Dim_2 for 2-dimentional images, and also Dim_3 for 3d)
|
|
47 |
DataType
|
|
48 |
ByteOrder
|
|
49 |
- For the written images, these fields are automatically genereted:
|
|
50 |
Size,Dim_1 (Dim_2 and Dim_3, if necessary), Byte Order, DataType, HeaderID and Image
|
|
51 |
These fields are called here "static header", and can be retrieved by the method
|
|
52 |
GetStaticHeader. Other header components are taken by GetHeader. Both methods returns
|
|
53 |
a dictionary in which the key is the keyword of the pair. When writting an image through
|
|
54 |
WriteImage method, the Header parameter should not contain the static header information,
|
|
55 |
which is automatically generated.
|
|
56 |
- The indexing of images through these functions is based just on the 0-based position in
|
|
57 |
the file, the header items HeaderID and Image are not considered for referencing the
|
|
58 |
images.
|
|
59 |
- The data section contais a number of bytes equal to the value of Size keyword. Data
|
|
60 |
section is going to be translated into an 1D, 2D or 3D Numaric Array, and accessed
|
|
61 |
through GetData method call.
|
|
62 |
||
63 |
||
64 |
IMPORTANT - READ THIS
|
|
65 |
===========================
|
|
66 |
If you are going to use EdfFile, you have to care about the type of your data.
|
|
67 |
The EdfFile class stores data in a Numeric Python array, very efficient
|
|
68 |
way for doing matrix operations.
|
|
69 |
||
70 |
However, for an unknow reason (to us), Numeric Python doesn't handle the following
|
|
71 |
types:
|
|
72 |
- unsigned short
|
|
73 |
- unsigned integer
|
|
74 |
- unsigned long
|
|
75 |
Which are supported by Edf file specification.
|
|
76 |
So if you use these formats, pay attention to the type parameters when reading
|
|
77 |
from or writing to a file (when using other Edf types, the convertions are direct,
|
|
78 |
and you don't need to mention the type, unless you really want to change it).
|
|
79 |
||
80 |
By default, if no type is mentioned, the EdfFile class stores, when reading a file:
|
|
81 |
- UnsignedShort data into an short array
|
|
82 |
- UnsignedInteger data into an integer array
|
|
83 |
- UnsignedLong data into a long array
|
|
84 |
||
85 |
This keeps the size of storage in memory, but can imply in loss of information.
|
|
86 |
||
87 |
Taking "unsigned short" as an exemple:
|
|
88 |
1) Supposing you get data with: "array=obj.GetData(0)", this array is going to be
|
|
89 |
created as signed short. If you write it then as: 'obj2.WriteImage({},array)',
|
|
90 |
the edf image created is going to be of signed short type, different from the
|
|
91 |
original. To save in the same way as the former image, you must be explicit
|
|
92 |
about the data type: 'obj2.WriteImage({},array,DataType="UnsignedShort")'
|
|
93 |
2) If you intend to make operations, or even just read properly the values of an
|
|
94 |
image, you should read this image as 'array=obj.GetData(0),DataType="Long")'.
|
|
95 |
This will require two times the storage space but will assure correct values.
|
|
96 |
If you intend to save it again, you should include the correct data type you
|
|
97 |
are saving to.
|
|
98 |
3) When you are saving an unsigned short array into a long, float or double
|
|
99 |
format, you should be explicit to the fact you want this array to be
|
|
100 |
considered a signed or unsigned (through the parameter WriteAsUnsigened).
|
|
101 |
Suppose an hexa value of FFFF in this array. This means -1 if the array
|
|
102 |
comes from signed data, or 65535 if it cames from unsigned data. If you save
|
|
103 |
the array as this: 'obj2.WriteImage({},array,DataType="FloatValue")' it is
|
|
104 |
going to be considered unsigned, and a value of FFFF is going to be
|
|
105 |
translated into a float -1. If you want to consider the array as unsigned
|
|
106 |
you should do:
|
|
107 |
'obj2.WriteImage({},array,DataType="FloatValue", WriteAsUnsigened=1 )'
|
|
108 |
In this way, a FFFF value is going to be translated into a float 65535.
|
|
109 |
||
110 |
||
111 |
"""
|
|
112 |
||
113 |
__author__ = 'Alexandre Gobbo (gobbo@esrf.fr)' |
|
114 |
__version__= '$Revision: 1.5 $' |
|
115 |
||
116 |
################################################################################
|
|
117 |
import sys, string |
|
34
by csa
Migration to numpy |
118 |
import numpy as Numeric |
4
by csa
Initial import |
119 |
import os.path , tempfile, shutil |
7
by csa
more consistent logging |
120 |
from logger import logger |
121 |
||
4
by csa
Initial import |
122 |
try: |
123 |
from FastEdf import extended_fread |
|
124 |
CAN_USE_FASTEDF = 1 |
|
7
by csa
more consistent logging |
125 |
logger.info(" imported the fast binary for edffile readings ") |
4
by csa
Initial import |
126 |
except: |
127 |
CAN_USE_FASTEDF = 0 |
|
7
by csa
more consistent logging |
128 |
logger.warning(" WARNING, the FastEDF is not imported (extended_fread is missing)") |
4
by csa
Initial import |
129 |
|
130 |
################################################################################
|
|
131 |
# constants
|
|
132 |
HEADER_BLOCK_SIZE = 1024 |
|
133 |
STATIC_HEADER_ELEMENTS=("HeaderID","Image","ByteOrder","DataType","Dim_1","Dim_2","Dim_3","Size") |
|
134 |
STATIC_HEADER_ELEMENTS_CAPS=("HEADERID","IMAGE","BYTEORDER","DATATYPE","DIM_1","DIM_2","DIM_3","SIZE") |
|
135 |
||
136 |
LOWER_CASE=0 |
|
137 |
UPPER_CASE=1 |
|
138 |
||
139 |
KEYS=1 |
|
140 |
VALUES=2 |
|
141 |
||
142 |
###############################################################################
|
|
143 |
class Image: |
|
144 |
"""
|
|
145 |
"""
|
|
146 |
def __init__(self): |
|
147 |
""" Constructor
|
|
148 |
"""
|
|
149 |
self.Header={} |
|
150 |
self.StaticHeader={} |
|
151 |
self.HeaderPosition=0 |
|
152 |
self.DataPosition=0 |
|
153 |
self.Size=0 |
|
154 |
self.NumDim=1 |
|
155 |
self.Dim1=0 |
|
156 |
self.Dim2=0 |
|
157 |
self.Dim3=0 |
|
158 |
self.DataType="" |
|
159 |
#for i in STATIC_HEADER_ELEMENTS: self.StaticHeader[i]=""
|
|
160 |
||
161 |
################################################################################
|
|
162 |
||
163 |
class EdfFile: |
|
164 |
"""
|
|
165 |
"""
|
|
166 |
############################################################################
|
|
167 |
#Interface
|
|
168 |
def __init__(self,FileName,fastedf=None): |
|
169 |
""" Constructor
|
|
170 |
FileName: Name of the file (either existing or to be created)
|
|
171 |
"""
|
|
172 |
self.Images=[] |
|
173 |
self.NumImages=0 |
|
174 |
self.FileName=FileName |
|
175 |
self.File = 0 |
|
176 |
if fastedf is None:fastedf=0 |
|
177 |
self.fastedf=fastedf |
|
178 |
||
179 |
if sys.byteorder=="big": self.SysByteOrder="HighByteFirst" |
|
180 |
else: self.SysByteOrder="LowByteFirst" |
|
181 |
try: |
|
182 |
if os.path.isfile(self.FileName)==0: |
|
183 |
self.File = open(self.FileName, "wb") |
|
184 |
self.File.close() |
|
185 |
||
186 |
if (os.access(self.FileName,os.W_OK)): |
|
187 |
self.File=open(self.FileName, "r+b") |
|
188 |
else : |
|
189 |
self.File=open(self.FileName, "rb") |
|
190 |
||
191 |
self.File.seek(0, 0) |
|
37
by csa
Optimizations of EDF reading |
192 |
except None: |
4
by csa
Initial import |
193 |
try: |
194 |
self.File.close() |
|
195 |
except: |
|
196 |
pass
|
|
197 |
print "filename ", FileName |
|
198 |
raise Exception, "EdfFile: Error opening file" |
|
199 |
||
200 |
self.File.seek(0, 0) |
|
201 |
||
202 |
Index=0 |
|
203 |
line = self.File.readline() |
|
204 |
while line != "": |
|
205 |
if string.count(line, "{\n") >= 1 or string.count(line, "{\r\n")>=1: |
|
206 |
Index=self.NumImages |
|
207 |
self.NumImages = self.NumImages + 1 |
|
208 |
self.Images.append(Image()) |
|
209 |
self.Images[Index].HeaderPosition=self.File.tell() |
|
210 |
||
211 |
if string.count(line, "=") >= 1: |
|
212 |
listItems = string.split(line, "=", 1) |
|
213 |
typeItem = string.strip(listItems[0]) |
|
214 |
listItems = string.split(listItems[1], ";", 1) |
|
215 |
valueItem = string.strip(listItems[0]) |
|
216 |
||
217 |
#if typeItem in self.Images[Index].StaticHeader.keys():
|
|
218 |
if (string.upper(typeItem)) in STATIC_HEADER_ELEMENTS_CAPS: |
|
219 |
self.Images[Index].StaticHeader[typeItem]=valueItem |
|
220 |
else: |
|
221 |
self.Images[Index].Header[typeItem]=valueItem |
|
222 |
if string.count(line, "}\n") >= 1: |
|
223 |
#for i in STATIC_HEADER_ELEMENTS_CAPS:
|
|
224 |
# if self.Images[Index].StaticHeader[i]=="":
|
|
225 |
# raise Exception, "Bad File Format"
|
|
226 |
self.Images[Index].DataPosition=self.File.tell() |
|
227 |
#self.File.seek(string.atoi(self.Images[Index].StaticHeader["Size"]), 1)
|
|
228 |
StaticPar = SetDictCase(self.Images[Index].StaticHeader,UPPER_CASE,KEYS) |
|
229 |
if "SIZE" in StaticPar.keys(): |
|
230 |
self.Images[Index].Size = string.atoi(StaticPar["SIZE"]) |
|
231 |
else: |
|
232 |
raise Exception, "EdfFile: Image doesn't have size information" |
|
233 |
if "DIM_1" in StaticPar.keys(): |
|
234 |
self.Images[Index].Dim1 = string.atoi(StaticPar["DIM_1"]) |
|
235 |
else: |
|
236 |
raise Exception, "EdfFile: Image doesn't have dimension information" |
|
237 |
if "DIM_2" in StaticPar.keys(): |
|
238 |
self.Images[Index].NumDim=2 |
|
239 |
self.Images[Index].Dim2 = string.atoi(StaticPar["DIM_2"]) |
|
240 |
if "DIM_3" in StaticPar.keys(): |
|
241 |
self.Images[Index].NumDim=3 |
|
242 |
self.Images[Index].Dim3 = string.atoi(StaticPar["DIM_3"]) |
|
243 |
if "DATATYPE" in StaticPar.keys(): |
|
244 |
self.Images[Index].DataType=StaticPar["DATATYPE"] |
|
245 |
else: |
|
246 |
raise Exception, "EdfFile: Image doesn't have datatype information" |
|
247 |
if "BYTEORDER" in StaticPar.keys(): |
|
248 |
self.Images[Index].ByteOrder=StaticPar["BYTEORDER"] |
|
249 |
else: |
|
250 |
raise Exception, "EdfFile: Image doesn't have byteorder information" |
|
251 |
||
252 |
||
253 |
||
254 |
self.File.seek(self.Images[Index].Size, 1) |
|
255 |
||
256 |
line = self.File.readline() |
|
257 |
||
258 |
||
259 |
def GetNumImages(self): |
|
260 |
""" Returns number of images of the object (and associated file)
|
|
261 |
"""
|
|
262 |
return self.NumImages |
|
263 |
||
264 |
||
265 |
||
266 |
def GetData(self,Index, DataType="",Pos=None,Size=None): |
|
267 |
""" Returns numeric array with image data
|
|
268 |
Index: The zero-based index of the image in the file
|
|
269 |
DataType: The edf type of the array to be returnd
|
|
270 |
If ommited, it is used the default one for the type
|
|
271 |
indicated in the image header
|
|
272 |
Attention to the absence of UnsignedShort,
|
|
273 |
UnsignedInteger and UnsignedLong types in
|
|
274 |
Numeric Python
|
|
275 |
Default relation between Edf types and NumPy's typecodes:
|
|
276 |
SignedByte 1
|
|
277 |
UnsignedByte b
|
|
278 |
SignedShort s
|
|
279 |
UnsignedShort w
|
|
280 |
SignedInteger i
|
|
281 |
UnsignedInteger u
|
|
282 |
SignedLong l
|
|
283 |
UnsignedLong u
|
|
284 |
FloatValue f
|
|
285 |
DoubleValue d
|
|
286 |
Pos: Tuple (x) or (x,y) or (x,y,z) that indicates the begining
|
|
287 |
of data to be read. If ommited, set to the origin (0),
|
|
288 |
(0,0) or (0,0,0)
|
|
289 |
Size: Tuple, size of the data to be returned as x) or (x,y) or
|
|
290 |
(x,y,z) if ommited, is the distance from Pos to the end.
|
|
291 |
||
292 |
If Pos and Size not mentioned, returns the whole data.
|
|
293 |
"""
|
|
294 |
fastedf = self.fastedf |
|
295 |
if Index < 0 or Index >= self.NumImages: raise Exception, "EdfFile: Index(%i) is out of %i available images" % (Index, self.NumImages) |
|
296 |
if fastedf is None:fastedf = 0 |
|
297 |
if Pos is None and Size is None: |
|
298 |
self.File.seek(self.Images[Index].DataPosition,0) |
|
299 |
Data = Numeric.fromstring(self.File.read(self.Images[Index].Size), self.__GetDefaultNumericType__(self.Images[Index].DataType)) |
|
300 |
if self.Images[Index].NumDim==3: |
|
301 |
Data = Numeric.reshape(Data, (self.Images[Index].Dim3,self.Images[Index].Dim2, self.Images[Index].Dim1)) |
|
302 |
elif self.Images[Index].NumDim==2: |
|
303 |
Data = Numeric.reshape(Data, (self.Images[Index].Dim2, self.Images[Index].Dim1)) |
|
304 |
elif fastedf and CAN_USE_FASTEDF: |
|
305 |
type= self.__GetDefaultNumericType__(self.Images[Index].DataType) |
|
306 |
size_pixel=self.__GetSizeNumericType__(type) |
|
307 |
Data=Numeric.array([],type) |
|
308 |
if self.Images[Index].NumDim==1: |
|
309 |
if Pos==None: Pos=(0,) |
|
310 |
if Size==None: Size=(0,) |
|
311 |
sizex=self.Images[Index].Dim1 |
|
312 |
Size=list(Size) |
|
313 |
if Size[0]==0:Size[0]=sizex-Pos[0] |
|
314 |
self.File.seek((Pos[0]*size_pixel)+self.Images[Index].DataPosition,0) |
|
315 |
Data = Numeric.fromstring(self.File.read(Size[0]*size_pixel), type) |
|
316 |
elif self.Images[Index].NumDim==2: |
|
317 |
if Pos==None: Pos=(0,0) |
|
318 |
if Size==None: Size=(0,0) |
|
319 |
Size=list(Size) |
|
320 |
sizex,sizey=self.Images[Index].Dim1,self.Images[Index].Dim2 |
|
321 |
if Size[0]==0:Size[0]=sizex-Pos[0] |
|
322 |
if Size[1]==0:Size[1]=sizey-Pos[1] |
|
323 |
Data=Numeric.zeros([Size[1],Size[0]],type) |
|
324 |
self.File.seek((((Pos[1]*sizex)+Pos[0])*size_pixel)+self.Images[Index].DataPosition,0) |
|
36
by csa
Fix usage of fast EDF reader |
325 |
#print Size[0], Size[1], sizex, size_pixel
|
326 |
extended_fread(Data, Size[0]*size_pixel , Numeric.array([Size[1]],"i"), Numeric.array([sizex*size_pixel],"i"), self.File) |
|
4
by csa
Initial import |
327 |
|
328 |
elif self.Images[Index].NumDim==3: |
|
329 |
if Pos==None: Pos=(0,0,0) |
|
330 |
if Size==None: Size=(0,0,0) |
|
331 |
Size=list(Size) |
|
332 |
sizex,sizey,sizez=self.Images[Index].Dim1,self.Images[Index].Dim2,self.Images[Index].Dim3 |
|
333 |
if Size[0]==0:Size[0]=sizex-Pos[0] |
|
334 |
if Size[1]==0:Size[1]=sizey-Pos[1] |
|
335 |
if Size[2]==0:Size[2]=sizez-Pos[2] |
|
336 |
Data=Numeric.zeros([Size[2],Size[1],Size[0]],type) |
|
337 |
self.File.seek(((((Pos[2]*sizey+Pos[1])*sizex)+Pos[0])*size_pixel)+self.Images[Index].DataPosition,0) |
|
36
by csa
Fix usage of fast EDF reader |
338 |
extended_fread(Data, Size[0]*size_pixel , Numeric.array([Size[2],Size[1]], "i"), |
339 |
Numeric.array([ sizey*sizex*size_pixel , sizex*size_pixel], "i") ,self.File) |
|
4
by csa
Initial import |
340 |
|
341 |
else: |
|
342 |
if fastedf:print "I could not use fast routines" |
|
343 |
type= self.__GetDefaultNumericType__(self.Images[Index].DataType) |
|
344 |
size_pixel=self.__GetSizeNumericType__(type) |
|
345 |
Data=Numeric.array([],type) |
|
346 |
if self.Images[Index].NumDim==1: |
|
347 |
if Pos==None: Pos=(0,) |
|
348 |
if Size==None: Size=(0,) |
|
349 |
sizex=self.Images[Index].Dim1 |
|
350 |
Size=list(Size) |
|
351 |
if Size[0]==0:Size[0]=sizex-Pos[0] |
|
352 |
self.File.seek((Pos[0]*size_pixel)+self.Images[Index].DataPosition,0) |
|
353 |
Data = Numeric.fromstring(self.File.read(Size[0]*size_pixel), type) |
|
354 |
elif self.Images[Index].NumDim==2: |
|
355 |
if Pos==None: Pos=(0,0) |
|
356 |
if Size==None: Size=(0,0) |
|
357 |
Size=list(Size) |
|
358 |
sizex,sizey=self.Images[Index].Dim1,self.Images[Index].Dim2 |
|
359 |
if Size[0]==0:Size[0]=sizex-Pos[0] |
|
360 |
if Size[1]==0:Size[1]=sizey-Pos[1] |
|
361 |
for y in range(Pos[1],Pos[1]+Size[1]): |
|
362 |
self.File.seek((((y*sizex)+Pos[0])*size_pixel)+self.Images[Index].DataPosition,0) |
|
363 |
line = Numeric.fromstring(self.File.read(Size[0]*size_pixel), type) |
|
364 |
Data=Numeric.concatenate((Data,line)) |
|
365 |
Data = Numeric.reshape(Data, (Size[1],Size[0])) |
|
366 |
elif self.Images[Index].NumDim==3: |
|
367 |
if Pos==None: Pos=(0,0,0) |
|
368 |
if Size==None: Size=(0,0,0) |
|
369 |
Size=list(Size) |
|
370 |
sizex,sizey,sizez=self.Images[Index].Dim1,self.Images[Index].Dim2,self.Images[Index].Dim3 |
|
371 |
if Size[0]==0:Size[0]=sizex-Pos[0] |
|
372 |
if Size[1]==0:Size[1]=sizey-Pos[1] |
|
373 |
if Size[2]==0:Size[2]=sizez-Pos[2] |
|
374 |
for z in range(Pos[2],Pos[2]+Size[2]): |
|
375 |
for y in range(Pos[1],Pos[1]+Size[1]): |
|
376 |
self.File.seek(((((z*sizey+y)*sizex)+Pos[0])*size_pixel)+self.Images[Index].DataPosition,0) |
|
377 |
line = Numeric.fromstring(self.File.read(Size[0]*size_pixel), type) |
|
378 |
Data=Numeric.concatenate((Data,line)) |
|
379 |
Data = Numeric.reshape(Data, (Size[2],Size[1],Size[0])) |
|
380 |
||
381 |
if string.upper(self.SysByteOrder)!=string.upper(self.Images[Index].ByteOrder): |
|
34
by csa
Migration to numpy |
382 |
Data=Data.byteswap(False) |
4
by csa
Initial import |
383 |
if DataType != "": |
384 |
Data=self.__SetDataType__ (Data,DataType) |
|
385 |
return Data |
|
386 |
||
387 |
||
388 |
||
389 |
def GetPixel(self,Index, Position): |
|
390 |
""" Returns double value of the pixel, regardless the format of the array
|
|
391 |
Index: The zero-based index of the image in the file
|
|
392 |
Position: Tuple with the coordinete (x), (x,y) or (x,y,z)
|
|
393 |
"""
|
|
394 |
if Index < 0 or Index >= self.NumImages: raise Exception, "EdfFile: Index out of limit" |
|
395 |
if len(Position)!= self.Images[Index].NumDim: raise Exception, "EdfFile: coordinate with wrong dimension " |
|
396 |
||
397 |
size_pixel=self.__GetSizeNumericType__(self.__GetDefaultNumericType__(self.Images[Index].DataType)) |
|
398 |
offset=Position[0]*size_pixel |
|
399 |
if self.Images[Index].NumDim>1: |
|
400 |
size_row=size_pixel * self.Images[Index].Dim1 |
|
401 |
offset=offset+ (Position[1]* size_row) |
|
402 |
if self.Images[Index].NumDim==3: |
|
403 |
size_img=size_row * self.Images[Index].Dim2 |
|
404 |
offset=offset+ (Position[2]* size_img) |
|
405 |
self.File.seek(self.Images[Index].DataPosition + offset,0) |
|
406 |
Data = Numeric.fromstring(self.File.read(size_pixel), self.__GetDefaultNumericType__(self.Images[Index].DataType)) |
|
407 |
if string.upper(self.SysByteOrder)!=string.upper(self.Images[Index].ByteOrder): |
|
408 |
Data=Data.byteswapped() |
|
409 |
Data=self.__SetDataType__ (Data,"DoubleValue") |
|
410 |
return Data[0] |
|
411 |
||
412 |
||
413 |
def GetHeader(self,Index): |
|
414 |
""" Returns dictionary with image header fields.
|
|
415 |
Does not include the basic fields (static) defined by data shape,
|
|
416 |
type and file position. These are get with GetStaticHeader
|
|
417 |
method.
|
|
418 |
Index: The zero-based index of the image in the file
|
|
419 |
"""
|
|
420 |
if Index < 0 or Index >= self.NumImages: raise Exception, "Index out of limit" |
|
421 |
#return self.Images[Index].Header
|
|
422 |
ret={} |
|
423 |
for i in self.Images[Index].Header.keys(): |
|
424 |
ret[i]=self.Images[Index].Header[i] |
|
425 |
return ret |
|
426 |
||
427 |
||
428 |
def GetStaticHeader(self,Index): |
|
429 |
""" Returns dictionary with static parameters
|
|
430 |
Data format and file position dependent information
|
|
431 |
(dim1,dim2,size,datatype,byteorder,headerId,Image)
|
|
432 |
Index: The zero-based index of the image in the file
|
|
433 |
"""
|
|
434 |
if Index < 0 or Index >= self.NumImages: raise Exception, "Index out of limit" |
|
435 |
#return self.Images[Index].StaticHeader
|
|
436 |
ret={} |
|
437 |
for i in self.Images[Index].StaticHeader.keys(): |
|
438 |
ret[i]=self.Images[Index].StaticHeader[i] |
|
439 |
return ret |
|
440 |
||
441 |
||
442 |
def WriteImage (self,Header,Data,Append=1,DataType="",ByteOrder=""): |
|
443 |
""" Writes image to the file.
|
|
444 |
Header: Dictionary containing the non-static header
|
|
445 |
information (static information is generated
|
|
446 |
according to position of image and data format
|
|
447 |
Append: If equals to 0, overwrites the file. Otherwise, appends
|
|
448 |
to the end of the file
|
|
449 |
DataType: The data type to be saved to the file:
|
|
450 |
SignedByte
|
|
451 |
UnsignedByte
|
|
452 |
SignedShort
|
|
453 |
UnsignedShort
|
|
454 |
SignedInteger
|
|
455 |
UnsignedInteger
|
|
456 |
SignedLong
|
|
457 |
UnsignedLong
|
|
458 |
FloatValue
|
|
459 |
DoubleValue
|
|
460 |
Default: according to Data array typecode:
|
|
461 |
1: SignedByte
|
|
462 |
b: UnsignedByte
|
|
463 |
s: SignedShort
|
|
464 |
w: UnsignedShort
|
|
465 |
i: SignedInteger
|
|
466 |
l: SignedLong
|
|
467 |
u: UnsignedLong
|
|
468 |
f: FloatValue
|
|
469 |
d: DoubleValue
|
|
470 |
ByteOrder: Byte order of the data in file:
|
|
471 |
HighByteFirst
|
|
472 |
LowByteFirst
|
|
473 |
Default: system's byte order
|
|
474 |
"""
|
|
475 |
if Append==0: |
|
476 |
self.File.truncate(0) |
|
477 |
self.Images=[] |
|
478 |
self.NumImages=0 |
|
479 |
Index=self.NumImages |
|
480 |
self.NumImages = self.NumImages + 1 |
|
481 |
self.Images.append(Image()) |
|
482 |
||
483 |
#self.Images[Index].StaticHeader["Dim_1"] = "%d" % Data.shape[1]
|
|
484 |
#self.Images[Index].StaticHeader["Dim_2"] = "%d" % Data.shape[0]
|
|
485 |
if len(Data.shape)==1: |
|
486 |
self.Images[Index].Dim1=Data.shape[0] |
|
487 |
self.Images[Index].StaticHeader["Dim_1"] = "%d" % self.Images[Index].Dim1 |
|
34
by csa
Migration to numpy |
488 |
self.Images[Index].Size=(Data.shape[0]*self.__GetSizeNumericType__(Data.dtype.char)) |
4
by csa
Initial import |
489 |
elif len(Data.shape)==2: |
490 |
self.Images[Index].Dim1=Data.shape[1] |
|
491 |
self.Images[Index].Dim2=Data.shape[0] |
|
492 |
self.Images[Index].StaticHeader["Dim_1"] = "%d" % self.Images[Index].Dim1 |
|
493 |
self.Images[Index].StaticHeader["Dim_2"] = "%d" % self.Images[Index].Dim2 |
|
34
by csa
Migration to numpy |
494 |
self.Images[Index].Size=(Data.shape[0]*Data.shape[1]*self.__GetSizeNumericType__(Data.dtype.char)) |
4
by csa
Initial import |
495 |
self.Images[Index].NumDim=2 |
496 |
elif len(Data.shape)==3: |
|
497 |
self.Images[Index].Dim1=Data.shape[2] |
|
498 |
self.Images[Index].Dim2=Data.shape[1] |
|
499 |
self.Images[Index].Dim3=Data.shape[0] |
|
500 |
self.Images[Index].StaticHeader["Dim_1"] = "%d" % self.Images[Index].Dim1 |
|
501 |
self.Images[Index].StaticHeader["Dim_2"] = "%d" % self.Images[Index].Dim2 |
|
502 |
self.Images[Index].StaticHeader["Dim_3"] = "%d" % self.Images[Index].Dim3 |
|
34
by csa
Migration to numpy |
503 |
self.Images[Index].Size=(Data.shape[0]*Data.shape[1]*Data.shape[2]*self.__GetSizeNumericType__(Data.dtype.char)) |
4
by csa
Initial import |
504 |
self.Images[Index].NumDim=3 |
505 |
elif len(Data.shape)>3: |
|
506 |
raise Exception, "EdfFile: Data dimension not suported" |
|
507 |
||
508 |
||
509 |
if DataType=="": |
|
34
by csa
Migration to numpy |
510 |
self.Images[Index].DataType=self.__GetDefaultEdfType__(Data.dtype.char) |
4
by csa
Initial import |
511 |
else: |
512 |
self.Images[Index].DataType=DataType |
|
513 |
Data=self.__SetDataType__ (Data,DataType) |
|
514 |
||
515 |
if ByteOrder=="": |
|
516 |
self.Images[Index].ByteOrder=self.SysByteOrder |
|
517 |
else: |
|
518 |
self.Images[Index].ByteOrder=ByteOrder |
|
519 |
||
520 |
self.Images[Index].StaticHeader["Size"] = "%d" % self.Images[Index].Size |
|
521 |
self.Images[Index].StaticHeader["Image"] = Index+1 |
|
522 |
self.Images[Index].StaticHeader["HeaderID"] = "EH:%06d:000000:000000" % self.Images[Index].StaticHeader["Image"] |
|
523 |
self.Images[Index].StaticHeader["ByteOrder"]=self.Images[Index].ByteOrder |
|
524 |
self.Images[Index].StaticHeader["DataType"]=self.Images[Index].DataType |
|
525 |
||
526 |
||
527 |
self.Images[Index].Header={} |
|
528 |
self.File.seek(0,2) |
|
529 |
StrHeader = "{\n" |
|
530 |
for i in STATIC_HEADER_ELEMENTS: |
|
531 |
if i in self.Images[Index].StaticHeader.keys(): |
|
532 |
StrHeader = StrHeader + ("%s = %s ;\n" % (i , self.Images[Index].StaticHeader[i])) |
|
533 |
for i in Header.keys(): |
|
534 |
StrHeader = StrHeader + ("%s = %s ;\n" % (i,Header[i])) |
|
535 |
self.Images[Index].Header[i]=Header[i] |
|
536 |
newsize=(((len(StrHeader)+1)/HEADER_BLOCK_SIZE)+1)*HEADER_BLOCK_SIZE -2 |
|
537 |
StrHeader = string.ljust(StrHeader,newsize) |
|
538 |
StrHeader = StrHeader+"}\n" |
|
539 |
||
540 |
self.Images[Index].HeaderPosition=self.File.tell() |
|
541 |
self.File.write(StrHeader) |
|
542 |
self.Images[Index].DataPosition=self.File.tell() |
|
543 |
||
544 |
#if self.Images[Index].StaticHeader["ByteOrder"] != self.SysByteOrder:
|
|
545 |
if string.upper(self.Images[Index].ByteOrder) != string.upper(self.SysByteOrder): |
|
546 |
self.File.write((Data.byteswapped()).tostring()) |
|
547 |
else: |
|
548 |
self.File.write(Data.tostring()) |
|
549 |
||
550 |
||
551 |
||
552 |
############################################################################
|
|
553 |
#Internal Methods
|
|
554 |
||
555 |
def __GetDefaultNumericType__(self, EdfType): |
|
556 |
""" Internal method: returns NumPy type according to Edf type
|
|
557 |
"""
|
|
558 |
return GetDefaultNumericType(EdfType) |
|
559 |
||
560 |
def __GetDefaultEdfType__(self, NumericType): |
|
561 |
""" Internal method: returns Edf type according Numpy type
|
|
562 |
"""
|
|
563 |
if NumericType == "1": return "SignedByte" |
|
564 |
elif NumericType == "b": return "UnsignedByte" |
|
565 |
elif NumericType == "s": return "SignedShort" |
|
566 |
elif NumericType == "w": return "UnsignedShort" |
|
567 |
elif NumericType == "i": return "SignedInteger" |
|
568 |
elif NumericType == "l": return "SignedLong" |
|
569 |
elif NumericType == "u": return "UnsignedLong" |
|
570 |
elif NumericType == "f": return "FloatValue" |
|
571 |
elif NumericType == "d": return "DoubleValue" |
|
572 |
else: raise Exception, "__GetDefaultEdfType__: unknown NumericType" |
|
573 |
||
574 |
||
575 |
def __GetSizeNumericType__(self, NumericType): |
|
576 |
""" Internal method: returns size of NumPy's Array Types
|
|
577 |
"""
|
|
578 |
if NumericType == "1": return 1 |
|
579 |
elif NumericType == "b": return 1 |
|
580 |
elif NumericType == "s": return 2 |
|
581 |
elif NumericType == "w": return 2 |
|
582 |
elif NumericType == "i": return 4 |
|
583 |
elif NumericType == "l": return 4 |
|
584 |
elif NumericType == "u": return 4 |
|
585 |
elif NumericType == "f": return 4 |
|
586 |
elif NumericType == "d": return 8 |
|
587 |
else: raise Exception, "__GetSizeNumericType__: unknown NumericType" |
|
588 |
||
589 |
||
590 |
def __SetDataType__ (self,Array,DataType): |
|
591 |
""" Internal method: array type convertion
|
|
592 |
"""
|
|
34
by csa
Migration to numpy |
593 |
FromEdfType= Array.dtype.char |
4
by csa
Initial import |
594 |
ToEdfType= self.__GetDefaultNumericType__(DataType) |
595 |
if ToEdfType != FromEdfType: |
|
596 |
aux=Array.astype(self.__GetDefaultNumericType__(DataType)) |
|
597 |
return aux |
|
598 |
return Array |
|
599 |
||
600 |
def __del__(self): |
|
601 |
try: |
|
602 |
self.File.close() |
|
603 |
except: |
|
604 |
pass
|
|
605 |
||
606 |
||
607 |
def GetDefaultNumericType(EdfType): |
|
608 |
""" Returns NumPy type according Edf type
|
|
609 |
"""
|
|
610 |
EdfType=string.upper(EdfType) |
|
611 |
if EdfType == "SIGNEDBYTE": return "1" |
|
612 |
elif EdfType == "UNSIGNEDBYTE": return "b" |
|
613 |
elif EdfType == "SIGNEDSHORT": return "s" |
|
614 |
elif EdfType == "UNSIGNEDSHORT": return "w" |
|
615 |
elif EdfType == "SIGNEDINTEGER": return "i" |
|
616 |
elif EdfType == "UNSIGNEDINTEGER": return "u" |
|
617 |
elif EdfType == "SIGNEDLONG": return "l" |
|
618 |
elif EdfType == "UNSIGNEDLONG": return "u" |
|
619 |
elif EdfType == "FLOATVALUE": return "f" |
|
620 |
elif EdfType == "FLOAT": return "f" |
|
621 |
elif EdfType == "DOUBLEVALUE": return "d" |
|
622 |
else: raise Exception, "__GetDefaultNumericType__: unknown EdfType" |
|
623 |
||
624 |
||
625 |
def SetDictCase(Dict, Case, Flag): |
|
626 |
""" Returns dictionary with keys and/or values converted into upper or lowercase
|
|
627 |
Dict: input dictionary
|
|
628 |
Case: LOWER_CASE, UPPER_CASE
|
|
629 |
Flag: KEYS, VALUES or KEYS | VALUES
|
|
630 |
"""
|
|
631 |
newdict={} |
|
632 |
for i in Dict.keys(): |
|
633 |
newkey=i |
|
634 |
newvalue=Dict[i] |
|
635 |
if Flag & KEYS: |
|
636 |
if Case == LOWER_CASE: newkey = string.lower(newkey) |
|
637 |
else: newkey = string.upper(newkey) |
|
638 |
if Flag & VALUES: |
|
639 |
if Case == LOWER_CASE: newvalue = string.lower(newvalue) |
|
640 |
else: newvalue = string.upper(newvalue) |
|
641 |
newdict[newkey]=newvalue |
|
642 |
return newdict |
|
643 |
||
644 |
||
645 |
def GetRegion(Arr,Pos,Size): |
|
646 |
"""Returns array with refion of Arr.
|
|
647 |
Arr must be 1d, 2d or 3d
|
|
648 |
Pos and Size are tuples in the format (x) or (x,y) or (x,y,z)
|
|
649 |
Both parameters must have the same size as the dimention of Arr
|
|
650 |
"""
|
|
651 |
Dim=len(Arr.shape) |
|
652 |
if len(Pos) != Dim: return None |
|
653 |
if len(Size) != Dim: return None |
|
654 |
||
655 |
if (Dim==1): |
|
656 |
SizeX=Size[0] |
|
657 |
if SizeX==0: SizeX=Arr.shape[0]-Pos[0] |
|
658 |
ArrRet=Numeric.take(Arr, range(Pos[0],Pos[0]+SizeX)) |
|
659 |
elif (Dim==2): |
|
660 |
SizeX=Size[0] |
|
661 |
SizeY=Size[1] |
|
662 |
if SizeX==0: SizeX=Arr.shape[1]-Pos[0] |
|
663 |
if SizeY==0: SizeY=Arr.shape[0]-Pos[1] |
|
664 |
ArrRet=Numeric.take(Arr, range(Pos[1],Pos[1]+SizeY)) |
|
665 |
ArrRet=Numeric.take(ArrRet, range(Pos[0],Pos[0]+SizeX),1) |
|
666 |
elif (Dim==3): |
|
667 |
SizeX=Size[0] |
|
668 |
SizeY=Size[1] |
|
669 |
SizeZ=Size[2] |
|
670 |
if SizeX==0: SizeX=Arr.shape[2]-Pos[0] |
|
671 |
if SizeY==0: SizeX=Arr.shape[1]-Pos[1] |
|
672 |
if SizeZ==0: SizeZ=Arr.shape[0]-Pos[2] |
|
673 |
ArrRet=Numeric.take(Arr, range(Pos[2],Pos[2]+SizeZ)) |
|
674 |
ArrRet=Numeric.take(ArrRet, range(Pos[1],Pos[1]+SizeY),1) |
|
675 |
ArrRet=Numeric.take(ArrRet, range(Pos[0],Pos[0]+SizeX),2) |
|
676 |
else: |
|
677 |
ArrRet=None |
|
678 |
return ArrRet |
|
679 |
||
680 |
#EXEMPLE CODE:
|
|
681 |
if __name__ == "__main__": |
|
682 |
#Creates object based on file exe.edf
|
|
683 |
exe=EdfFile("images/test_image.edf") |
|
684 |
x=EdfFile("images/test_getdata.edf") |
|
685 |
#Gets unsigned short data, storing in an signed long
|
|
686 |
arr=exe.GetData(0,Pos=(100,200),Size=(200,400)) |
|
687 |
x.WriteImage({},arr,0) |
|
688 |
||
689 |
arr=exe.GetData(0,Pos=(100,200)) |
|
690 |
x.WriteImage({},arr) |
|
691 |
||
692 |
arr=exe.GetData(0,Size=(200,400)) |
|
693 |
x.WriteImage({},arr) |
|
694 |
||
695 |
arr=exe.GetData(0) |
|
696 |
x.WriteImage({},arr) |
|
697 |
||
698 |
sys.exit() |
|
699 |
||
700 |
#Creates object based on file exe.edf
|
|
701 |
exe=EdfFile("images/.edf") |
|
702 |
||
703 |
#Creates long array , filled with 0xFFFFFFFF(-1)
|
|
704 |
la=Numeric.zeros((100,100)) |
|
705 |
la=la-1 |
|
706 |
||
707 |
#Creates a short array, filled with 0xFFFF
|
|
708 |
sa=Numeric.zeros((100,100)) |
|
709 |
sa=sa+0xFFFF |
|
710 |
sa=sa.astype("s") |
|
711 |
||
712 |
#Writes long array, initializing file (append=0)
|
|
713 |
exe.WriteImage({},la,0,"") |
|
714 |
||
715 |
#Appends short array with new header items
|
|
716 |
exe.WriteImage({'Name': 'Alexandre', 'Date': '16/07/2001'},sa) |
|
717 |
||
718 |
#Appends short array, in Edf type unsigned
|
|
719 |
exe.WriteImage({},sa,DataType="UnsignedShort") |
|
720 |
||
721 |
#Appends short array, in Edf type unsigned
|
|
722 |
exe.WriteImage({},sa,DataType="UnsignedLong") |
|
723 |
||
724 |
#Appends long array as a double, considering unsigned
|
|
725 |
exe.WriteImage({},la,DataType="DoubleValue",WriteAsUnsigened=1) |
|
726 |
||
727 |
#Gets unsigned short data, storing in an signed long
|
|
728 |
ushort=exe.GetData(2,"SignedLong") |
|
729 |
||
730 |
#Makes an operation
|
|
731 |
ushort=ushort-0x10 |
|
732 |
||
733 |
#Saves Result as signed long
|
|
734 |
exe.WriteImage({},ushort) |
|
735 |
||
736 |
#Saves in the original format (unsigned short)
|
|
737 |
OldHeader=exe.GetStaticHeader(2) |
|
738 |
exe.WriteImage({},ushort,1,OldHeader["DataType"] ) |
|
739 |