-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsis2_lib.py
335 lines (282 loc) · 11.3 KB
/
sis2_lib.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
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright (C) 2016 Simone Serafini et al.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import numpy as np
import time
import datetime
import os
from io import BytesIO
def thalammerize(image):
image += 1
image = image * (2**16)/10
image = np.clip(image, 0, 2**16-1)
return image
def readsis(filename, verbose=False):
''' Read sis files, both old version and SisV2
Parameters
----------
filename : stringa con il nome o il path relativo del file.
Returns im1, im2, image, rawdata, stringa, block
-------
im1 : ndarray 2D
first half of the image [righe 0 : height/2-1].
im2 : ndarray 2D
second half of the image [righe height/2 : height-1].
image : ndarray 2D
whole image
rawdata : ndarray 1D
raw data read from file
stringa : string
comment and datestamp of the image
block : tuple (Bheight,Bwidth)
Bheight : int
y dimension of the sub-block
Bwidth : int
x dimension of the sub-block
Notes
-----
NB all the outputs are slices of the raw data: any modifications of them will be reflected also in the linked rawdata elements
'''
f = open(filename, 'rb') # open in reading and binary mode
header = f.read(512) # read the fixed size header: 512 bytes
if header[0] == 48: # 48 is ASCII code for '0': all older sis start with 0
sisVersion = ' sis1'
datestamp = ' we do not know'
commitProg = ' nothing'
comment = ' nothing'
elif header[0:5] == b'SisV2': # SisV2 print header
sisVersion = str(header[0:5])
datestamp = str(header[18:37])
commitProg = str(header[40:48])
comment = str(header[48:])
else:
print('What fuck are you opening?')
return True
if verbose:
print("You are opening the " + sisVersion[2:-1] + " file: " + filename)
f.close()
# Sometimes it gives error if the file is opened a sigle time
f = open(filename, 'rb') # open in reading and binary mode
rawdata = np.fromfile(f,np.uint16).astype(np.int)
# 'H' = uint16
# types are listed in np.typeDict
# put in an array the data formatted uint16 and casted to int
''' NB fundamental to cast to int:
unsigned short gives overflow '''
f.close()
# Dimension of the whole image
width=rawdata[6] # N cols
height=rawdata[5] # N rows
# Dimension of the sub-blocks
Bwidth=rawdata[8] # N subcols
Bheight=rawdata[7] # N subrows
# Length of comments
ls = rawdata[19]
# Reading the images
image = rawdata[-width*height:]
image.resize(height,width)
# defines the two images in the sis
im0 = image[:height//2, :]
im1 = image[height//2:, :]
if header[0] == 48:
stringa = sisVersion[1:-1] + ' ' + datestamp[2:-1] + ' ' + comment[2:]
elif header[0:5] == b'SisV2':
stringa = sisVersion[1:-1] + ' ' + datestamp[2:-1] + ' ' + comment[2:ls+2]
block = (Bheight,Bwidth)
if verbose:
print("It says: " + comment[1:ls+2] + "...")
print("...and was created on " + datestamp[1:])
print("The commit of the program is: " + commitProg[2:])
return im0, im1, image, rawdata, commitProg, stringa , block
def readsis_quiet(filename, verbose=False):
''' Read sis files, both old version and SisV2
Parameters
----------
filename : stringa con il nome o il path relativo del file.
Returns im1, im2, image, rawdata, stringa, block
-------
im1 : ndarray 2D
first half of the image [righe 0 : height/2-1].
im2 : ndarray 2D
second half of the image [righe height/2 : height-1].
image : ndarray 2D
whole image
rawdata : ndarray 1D
raw data read from file
stringa : string
comment and datestamp of the image
block : tuple (Bheight,Bwidth)
Bheight : int
y dimension of the sub-block
Bwidth : int
x dimension of the sub-block
Notes
-----
NB all the outputs are slices of the raw data: any modifications of them will be reflected also in the linked rawdata elements
'''
f = open(filename, 'rb') # open in reading and binary mode
header = f.read(512) # read the fixed size header: 512 bytes
if verbose:
print("You are opening the file: " + filename)
f.close()
# Sometimes it gives error if the file is opened a sigle time
f = open(filename, 'rb') # open in reading and binary mode
rawdata = np.fromfile(f,np.uint16).astype(np.int)
# 'H' = uint16
# types are listed in np.typeDict
# put in an array the data formatted uint16 and casted to int
''' NB fundamental to cast to int:
unsigned short gives overflow '''
f.close()
# Dimension of the whole image
width=rawdata[6] # N cols
height=rawdata[5] # N rows
# Dimension of the sub-blocks
Bwidth=rawdata[8] # N subcols
Bheight=rawdata[7] # N subrows
# Length of comments
ls = rawdata[19]
# Reading the images
image = rawdata[-width*height:]
image.resize(height,width)
# defines the two images in the sis
im0 = image[:height//2, :]
im1 = image[height//2:, :]
return im0, im1
def sis_writeOUT(filename, binData):
"""
Writing of .sis file using a placeholder tmp file, to avoid reading of
incomplete files when transfer speed is low
"""
with open(filename+".tmp", 'w+b') as fid:
fid.write(binData)
written = False
while not written:
try:
os.rename(filename+".tmp", filename)
written = True
except PermissionError as e:
print(e)
time.sleep(0.3)
# os.system("rm %s"%(filename+".tmp"))
def sis_write(filename, image, Bheight=0, Bwidth=0, commitProg='', stamp='', sisposition=None, thalammer=True):
"""
Low-level interaction with the sis file for writing it.
Writes the whole image, with the unused part filled with zeros.
Args:
image (np.array): the 2d-array that must be writed after conversion
to 16-bit unsigned-integers (must be already normalized)
filename (string): sis filename
Bheight (int): the y dimension of the eventual block
Bwidth (int): the x dimension of the eventual block
stamp (string): a string to describe who, why and what you want
"""
#keep the double-image convention for sis files, filling the unused
#with zeros
if sisposition == 'single':
image = image
elif sisposition == 0:
image = np.concatenate((image, np.zeros_like(image)))
elif sisposition == 1:
image = np.concatenate((np.zeros_like(image), image))
elif sisposition is None:
image = np.concatenate((image, image))
with BytesIO() as fid:
# Write here SisV2 + other 4 free bytes
head = 'SisV2' + '.' + '0'*4
fid.write(head.encode())
# This is OK
height, width = image.shape
size = np.array([height, width], dtype=np.uint16)
fid.write(bytes(size))
# fid.write(size.tobytes())
# size.tofile(fid)
# Here we put 2*2 more bytes with the sub-block dimension
Bsize = np.array([Bheight, Bwidth], dtype=np.uint16)
fid.write(bytes(Bsize))
# fid.write(Bsize.tobytes())
# Bsize.tofile(fid)
# Also a timestamp
ts = time.time()
phead = datetime.datetime.fromtimestamp(ts).strftime('%Y-%m-%d %H:%M:%S.')
fid.write(phead.encode())
# More: commitProg + descriptive stamp
ls = np.array([len(stamp)], dtype=np.uint16) # length of the stamp coded at the 38+39 byte
fid.write(bytes(ls))
# fid.write(ls.tobytes())
# ls.tofile(fid)
fid.write(commitProg[:8].encode())
fid.write(stamp.encode())
freeHead = '0'*(472-len(commitProg[:8]+stamp))
fid.write(freeHead.encode())
if thalammer:
image = thalammerize(image)
fid.write(bytes(image.astype(np.uint16)))
# fid.write(image.astype(np.uint16).tobytes())
sis_writeOUT(filename, fid.getvalue())
print('sis written to ' + filename)
def sis_write_off(self, OD, filename, Bheight, Bwidth, stamp):
"""
Low-level interaction with the sis file for writing it.
Writes the whole image, with the unused part filled with zeros.
Args:
image (np.array): the 2d-array that must be writed after conversion
to 16-bit unsigned-integers (must be already normalized)
filename (string): sis filename
Bheight (int): the y dimension of the eventual block
Bwidth (int): the x dimension of the eventual block
stamp (string): a string to describe who, why and what you want
"""
#norm = np.array((2,1))
norm = np.append(OD.min(), OD.max())
par = OD + abs(norm[0])
image = par * 6553.6 # Thalhammer's constant 2**16/10
#image = par.astype(np.uint16)
print(norm.astype(np.uint16))
#keep the double-image convention for sis files, filling the unused
#with zeros
if self == 0:
image = np.concatenate((image, np.zeros_like(image)))
elif self == 1:
image = np.concatenate((np.zeros_like(image), image))
with open(str(filename), 'w+b') as fid:
# Write here SisV2 + other 4 free bytes
head = 'SisV2' + '.' + '0'*4
fid.write(head.encode())
# This is OK
height, width = image.shape
size = np.array([height, width], dtype=np.uint16)
size.tofile(fid)
# Here we put 2*2 more bytes with the sub-block dimension
Bsize = np.array([Bheight, Bwidth], dtype=np.uint16)
Bsize.tofile(fid)
# Also a timestamp
ts = time.time()
phead = datetime.datetime.fromtimestamp(ts).strftime('%Y-%m-%d %H:%M:%S.')
fid.write(phead.encode())
# More: descriptive stamp
ls = np.array([len(stamp)], dtype=np.uint16) # length of the stamp coded at the 38+39 byte
ls.tofile(fid)
fid.write(stamp.encode())
freeHead = '0'*(472-len(stamp))
fid.write(freeHead.encode())
image.astype(np.uint16).tofile(fid)
# compatibility aliasing
read_sis = readsis
write_sis = sis_write
def read_sis0(*args, **kwargs):
S = read_sis(*args, **kwargs)
return S[0]