source: trunk/imports/G2img_1TIF.py @ 3323

Last change on this file since 3323 was 3323, checked in by toby, 5 years ago

fix image plotting at expense of 'w' plots; note code to be obsoleted

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