source: trunk/imports/G2img_1TIF.py @ 4288

Last change on this file since 4288 was 4288, checked in by vondreele, 3 years ago

add import of Dectris Eiger 1M tif images

  • Property svn:eol-style set to native
  • Property svn:keywords set to Date Author Revision URL Id
File size: 16.3 KB
Line 
1# -*- coding: utf-8 -*-
2########### SVN repository information ###################
3# $Date: 2020-02-05 11:00:20 +0000 (Wed, 05 Feb 2020) $
4# $Author: vondreele $
5# $Revision: 4288 $
6# $URL: trunk/imports/G2img_1TIF.py $
7# $Id: G2img_1TIF.py 4288 2020-02-05 11:00:20Z vondreele $
8########### SVN repository information ###################
9'''
10*Module G2img_1TIF: Tagged-image File images*
11--------------------------------------------------
12
13Routine to read an image in Tagged-image file (TIF) format as well as a variety
14of slightly incorrect pseudo-TIF formats used at instruments around the world.
15Note that the name ``G2img_1TIF`` is used so that this file will
16sort to the top of the image formats and thus show up first in the menu.
17(It is the most common, alas).
18
19'''
20
21from __future__ import division, print_function
22import struct as st
23import GSASIIobj as G2obj
24import GSASIIpath
25import GSASIIfiles as G2fil
26import numpy as np
27import time
28DEBUG = False
29GSASIIpath.SetVersionNumber("$Revision: 4288 $")
30class TIF_ReaderClass(G2obj.ImportImage):
31    '''Reads TIF files using a routine (:func:`GetTifData`) that looks
32    for files that can be identified from known instruments and will
33    correct for slightly incorrect TIF usage. If that routine fails,
34    it will be read with a standard TIF reader, which can handle compression
35    and other things less commonly used at beamlines.
36    '''
37    def __init__(self):
38        super(self.__class__,self).__init__( # fancy way to self-reference
39            extensionlist=('.tif','.tiff'),
40            strictExtension=False,
41            formatName = 'TIF image',
42            longFormatName = 'Various .tif and pseudo-TIF formats'
43            )
44        self.scriptable = True
45
46    def ContentsValidator(self, filename):
47        '''Does the header match the required TIF header?
48        '''
49        fp = open(filename,'rb')
50        tag = fp.read(2)
51        if 'bytes' in str(type(tag)):
52            tag = tag.decode('latin-1')
53        if tag == 'II' and int(st.unpack('<h',fp.read(2))[0]) == 42: #little endian
54            pass
55        elif tag == 'MM' and int(st.unpack('>h',fp.read(2))[0]) == 42: #big endian
56            pass
57        else:
58            return False # header not found; not valid TIF
59            fp.close()
60        fp.close()
61        return True
62   
63    def Reader(self,filename, ParentFrame=None, **unused):
64        '''Read the TIF file using :func:`GetTifData`. If that fails,
65        use :func:`scipy.misc.imread` and give the user a chance to
66        edit the likely wrong default image parameters.
67        '''
68        self.Comments,self.Data,self.Npix,self.Image = GetTifData(filename)
69        if self.Npix == 0:
70            G2fil.G2Print("GetTifData failed to read "+str(filename)+" Trying PIL")
71#            import scipy.misc
72#            self.Image = scipy.misc.imread(filename,flatten=True)
73            import PIL.Image as PI
74            self.Image = PI.open(filename,mode='r')
75           
76            # for scipy 1.2 & later  scipy.misc.imread will be removed
77            # with note to use imageio.imread instead
78            # (N.B. scipy.misc.imread uses PIL/pillow perhaps better to just use pillow)
79            self.Npix = self.Image.size
80            if ParentFrame:
81                self.SciPy = True
82                self.Comments = ['no metadata']
83                self.Data = {'wavelength': 0.1, 'pixelSize': [200., 200.], 'distance': 100.0}
84                self.Data['size'] = list(self.Image.shape)
85                self.Data['center'] = [int(i/2) for i in self.Image.shape]
86        if self.Npix == 0:
87            return False
88        self.LoadImage(ParentFrame,filename)
89        return True
90
91def GetTifData(filename):
92    '''Read an image in a pseudo-tif format,
93    as produced by a wide variety of software, almost always
94    incorrectly in some way.
95    '''
96    import struct as st
97    import array as ar
98    import ReadMarCCDFrame as rmf
99    image = None
100    File = open(filename,'rb')
101    dataType = 5
102    center = [None,None]
103    wavelength = None
104    distance = None
105    polarization = None
106    samplechangerpos = None
107    try:
108        Meta = open(filename+'.metadata','Ur')
109        head = Meta.readlines()
110        for line in head:
111            line = line.strip()
112            try:
113                if '=' not in line: continue
114                keyword = line.split('=')[0].strip()
115                if 'dataType' == keyword:
116                    dataType = int(line.split('=')[1])
117                elif 'wavelength' == keyword.lower():
118                    wavelength = float(line.split('=')[1])
119                elif 'distance' == keyword.lower():
120                    distance = float(line.split('=')[1])
121                elif 'polarization' == keyword.lower():
122                    polarization = float(line.split('=')[1])
123                elif 'samplechangercoordinate' == keyword.lower():
124                    samplechangerpos = float(line.split('=')[1])
125            except:
126                G2fil.G2Print('error reading metadata: '+line)
127        Meta.close()
128    except IOError:
129        G2fil.G2Print ('no metadata file found - will try to read file anyway')
130        head = ['no metadata file found',]
131       
132    tag = File.read(2)
133    if 'bytes' in str(type(tag)):
134        tag = tag.decode('latin-1')
135    byteOrd = '<'
136    if tag == 'II' and int(st.unpack('<h',File.read(2))[0]) == 42:     #little endian
137        IFD = int(st.unpack(byteOrd+'i',File.read(4))[0])
138    elif tag == 'MM' and int(st.unpack('>h',File.read(2))[0]) == 42:   #big endian
139        byteOrd = '>'
140        IFD = int(st.unpack(byteOrd+'i',File.read(4))[0])       
141    else:
142#        print (tag)
143        lines = ['not a detector tiff file',]
144        return lines,0,0,0
145    File.seek(IFD)                                                  #get number of directory entries
146    NED = int(st.unpack(byteOrd+'h',File.read(2))[0])
147    IFD = {}
148    nSlice = 1
149    if DEBUG: print('byteorder:',byteOrd)
150    for ied in range(NED):
151        Tag,Type = st.unpack(byteOrd+'Hh',File.read(4))
152        nVal = st.unpack(byteOrd+'i',File.read(4))[0]
153        if DEBUG: print ('Try:',Tag,Type,nVal)
154        if Type == 1:
155            Value = st.unpack(byteOrd+nVal*'b',File.read(nVal))
156        elif Type == 2:
157            Value = st.unpack(byteOrd+'i',File.read(4))
158        elif Type == 3:
159            Value = st.unpack(byteOrd+nVal*'h',File.read(nVal*2))
160            st.unpack(byteOrd+nVal*'h',File.read(nVal*2))
161        elif Type == 4:
162            if Tag in [273,279]:
163                nSlice = nVal
164                nVal = 1
165            Value = st.unpack(byteOrd+nVal*'i',File.read(nVal*4))
166        elif Type == 5:
167            Value = st.unpack(byteOrd+nVal*'i',File.read(nVal*4))
168        elif Type == 11:
169            Value = st.unpack(byteOrd+nVal*'f',File.read(nVal*4))
170        IFD[Tag] = [Type,nVal,Value]
171        if DEBUG: print (Tag,IFD[Tag])
172    sizexy = [IFD[256][2][0],IFD[257][2][0]]
173    [nx,ny] = sizexy
174    Npix = nx*ny
175    time0 = time.time()
176    if 34710 in IFD:
177        G2fil.G2Print ('Read MAR CCD tiff file: '+filename)
178        marFrame = rmf.marFrame(File,byteOrd,IFD)
179        image = np.flipud(np.array(np.asarray(marFrame.image),dtype=np.int32))
180        tifType = marFrame.filetitle
181        pixy = [marFrame.pixelsizeX/1000.0,marFrame.pixelsizeY/1000.0]
182        head = marFrame.outputHead()
183# extract resonable wavelength from header
184        wavelength = marFrame.sourceWavelength*1e-5
185        wavelength = (marFrame.opticsWavelength > 0) and marFrame.opticsWavelength*1e-5 or wavelength
186        wavelength = (wavelength <= 0) and None or wavelength
187# extract resonable distance from header
188        distance = (marFrame.startXtalToDetector+marFrame.endXtalToDetector)*5e-4
189        distance = (distance <= marFrame.startXtalToDetector*5e-4) and marFrame.xtalToDetector*1e-3 or distance
190        distance = (distance <= 0) and None or distance
191# extract resonable center from header
192        center = [marFrame.beamX*marFrame.pixelsizeX*1e-9,marFrame.beamY*marFrame.pixelsizeY*1e-9]
193        center = (center[0] != 0 and center[1] != 0) and center or [None,None]
194#print head,tifType,pixy
195    elif nSlice > 1:    #CheMin multislice tif file!
196        try:
197            import Image as Im
198        except ImportError:
199            try:
200                from PIL import Image as Im
201            except ImportError:
202                G2fil.G2Print ("PIL/pillow Image module not present. This TIF cannot be read without this")
203                #raise Exception("PIL/pillow Image module not found")
204                lines = ['not a detector tiff file',]
205                return lines,0,0,0
206        tifType = 'CheMin'
207        pixy = [40.,40.]
208        image = np.flipud(np.array(Im.open(filename)))*10.
209        distance = 18.0
210        center = [pixy[0]*sizexy[0]/2000,0]     #the CheMin beam stop is here
211        wavelength = 1.78892
212    elif 272 in IFD:
213        ifd = IFD[272]
214        File.seek(ifd[2][0])
215        S = File.read(ifd[1])
216        if b'PILATUS' in S:
217            tifType = 'Pilatus'
218            dataType = 0
219            pixy = [172.,172.]
220            File.seek(4096)
221            G2fil.G2Print ('Read Pilatus tiff file: '+filename)
222            image = np.array(np.frombuffer(File.read(4*Npix),dtype=np.int32),dtype=np.int32)
223        else:
224            if IFD[258][2][0] == 16:
225                if sizexy == [3888,3072] or sizexy == [3072,3888]:
226                    tifType = 'Dexela'
227                    pixy = [74.8,74.8]
228                    G2fil.G2Print ('Read Dexela detector tiff file: '+filename)
229                else:
230                    tifType = 'GE'
231                    pixy = [200.,200.]
232                    G2fil.G2Print ('Read GE-detector tiff file: '+filename)
233                File.seek(8)
234                image = np.array(np.frombuffer(File.read(2*Npix),dtype=np.uint16),dtype=np.int32)
235            elif IFD[258][2][0] == 32:
236                # includes CHESS & Pilatus files from Area Detector
237                tifType = 'CHESS'
238                pixy = [200.,200.]
239                File.seek(8)
240                G2fil.G2Print ('Read as 32-bit unsigned (CHESS) tiff file: '+filename)
241                image = np.array(ar.array('I',File.read(4*Npix)),dtype=np.uint32)
242    elif 270 in IFD:
243        File.seek(IFD[270][2][0])
244        S = File.read(IFD[273][2][0]-IFD[270][2][0])
245        if b'ImageJ' in S:
246            tifType = 'ImageJ'
247            dataType = 0
248            pixy = [200.,200.]*IFD[277][2][0]
249            File.seek(IFD[273][2][0])
250            G2fil.G2Print ('Read ImageJ tiff file: '+filename)
251            if IFD[258][2][0] == 32:
252                image = File.read(4*Npix)
253                image = np.array(np.frombuffer(image,dtype=byteOrd+'i4'),dtype=np.int32)
254            elif IFD[258][2][0] == 16:
255                image = File.read(2*Npix)
256                pixy = [109.92,109.92]      #for LCLS ImageJ tif files
257                image = np.array(np.frombuffer(image,dtype=byteOrd+'u2'),dtype=np.int32)
258        else:   #gain map from  11-ID-C?
259            pixy = [200.,200.]
260            tifType = 'Gain map'
261            image = File.read(4*Npix)
262            image = np.array(np.frombuffer(image,dtype=byteOrd+'f4')*1000,dtype=np.int32)
263           
264    elif 262 in IFD and IFD[262][2][0] > 4:
265        tifType = 'DND'
266        pixy = [158.,158.]
267        File.seek(512)
268        G2fil.G2Print ('Read DND SAX/WAX-detector tiff file: '+filename)
269        image = np.array(np.frombuffer(File.read(2*Npix),dtype=np.uint16),dtype=np.int32)
270    elif sizexy == [1536,1536]:
271        tifType = 'APS Gold'
272        pixy = [150.,150.]
273        File.seek(64)
274        G2fil.G2Print ('Read Gold tiff file:'+filename)
275        image = np.array(np.frombuffer(File.read(2*Npix),dtype=np.uint16),dtype=np.int32)
276    elif sizexy == [2048,2048] or sizexy == [1024,1024] or sizexy == [3072,3072]:
277        if IFD[273][2][0] == 8:
278            if IFD[258][2][0] == 32:
279                tifType = 'PE'
280                pixy = [200.,200.]
281                File.seek(8)
282                G2fil.G2Print ('Read APS PE-detector tiff file: '+filename)
283                if dataType == 5:
284                    image = np.array(np.frombuffer(File.read(4*Npix),dtype=np.float32),dtype=np.int32)  #fastest
285                else:
286                    image = np.array(np.frombuffer(File.read(4*Npix),dtype=np.int32),dtype=np.int32)
287            elif IFD[258][2][0] == 16: 
288                tifType = 'MedOptics D1'
289                pixy = [46.9,46.9]
290                File.seek(8)
291                G2fil.G2Print ('Read MedOptics D1 tiff file: '+filename)
292                image = np.array(np.frombuffer(File.read(2*Npix),dtype=np.uint16),dtype=np.int32)
293                 
294        elif IFD[273][2][0] == 4096:
295            if sizexy[0] == 3072:
296                pixy =  [73.,73.]
297                tifType = 'MAR225'           
298            else:
299                pixy = [158.,158.]
300                tifType = 'MAR325'           
301            File.seek(4096)
302            G2fil.G2Print ('Read MAR CCD tiff file: '+filename)
303            image = np.array(np.frombuffer(File.read(2*Npix),dtype=np.uint16),dtype=np.int32)
304        elif IFD[273][2][0] == 512:
305            tifType = '11-ID-C'
306            pixy = [200.,200.]
307            File.seek(512)
308            G2fil.G2Print ('Read 11-ID-C tiff file: '+filename)
309            image = np.array(np.frombuffer(File.read(2*Npix),dtype=np.uint16),dtype=np.int32)
310                   
311    elif sizexy == [4096,4096]:
312        if IFD[273][2][0] == 8:
313            if IFD[258][2][0] == 16:
314                tifType = 'scanCCD'
315                pixy = [9.,9.]
316                File.seek(8)
317                G2fil.G2Print ('Read APS scanCCD tiff file: '+filename)
318                image = np.array(ar.array('H',File.read(2*Npix)),dtype=np.int32)
319            elif IFD[258][2][0] == 32:
320                tifType = 'PE4k'
321                pixy = [100.,100.]
322                File.seek(8)
323                G2fil.G2Print ('Read PE 4Kx4K tiff file: '+filename)
324                image = np.array(np.frombuffer(File.read(4*Npix),dtype=np.float32)/2.**4,dtype=np.int32)
325        elif IFD[273][2][0] == 4096:
326            tifType = 'Rayonix'
327            pixy = [73.242,73.242]
328            File.seek(4096)
329            G2fil.G2Print ('Read Rayonix MX300HE tiff file: '+filename)
330            image = np.array(np.frombuffer(File.read(2*Npix),dtype=np.uint16),dtype=np.int32)
331    elif sizexy == [391,380]:
332        pixy = [109.92,109.92]
333        File.seek(8)
334        image = np.array(np.frombuffer(File.read(2*Npix),dtype=np.int16),dtype=np.int32)
335    elif sizexy == [380,391]:
336        File.seek(110)
337        pixy = [109.92,109.92]
338        image = np.array(np.frombuffer(File.read(Npix),dtype=np.uint8),dtype=np.int32)
339    elif sizexy ==  [825,830]:
340        pixy = [109.92,109.92]
341        File.seek(8)
342        image = np.array(np.frombuffer(File.read(Npix),dtype=np.uint8),dtype=np.int32)
343    elif sizexy ==  [1800,1800]:
344        pixy = [109.92,109.92]
345        File.seek(110)
346        image = np.array(np.frombuffer(File.read(Npix),dtype=np.uint8),dtype=np.int32)
347    elif sizexy == [2880,2880]:
348        pixy = [150.,150.]
349        File.seek(8)
350        dt = np.dtype(np.float32)
351        dt = dt.newbyteorder(byteOrd)
352        image = np.array(np.frombuffer(File.read(Npix*4),dtype=dt),dtype=np.int32)
353    elif sizexy == [3070,1102]:
354        G2fil.G2Print ('Read Dectris Eiger 1M tiff file: '+filename)
355        pixy = [75.,75.]
356        File.seek(8)
357        dt = np.dtype(np.float32)
358        dt = dt.newbyteorder(byteOrd)
359        image = np.array(np.frombuffer(File.read(Npix*4),dtype=np.uint32),dtype=np.int32)
360#    elif sizexy == [960,960]:
361#        tiftype = 'PE-BE'
362#        pixy = (200,200)
363#        File.seek(8)
364#        if not imageOnly:
365#            print 'Read Gold tiff file:',filename
366#        image = np.array(ar.array('H',File.read(2*Npix)),dtype=np.int32)
367           
368    if image is None:
369        lines = ['not a known detector tiff file',]
370        return lines,0,0,0
371       
372    if sizexy[1]*sizexy[0] != image.size: # test is resize is allowed
373        lines = ['not a known detector tiff file',]
374        return lines,0,0,0
375    if GSASIIpath.GetConfigValue('debug'):
376        G2fil.G2Print ('image read time: %.3f'%(time.time()-time0))
377    image = np.reshape(image,(sizexy[1],sizexy[0]))
378    center = (not center[0]) and [pixy[0]*sizexy[0]/2000,pixy[1]*sizexy[1]/2000] or center
379    wavelength = (not wavelength) and 0.10 or wavelength
380    distance = (not distance) and 100.0 or distance
381    polarization = (not polarization) and 0.99 or polarization
382    samplechangerpos = (not samplechangerpos) and 0.0 or samplechangerpos
383    data = {'pixelSize':pixy,'wavelength':wavelength,'distance':distance,'center':center,'size':sizexy,
384            'setdist':distance,'PolaVal':[polarization,False],'samplechangerpos':samplechangerpos}
385    File.close()   
386    return head,data,Npix,image
Note: See TracBrowser for help on using the repository browser.