2
# The Python Imaging Library.
4
# SPIDER image file handling
7
# 2004-08-02 Created BB
8
# 2006-03-02 added save method
9
# 2006-03-13 added support for stack images
11
# Copyright (c) 2004 by Health Research Inc. (HRI) RENSSELAER, NY 12144.
12
# Copyright (c) 2004 by William Baxter.
13
# Copyright (c) 2004 by Secret Labs AB.
14
# Copyright (c) 2004 by Fredrik Lundh.
18
# Image plugin for the Spider image format. This format is is used
19
# by the SPIDER software, in processing image data from electron
20
# microscopy and tomography.
24
# SpiderImagePlugin.py
26
# The Spider image format is used by SPIDER software, in processing
27
# image data from electron microscopy and tomography.
30
# http://www.wadsworth.org/spider_doc/spider/docs/spider.html
32
# Details about the Spider image format:
33
# http://www.wadsworth.org/spider_doc/spider/docs/image_doc.html
36
import Image, ImageFile
37
import os, string, struct, sys
47
iforms = [1,3,-11,-12,-21,-22]
49
# There is no magic number to identify Spider files, so just check a
50
# series of header locations to see if they have reasonable values.
51
# Returns no.of bytes in the header, if it is a valid Spider header,
54
def isSpiderHeader(t):
55
h = (99,) + t # add 1 value so can use spider header index start=1
56
# header values 1,2,5,12,13,22,23 should be integers
57
for i in [1,2,5,12,13,22,23]:
58
if not isInt(h[i]): return 0
61
if not iform in iforms: return 0
62
# check other header values
63
labrec = int(h[13]) # no. records in file header
64
labbyt = int(h[22]) # total no. of bytes in header
65
lenbyt = int(h[23]) # record length in bytes
66
#print "labrec = %d, labbyt = %d, lenbyt = %d" % (labrec,labbyt,lenbyt)
67
if labbyt != (labrec * lenbyt): return 0
68
# looks like a valid header
71
def isSpiderImage(filename):
72
fp = open(filename,'rb')
73
f = fp.read(92) # read 23 * 4 bytes
76
t = struct.unpack('>23f',f) # try big-endian first
77
hdrlen = isSpiderHeader(t)
80
t = struct.unpack('<23f',f) # little-endian
81
hdrlen = isSpiderHeader(t)
85
class SpiderImageFile(ImageFile.ImageFile):
88
format_description = "Spider 2D image"
92
n = 27 * 4 # read 27 float values
97
t = struct.unpack('>27f',f) # try big-endian first
98
hdrlen = isSpiderHeader(t)
101
t = struct.unpack('<27f',f) # little-endian
102
hdrlen = isSpiderHeader(t)
104
raise SyntaxError, "not a valid Spider file"
106
raise SyntaxError, "not a valid Spider file"
108
h = (99,) + t # add 1 value : spider header index starts at 1
111
raise SyntaxError, "not a Spider 2D image"
113
self.size = int(h[12]), int(h[2]) # size in pixels (width, height)
114
self.istack = int(h[24])
115
self.imgnumber = int(h[27])
117
if self.istack == 0 and self.imgnumber == 0:
118
# stk=0, img=0: a regular 2D image
121
elif self.istack > 0 and self.imgnumber == 0:
122
# stk>0, img=0: Opening the stack for the first time
123
self.imgbytes = int(h[12]) * int(h[2]) * 4
125
self.nimages = int(h[26])
126
# Point to the first image in the stack
129
elif self.istack == 0 and self.imgnumber > 0:
130
# stk=0, img>0: an image within the stack
131
offset = hdrlen + self.stkoffset
132
self.istack = 2 # So Image knows it's still a stack
134
raise SyntaxError, "inconsistent stack header values"
137
self.rawmode = "F;32BF"
139
self.rawmode = "F;32F"
142
self.tile = [("raw", (0, 0) + self.size, offset,
143
(self.rawmode, 0, 1))]
144
self.__fp = self.fp # FIXME: hack
146
# 1st image index is zero (although SPIDER imgnumber starts at 1)
148
if self.imgnumber < 1:
151
return self.imgnumber - 1
153
def seek(self, frame):
156
if frame >= self.nimages:
157
raise EOFError, "attempt to seek past end of file"
158
self.stkoffset = self.hdrlen + frame * (self.hdrlen + self.imgbytes)
160
self.fp.seek(self.stkoffset)
163
# returns a byte image after rescaling to 0..255
164
def convert2byte(self, depth=255):
165
(min, max) = self.getextrema()
168
m = depth / (max-min)
170
return self.point(lambda i, m=m, b=b: i * m + b).convert("L")
172
# returns a ImageTk.PhotoImage object, after rescaling to 0..255
173
def tkPhotoImage(self):
175
return ImageTk.PhotoImage(self.convert2byte(), palette=256)
177
# --------------------------------------------------------------------
180
# given a list of filenames, return a list of images
181
def loadImageSeries(filelist=None):
182
" create a list of Image.images for use in montage "
183
if filelist == None or len(filelist) < 1:
188
if not os.path.exists(img):
189
print "unable to find %s" % img
192
im = Image.open(img).convert2byte()
194
if not isSpiderImage(img):
195
print img + " is not a Spider image file"
197
im.info['filename'] = img
201
# --------------------------------------------------------------------
202
# For saving images in Spider format
204
def makeSpiderHeader(im):
206
lenbyt = nsam * 4 # There are labrec records in the header
207
labrec = 1024 / lenbyt
208
if 1024%lenbyt != 0: labrec += 1
209
labbyt = labrec * lenbyt
212
for i in range(nvalues):
218
# NB these are Fortran indices
219
hdr[1] = 1.0 # nslice (=1 for an image)
220
hdr[2] = float(nrow) # number of rows per slice
221
hdr[5] = 1.0 # iform for 2D image
222
hdr[12] = float(nsam) # number of pixels per line
223
hdr[13] = float(labrec) # number of records in file header
224
hdr[22] = float(labbyt) # total number of bytes in header
225
hdr[23] = float(lenbyt) # record length in bytes
227
# adjust for Fortran indexing
230
# pack binary data into a string
233
hdrstr.append(struct.pack('f',v))
236
def _save(im, fp, filename):
237
if im.mode[0] != "F":
240
hdr = makeSpiderHeader(im)
242
raise IOError, "Error creating Spider header"
244
# write the SPIDER header
246
fp = open(filename, 'wb')
248
raise IOError, "Unable to open %s for writing" % filename
251
rawmode = "F;32NF" #32-bit native floating point
252
ImageFile._save(im, fp, [("raw", (0,0)+im.size, 0, (rawmode,0,1))])
256
def _save_spider(im, fp, filename):
257
# get the filename extension and register it with Image
258
fn, ext = os.path.splitext(filename)
259
Image.register_extension("SPIDER", ext)
260
_save(im, fp, filename)
262
# --------------------------------------------------------------------
264
Image.register_open("SPIDER", SpiderImageFile)
265
Image.register_save("SPIDER", _save_spider)
267
if __name__ == "__main__":
270
print "Syntax: python SpiderImagePlugin.py Spiderimage [outfile]"
273
filename = sys.argv[1]
274
if not isSpiderImage(filename):
275
print "input image must be in Spider format"
279
if len(sys.argv[1:]) > 1:
280
outfile = sys.argv[2]
282
im = Image.open(filename)
283
print "image: " + str(im)
284
print "format: " + str(im.format)
285
print "size: " + str(im.size)
286
print "mode: " + str(im.mode)
288
print im.getextrema()
291
# perform some image operation
292
im = im.transpose(Image.FLIP_LEFT_RIGHT)
293
print "saving a flipped version of %s as %s " % (os.path.basename(filename), outfile)
294
im.save(outfile, "SPIDER")