fabio.brukerimage

Package fabio :: Module brukerimage |
[hide private]
[frames] | no frames]

# Source Code for Module fabio.brukerimage

      1  #!/usr/bin/env python
      2  """
      3
      4  Authors: Henning O. Sorensen & Erik Knudsen
      5           Center for Fundamental Research: Metal Structures in Four Dimensions
      6           Risoe National Laboratory
      7           Frederiksborgvej 399
      8           DK-4000 Roskilde
      9           email:erik.knudsen@risoe.dk
     10
     11  Based on: openbruker,readbruker, readbrukerheader functions in the opendata
     12           module of ImageD11 written by Jon Wright, ESRF, Grenoble, France
     13
     14  """
     15
     16  import numpy, logging
     17  logger = logging.getLogger("brukerimage")
     18  from fabioimage import fabioimage
     19  from readbytestream import readbytestream
     20
     21
     22 -class brukerimage(fabioimage):
     23      """
     24      Read and eventually write ID11 bruker (eg smart6500) images
     25      """
     26
     27      # needed if you feel like writing - see ImageD11/scripts/edf2bruker.py
     28
     29      __headerstring__ = ""
     30
     31
     32 -    def _readheader(self, infile):
     33          """
     34          the bruker format uses 80 char lines in key : value format
     35          In the fisrt 512*5 bytes of the header there should be a
     36          HDRBLKS key, whose value denotes how many 512 byte blocks
     37          are in the total header. The header is always n*5*512 bytes,
     38          otherwise it wont contain whole key: value pairs
     39          """
     40          lump = infile.read(512 * 5)
     41          self.__headerstring__ += lump
     42          i = 80
     43          self.header = {}
     44          while i < 512 * 5:
     45              if lump[i - 80: i].find(":") > 0:
     46                  key, val = lump[i - 80: i].split(":", 1)
     47                  key = key.strip()         # remove the whitespace (why?)
     48                  val = val.strip()
     49                  if self.header.has_key(key):
     50                      # append lines if key already there
     51                      self.header[key] = self.header[key] + '\n' + val
     52                  else:
     53                      self.header[key] = val
     54                      self.header_keys.append(key)
     55              i = i + 80                  # next 80 characters
     56          # we must have read this in the first 512 bytes.
     57          nhdrblks = int(self.header['HDRBLKS'])
     58          # Now read in the rest of the header blocks, appending
     59          rest = infile.read(512 * (nhdrblks - 5))
     60          self.__headerstring__ += rest
     61          lump = lump[i - 80: 512] + rest
     62          i = 80
     63          j = 512 * nhdrblks
     64          while i < j :
     65              if lump[i - 80: i].find(":") > 0: # as for first 512 bytes of header
     66                  key, val = lump[i - 80: i].split(":", 1)
     67                  key = key.strip()
     68                  val = val.strip()
     69                  if self.header.has_key(key):
     70                      self.header[key] = self.header[key] + '\n' + val
     71                  else:
     72                      self.header[key] = val
     73                      self.header_keys.append(key)
     74              i = i + 80
     75          # make a (new) header item called "datastart"
     76          self.header['datastart'] = infile.tell()
     77          #set the image dimensions
     78          self.dim1 = int(self.header['NROWS'])
     79          self.dim2 = int(self.header['NCOLS'])
     80
     81 -    def read(self, fname, frame=None):
     82          """
     83          Read in and unpack the pixels (including overflow table
     84          """
     85          infile = self._open(fname, "rb")
     86          try:
     87              self._readheader(infile)
     88          except:
     89              raise
     90
     91          rows = self.dim1
     92          cols = self.dim2
     93
     94          try:
     95              # you had to read the Bruker docs to know this!
     96              npixelb = int(self.header['NPIXELB'])
     97          except:
     98              errmsg = "length " + str(len(self.header['NPIXELB'])) + "\n"
     99              for byt in self.header['NPIXELB']:
    100                  errmsg += "char: " + str(byt) + " " + str(ord(byt)) + "\n"
    101              logger.warning(errmsg)
    102              raise
    103
    104          self.data = readbytestream(infile, infile.tell(),
    105                                     rows, cols, npixelb,
    106                                     datatype="int",
    107                                     signed='n',
    108                                     swap='n')
    109
    110          #handle overflows
    111          nov = int(self.header['NOVERFL'])
    112          if nov > 0:   # Read in the overflows
    113              # need at least int32 sized data I guess - can reach 2^21
    114              self.data = self.data.astype(numpy.uint32)
    115              # 16 character overflows:
    116              #      9 characters of intensity
    117              #      7 character position
    118              for i in range(nov):
    119                  ovfl = infile.read(16)
    120                  intensity = int(ovfl[0: 9])
    121                  position = int(ovfl[9: 16])
    122                  # relies on python style modulo being always +
    123                  row = position % rows
    124                  # relies on truncation down
    125                  col = position / rows
    126                  #print "Overflow ", r, c, intensity, position,\
    127                  #    self.data[r,c],self.data[c,r]
    128                  self.data[col, row] = intensity
    129          infile.close()
    130
    131          self.resetvals()
    132          self.pilimage = None
    133          return self
    134
    135
    136 -    def write(self, fname):
    137          """
    138          Writes the image as EDF
    139
    140          FIXME:  this should call edfimage.write if that is wanted?
    141                  obj = edfimage(data = self.data, header = self.header)
    142                  obj.write(fname)
    143                  or maybe something like: edfimage.write(self, fname)
    144
    145          """
    146          logger.warning("***warning***: call to unifinished " + \
    147                  "brukerimage.write. This will write the file" + \
    148                              fname + "as an edf-file")
    149
    150
    151          outfile = self._open(fname, "wb")
    152          outfile.write('{\n')
    153          i = 4
    154          for k in self.header_keys:
    155              out = (("%s = %s;\n") % (k, self.header[k]))
    156              i = i + len(out)
    157              outfile.write(out)
    158          out = (4096 - i) * ' '
    159          outfile.write(out)
    160          outfile.write('}\n')
    161          # Assumes a short-circuiting if / or ...
    162          if not self.header.has_key("ByteOrder") or \
    163                 self.header["ByteOrder"] == "LowByteFirst":
    164              outfile.write(self.data.astype(numpy.uint16).tostring())
    165          else:
    166              outfile.write(self.data.byteswap().astype(
    167                      numpy.uint16).tostring())
    168          outfile.close()
    169
    170
    171
    172
    173 -def test():
    174      """ a testcase """
    175      import sys, time
    176      img = brukerimage()
    177      start = time.clock()
    178      for filename in sys.argv[1:]:
    179          img.read(filename)
    180          res = img.toPIL16()
    181          img.rebin(2, 2)
    182          print filename + (": max=%d, min=%d, mean=%.2e, stddev=%.2e") % (
    183              img.getmax(), img.getmin(), img.getmean(), img.getstddev())
    184          print 'integrated intensity (%d %d %d %d) =%.3f' % (
    185              10, 20, 20, 40, img.integrate_area((10, 20, 20, 40)))
    186      end = time.clock()
    187      print (end - start)
    188
    189
    190
    191  if __name__ == '__main__':
    192      test()
    193