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

Source Code for Module fabio.OXDimage

  1  #!/usr/bin/env python
 
  2  
 
  3  """
 
  4  Reads Oxford Diffraction Sapphire 3 images
 
  5  
 
  6  Authors: Henning O. Sorensen & Erik Knudsen
 
  7           Center for Fundamental Research: Metal Structures in Four Dimensions
 
  8           Risoe National Laboratory
 
  9           Frederiksborgvej 399
 
 10           DK-4000 Roskilde
 
 11           email:erik.knudsen@risoe.dk
 
 12  
 
 13          + Jon Wright, ESRF
 
 14  
 
 15  """ 
 16  
 
 17  import numpy as N, logging 
 18  from fabioimage import fabioimage 
 19  
 
 20  DETECTOR_TYPES = {0: 'Sapphire/KM4CCD (1x1: 0.06mm, 2x2: 0.12mm)',
 
 21  1: 'Sapphire2-Kodak (1x1: 0.06mm, 2x2: 0.12mm)',
 
 22  2: 'Sapphire3-Kodak (1x1: 0.03mm, 2x2: 0.06mm, 4x4: 0.12mm)',
 
 23  3: 'Onyx-Kodak (1x1: 0.06mm, 2x2: 0.12mm, 4x4: 0.24mm)',
 
 24  4: 'Unknown Oxford diffraction detector'} 
 25  
 
 26  
 
