#!/usr/bin/env python
# This library works for Python3
"""
Reading spider format volumes into numpy arrays, and saving 3D numpy arrays into spider format volumes.
"""
# The spider format that was used to build the functions
# http://spider.wadsworth.org/spider_doc/spider/docs/image_doc.html
import sys
from struct import pack, unpack
import numpy as np
# From the spider format:
labels = {i - 1: v for i, v in [
(1, 'NZ'),
(2, 'NY'),
(3, 'IREC'),
(5, 'IFORM'),
(6, 'IMAMI'),
(7, 'FMAX'),
(8, 'FMIN'),
(9, 'AV'),
(10, 'SIG'),
(12, 'NX'),
(13, 'LABREC'),
(14, 'IANGLE'),
(15, 'PHI'),
(16, 'THETA'),
(17, 'GAMMA'),
(18, 'XOFF'),
(19, 'YOFF'),
(20, 'ZOFF'),
(21, 'SCALE'),
(22, 'LABBYT'),
(23, 'LENBYT'),
(24, 'ISTACK/MAXINDX'),
(26, 'MAXIM'),
(27, 'IMGNUM'),
(28, 'LASTINDX'),
(31, 'KANGLE'),
(32, 'PHI1'),
(33, 'THETA1'),
(34, 'PSI1'),
(35, 'PHI2'),
(36, 'THETA2'),
(37, 'PSI2'),
(38, 'PIXSIZ'),
(39, 'EV'),
(40, 'PROJ'),
(41, 'MIC'),
(42, 'NUM'),
(43, 'GLONUM'),
(101, 'PSI3'),
(102, 'THETA3'),
(103, 'PHI3'),
(104, 'LANGLE')]}
# Inverse.
locations = {v: k for k, v in labels.items()}
[docs]def open_volume(filename, endianness='ieee-le'):
"""Read a volume in spider format and return a numpy array."""
f = open(filename, encoding="latin-1")
e = {'ieee-le': '<', 'ieee-be': '>'}[endianness]
fields = unpack('%s13f' % e, bytes(f.read(4 * 13), encoding="latin-1"))
nz, ny, nx, labrec = [int(fields[i]) for i in [0, 1, 11, 12]]
f.seek(4 * nx * labrec) # go to end of header
# print(np.fromfile(f, dtype='%sf4' % e).size)
return np.fromfile(f, dtype='%sf4' % e).reshape((nx, ny, nz))
[docs]def open_image(filename, n=0, endianness='ieee-le'):
"""Read an image from a file in spider format and return a numpy array."""
f = open(filename, encoding="latin-1")
e = {'ieee-le': '<', 'ieee-be': '>'}[endianness]
fields = unpack('%s256f' % e, bytes(f.read(4 * 256), encoding="latin-1"))
nz, ny, nx, labrec = [int(fields[i]) for i in [0, 1, 11, 12]]
size = nx * labrec
if size != 256:
f.seek(4 * size)
f.seek(4 * n * (size + nx * ny * nz), 1)
return np.fromfile(f, dtype='%sf4' % e, count=nx * ny).reshape((nx, ny))
[docs]def save_volume(vol, filename):
"""Save volume vol into a file, with the spider format."""
nx, ny, nz = vol.shape
fields = [0.0] * nx
values = {
'NZ': nz, 'NY': ny,
'IREC': 3, # number of records (including header records)
'IFORM': 3, # 3D volume
'FMAX': vol.max(), 'FMIN': vol.min(),
'AV': vol.mean(), 'SIG': vol.std(),
'NX': nx,
'LABREC': 1, # number of records in file header (label)
'SCALE': 1,
'LABBYT': 4 * nx, # number of bytes in header
'LENBYT': 4 * nx, # record length in bytes (only 1 in our header)
}
for label, value in values.items():
fields[locations[label]] = float(value)
header = pack('%df' % nx, *fields)
with open(filename, 'wb') as f:
f.write(header)
vol.tofile(f)