File: fit2dmaskimage.py

package info (click to toggle)
python-fabio 0.4.0%2Bdfsg-2
  • links: PTS, VCS
  • area: main
  • in suites: stretch
  • size: 4,788 kB
  • ctags: 6,209
  • sloc: python: 12,748; ansic: 1,091; makefile: 129
file content (143 lines) | stat: -rw-r--r-- 4,893 bytes parent folder | download | duplicates (2)
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