27 -class OXDimage(fabioimage):
28 - def _readheader(self, infile):
29 30 infile.seek(0) 31 32 # Ascii header part 512 byes long 33 self.header['Header Version'] = infile.readline()[:-2] 34 block = infile.readline() 35 self.header['Compression'] = block[12:15] 36 block = infile.readline() 37 self.header['NX'] = int(block[3:7]) 38 self.header['NY'] = int(block[11:15]) 39 self.header['OI'] = int(block[19:26]) 40 self.header['OL'] = int(block[30:37]) 41 block = infile.readline() 42 self.header['Header Size In Bytes'] = int(block[8:15]) 43 #self.header['NG'] = int(block[19:26]) 44 #self.header['NK'] = int(block[30:37]) 45 #self.header['NS'] = int(block[41:48]) 46 #self.header['NH'] = int(block[52:59]) 47 block = infile.readline() 48 #self.header['NSUPPLEMENT'] = int(block[12:19]) 49 block = infile.readline() 50 self.header['Time'] = block[5:29] 51 52 # Skip to general section (NG) 512 byes long <<<<<<" 53 infile.seek(256) 54 block = infile.read(512) 55 self.header['Binning in x'] = N.fromstring(block[0:2], N.uint16)[0] 56 self.header['Binning in y'] = N.fromstring(block[2:4], N.uint16)[0] 57 self.header['Detector size x'] = N.fromstring(block[22:24], N.uint16)[0] 58 self.header['Detector size y'] = N.fromstring(block[24:26], N.uint16)[0] 59 self.header['Pixels in x'] = N.fromstring(block[26:28], N.uint16)[0] 60 self.header['Pixels in y'] = N.fromstring(block[28:30], N.uint16)[0] 61 self.header['No of pixels'] = N.fromstring(block[36:40], N.uint32)[0] 62 63 # Speciel section (NS) 768 bytes long 64 block = infile.read(768) 65 self.header['Gain'] = N.fromstring(block[56:64], N.float)[0] 66 self.header['Overflows flag'] = N.fromstring(block[464:466], N.int16)[0] 67 self.header['Overflow after remeasure flag'] = N.fromstring(block[466:468], N.int16)[0] 68 self.header['Overflow threshold'] = N.fromstring(block[472:476], N.int32)[0] 69 self.header['Exposure time in sec'] = N.fromstring(block[480:488], N.float)[0] 70 self.header['Overflow time in sec'] = N.fromstring(block[488:496], N.float)[0] 71 self.header['Monitor counts of raw image 1'] = N.fromstring(block[528:532], N.int32)[0] 72 self.header['Monitor counts of raw image 2'] = N.fromstring(block[532:536], N.int32)[0] 73 self.header['Monitor counts of overflow raw image 1'] = N.fromstring(block[536:540], N.int32)[0] 74 self.header['Monitor counts of overflow raw image 2'] = N.fromstring(block[540:544], N.int32)[0] 75 self.header['Unwarping'] = N.fromstring(block[544:548], N.int32)[0] 76 self.header['Detector type'] = DETECTOR_TYPES[N.fromstring(block[548:552], N.int32)[0]] 77 self.header['Real pixel size x (mm)'] = N.fromstring(block[568:576], N.float)[0] 78 self.header['Real pixel size y (mm)'] = N.fromstring(block[576:584], N.float)[0] 79 80 # KM4 goniometer section (NK) 1024 bytes long 81 block = infile.read(1024) 82 # Spatial correction file 83 self.header['Spatial correction file'] = block[26:272] 84 self.header['Spatial correction file date'] = block[0:26] 85 # Angles are in steps due to stepper motors - conversion factor RAD 86 # angle[0] = omega, angle[1] = theta, angle[2] = kappa, angle[3] = phi, 87 start_angles_step = N.fromstring(block[284:304], N.int32) 88 end_angles_step = N.fromstring(block[324:344], N.int32) 89 step2rad = N.fromstring(block[368:408], N.float) 90 # calc angles 91 start_angles_deg = start_angles_step * step2rad * 180.0 / N.pi 92 93 end_angles_deg = end_angles_step * step2rad * 180.0 / N.pi 94 self.header['Omega start in deg'] = start_angles_deg[0] 95 self.header['Theta start in deg'] = start_angles_deg[1] 96 self.header['Kappa start in deg'] = start_angles_deg[2] 97 self.header['Phi start in deg'] = start_angles_deg[3] 98 self.header['Omega end in deg'] = end_angles_deg[0] 99 self.header['Theta end in deg'] = end_angles_deg[1] 100 self.header['Kappa end in deg'] = end_angles_deg[2] 101 self.header['Phi end in deg'] = end_angles_deg[3] 102 103 zero_correction_soft_step = N.fromstring(block[512:532], N.int32) 104 zero_correction_soft_deg = zero_correction_soft_step * step2rad * 180.0 / N.pi 105 self.header['Omega zero corr. in deg'] = zero_correction_soft_deg[0] 106 self.header['Theta zero corr. in deg'] = zero_correction_soft_deg[1] 107 self.header['Kappa zero corr. in deg'] = zero_correction_soft_deg[2] 108 self.header['Phi zero corr. in deg'] = zero_correction_soft_deg[3] 109 # Beam rotation about e2,e3 110 self.header['Beam rot in deg (e2)'] = N.fromstring(block[552:560], N.float)[0] 111 self.header['Beam rot in deg (e3)'] = N.fromstring(block[560:568], N.float)[0] 112 # Wavelenghts alpha1, alpha2, beta 113 self.header['Wavelength alpha1'] = N.fromstring(block[568:576], N.float)[0] 114 self.header['Wavelength alpha2'] = N.fromstring(block[576:584], N.float)[0] 115 self.header['Wavelength alpha'] = N.fromstring(block[584:592], N.float)[0] 116 self.header['Wavelength beta'] = N.fromstring(block[592:600], N.float)[0] 117 118 # Detector tilts around e1,e2,e3 in deg 119 self.header['Detector tilt e1 in deg'] = N.fromstring(block[640:648], N.float)[0] 120 self.header['Detector tilt e2 in deg'] = N.fromstring(block[648:656], N.float)[0] 121 self.header['Detector tilt e3 in deg'] = N.fromstring(block[656:664], N.float)[0] 122 123 124 # Beam center 125 self.header['Beam center x'] = N.fromstring(block[664:672], N.float)[0] 126 self.header['Beam center y'] = N.fromstring(block[672:680], N.float)[0] 127 # Angle (alpha) between kappa rotation axis and e3 (ideally 50 deg) 128 self.header['Alpha angle in deg'] = N.fromstring(block[672:680], N.float)[0] 129 # Angle (beta) between phi rotation axis and e3 (ideally 0 deg) 130 self.header['Beta angle in deg'] = N.fromstring(block[672:680], N.float)[0] 131 132 # Detector distance 133 self.header['Distance in mm'] = N.fromstring(block[712:720], N.float)[0] 134 # Statistics section (NS) 512 bytes long 135 block = infile.read(512) 136 self.header['Stat: Min '] = N.fromstring(block[0:4], N.int32)[0] 137 self.header['Stat: Max '] = N.fromstring(block[4:8], N.int32)[0] 138 self.header['Stat: Average '] = N.fromstring(block[24:32], N.float)[0] 139 self.header['Stat: Stddev '] = N.sqrt(N.fromstring(block[32:40], N.float)[0]) 140 self.header['Stat: Skewness '] = N.fromstring(block[40:48], N.float)[0] 141 142 # History section (NH) 2048 bytes long - only reads first 256 bytes 143 block = infile.read(256) 144 self.header['Flood field image'] = block[99:126]
145
146 - def read(self, fname):
147 """ 148 Read in header into self.header and 149 the data into self.data 150 """ 151 self.header = {} 152 self.resetvals() 153 infile = self._open(fname) 154 self._readheader(infile) 155 156 infile.seek(self.header['Header Size In Bytes']) 157 158 # Compute image size 159 try: 160 self.dim1 = int(self.header['NX']) 161 self.dim2 = int(self.header['NY']) 162 except: 163 raise Exception("Oxford file", str(fname) + \ 164 "is corrupt, cannot read it") 165 # 166 if self.header['Compression'] == 'TY1': 167 #Compressed with the KM4CCD compression 168 bytecode = N.uint8 169 self.bpp = len(N.array(0, bytecode).tostring()) 170 ReadBytes = self.dim1 * self.dim2 * self.bpp 171 diffs = infile.read(ReadBytes) 172 diffs = N.fromstring(diffs, bytecode) 173 offset = -127 174 diffs = diffs.astype(N.int32) + offset 175 176 if self.header['OI'] > 0: 177 bytecode = N.int16 178 self.bpp = len(N.array(0, bytecode).tostring()) 179 ReadBytes = self.header['OI'] * self.bpp 180 over_short = infile.read(ReadBytes) 181 over_short = N.fromstring(over_short, bytecode) 182 if self.header['OL'] > 0: 183 bytecode = N.int32 184 self.bpp = len(N.array(0, bytecode).tostring()) 185 ReadBytes = self.header['OL'] * self.bpp 186 over_long = infile.read(ReadBytes) 187 over_long = N.fromstring(over_long, bytecode) 188 block = diffs.copy() 189 old_val = 0 190 js = 0 191 jl = 0 192 print 'OVER_SHORT: ', block.dtype 193 194 for i in range(self.dim1 * self.dim2): 195 if diffs[i] < 127: 196 #print 'DIFF < 127:' , diffs[i] 197 d = diffs[i] 198 elif diffs[i] == 127: 199 #print 'DIFF == 127:' , diffs[i] 200 d = over_short[js] 201 #print 'd ' , d 202 js = js + 1 203 elif diffs[i] == 128: 204 #print 'DIFF == 128:' , diffs[i] 205 d = over_long[jl] 206 jl = jl + 1 207 old_val = old_val + d 208 block[i] = old_val 209 else: 210 bytecode = N.int32 211 self.bpp = len(N.array(0, bytecode).tostring()) 212 ReadBytes = self.dim1 * self.dim2 * self.bpp 213 block = N.fromstring(infile.read(ReadBytes), bytecode) 214 215 print 'OVER_SHORT2: ', block.dtype 216 print (block < 0).sum() 217 # 218 infile.close() 219 print "BYTECODE", bytecode 220 try: 221 # avoid int64 for x86_64 with astype 222 bytecode = N.int32 223 224 self.data = N.reshape(block.astype(bytecode), [self.dim2, self.dim1]) 225 #self.data = N.reshape(block,[self.dim2, self.dim1]) 226 except: 227 print len(block), self.dim2, self.dim1 228 raise IOError, \ 229 'Size spec in OD-header does not match size of image data field' 230 231 self.bytecode = self.data.dtype.type 232 self.pilimage = None 233 return self
234