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
|
# coding: utf-8
#
# Project: X-ray image reader
# https://github.com/silx-kit/fabio
#
#
# Copyright (C) European Synchrotron Radiation Facility, Grenoble, France
#
# Principal author: Jérôme Kieffer (Jerome.Kieffer@ESRF.eu)
#
# 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/>.
#
"""
Author: Andy Hammersley, ESRF
Translation into python/fabio: Jon Wright, ESRF.
Writer: Jérôme Kieffer
"""
# Get ready for python3:
from __future__ import with_statement, print_function
__authors__ = ["Jon Wright", "Jérôme Kieffer"]
__contact__ = "Jerome.Kieffer@esrf.fr"
__license__ = "GPLv3+"
__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
__version__ = "06/01/2015"
import numpy
import sys
import struct
from .fabioimage import FabioImage
if sys.version < '3':
bytes = str
class Fit2dMaskImage(FabioImage):
""" Read and try to write Andy Hammersley's mask format """
def _readheader(self, infile):
"""
Read in a header from an already open file
"""
# 1024 bytes gives 256x32 bit integers
header = infile.read(1024)
for i, j in [ (b"M", 0),
(b"A", 4),
(b"S", 8),
(b"K", 12) ]:
if header[j] != i[0]:
raise Exception("Not a fit2d mask file")
fit2dhdr = numpy.fromstring(header, numpy.int32)
# Enforce little endian
if not numpy.little_endian:
fit2dhdr.byteswap(True)
self._dim1 = fit2dhdr[4] # 1 less than Andy's fortran
self._dim2 = fit2dhdr[5]
def read(self, fname, frame=None):
"""
Read in header into self.header and
the data into self.data
"""
fin = self._open(fname)
self._readheader(fin)
# Compute image size
self.bytecode = numpy.uint8
self.bpp = numpy.dtype(self.bytecode).itemsize
# integer division
num_ints = (self._dim1 + 31) // 32
total = self._dim2 * num_ints * 4
data = fin.read(total)
assert len(data) == total
fin.close()
# Now to unpack it
data = numpy.fromstring(data, numpy.uint8)
if not numpy.little_endian:
data.byteswap(True)
data = numpy.reshape(data, (self._dim2, num_ints * 4))
result = numpy.zeros((self._dim2, num_ints * 4 * 8), numpy.uint8)
# Unpack using bitwise comparisons to 2**n
bits = numpy.ones((1), numpy.uint8)
for i in range(8):
temp = numpy.bitwise_and(bits, data)
result[:, i::8] = temp.astype(numpy.uint8)
bits = bits * 2
# Extra rows needed for packing odd dimensions
spares = num_ints * 4 * 8 - self._dim1
if spares == 0:
data = numpy.where(result == 0, 0, 1)
else:
data = numpy.where(result[:, :-spares] == 0, 0, 1)
# Transpose appears to be needed to match edf reader (scary??)
# self.data = numpy.transpose(self.data)
self.data = numpy.ascontiguousarray(data, dtype=numpy.uint8).reshape(self._dim2, self._dim1)
self.pilimage = None
return self
def write(self, fname):
"""
Try to write a file
"""
header = bytearray(b"\x00" * 1024)
header[0] = 77 # M
header[4] = 65 # A
header[8] = 83 # S
header[12] = 75 # K
header[24] = 1 # 1
header[16:20] = struct.pack("<I", self.dim1)
header[20:24] = struct.pack("<I", self.dim2)
compact_array = numpy.zeros((self.dim2, ((self.dim1 + 31) // 32) * 4), dtype=numpy.uint8)
large_array = numpy.zeros((self.dim2, ((self.dim1 + 31) // 32) * 32), dtype=numpy.uint8)
large_array[:self.dim2, :self.dim1] = (self.data != 0)
for i in range(8):
order = (1 << i)
compact_array += large_array[:, i::8] * order
with self._open(fname, mode="wb") as outfile:
outfile.write(bytes(header))
outfile.write(compact_array.tostring())
@staticmethod
def check_data(data=None):
if data is None:
return None
else:
return (data != 0).astype(numpy.uint8)
fit2dmaskimage = Fit2dMaskImage
|