source: trunk/autoint.py @ 2065

Last change on this file since 2065 was 2065, checked in by toby, 6 years ago

Allow reading of multiple images from single file

  • Property svn:eol-style set to native
File size: 19.3 KB
Line 
1import os
2import wx
3import copy
4import glob
5import re
6import GSASIIpath
7import GSASIIIO as G2IO
8import GSASIIctrls as G2G
9import GSASIIgrid as G2gd
10import GSASIIimgGUI as G2imG
11'''
12Define a class to be used for Andrey's AutoIntegration process
13'''
14
15class AutoIntFrame(wx.Frame):
16    '''Creates a wx.Frame window for the Image AutoIntegration.
17    The intent is that this will be used as a non-modal dialog window.
18   
19    Implements a Start button that morphs into a pause and resume button.
20    This button starts a processing loop that is repeated every
21    :meth:`PollTime` seconds.
22
23    :param wx.Frame G2frame: main GSAS-II frame
24    :param float PollTime: frequency in seconds to repeat calling the
25      processing loop. (Default is 3.0 seconds.)
26    '''
27    def OnTimerLoop(self,event):
28        '''A method that is called every :meth:`PollTime` seconds that is
29        used to check for new files and process them. This is called only
30        after the "Start" button is pressed (when its label reads "Pause").
31        '''
32        G2frame = self.G2frame
33        try:
34            self.currImageList = sorted(
35                glob.glob(os.path.join(self.imagedir,self.params['filter'])))
36        except IndexError:
37            self.currImageList = []
38            return
39
40        # Create a list of image files that have already been read
41        imageFileList = []
42        for img in G2gd.GetPatternTreeDataNames(G2frame,['IMG ']):
43            imgId = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,img)
44            size,imagefile,imagetag = G2frame.PatternTree.GetImageLoc(imgId)
45            if imagefile not in imageFileList: imageFileList.append(imagefile)
46        # loop over image files matching glob, reading in new ones
47        for newImage in self.currImageList:
48            if newImage in imageFileList: continue # already read
49            for imgId in G2IO.ReadImages(G2frame,newImage):
50                # update controls from master
51                controlsDict = G2frame.PatternTree.GetItemPyData(
52                    G2gd.GetPatternTreeItemId(G2frame,imgId, 'Image Controls'))
53                controlsDict.update(self.ImageControls)
54                # update masks from master
55                ImageMasks = G2frame.PatternTree.GetItemPyData(
56                    G2gd.GetPatternTreeItemId(G2frame,imgId, 'Masks'))
57                ImageMasks.update(self.ImageMasks)
58        # now integrate the images that have not already been processed before
59        for img in G2gd.GetPatternTreeDataNames(G2frame,['IMG ']):
60            if img in G2frame.IntegratedList: continue
61            G2frame.IntegratedList.append(img)
62            imgId = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,img)
63            G2frame.Image = imgId
64            G2frame.PickId = G2gd.GetPatternTreeItemId(G2frame,G2frame.Image, 'Image Controls')
65            #  integrate in this entry
66            size,imagefile,imagetag = G2frame.PatternTree.GetImageLoc(imgId)
67            G2frame.ImageZ = G2IO.GetImageData(G2frame,imagefile,True,imagetag)
68            masks = G2frame.PatternTree.GetItemPyData(
69                G2gd.GetPatternTreeItemId(G2frame,G2frame.Image, 'Masks'))
70            data = G2frame.PatternTree.GetItemPyData(G2frame.PickId)
71            self.oldImagefile = '' # mark image as changed; reread as needed
72            # simulate a Image Controls press, since that is where the
73            # integration is hidden
74            G2imG.UpdateImageControls(G2frame,data,masks,IntegrateOnly=True)
75            # split name and control number
76            s = re.split(r'(\d+)\Z',os.path.split(os.path.splitext(imagefile)[0])[1])
77            namepre = s[0]
78            if len(s) > 1:
79                namenum = s[1]
80            else:
81                namenum = ''
82            # write out the images in the selected formats and save the names,
83            # reset will delete them
84            for Id in G2frame.IntgOutList:
85                treename = G2frame.PatternTree.GetItemText(Id)
86                G2frame.AutointPWDRnames.append(treename)
87                Sdata = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id, 'Sample Parameters'))
88                # determine the name for the current file
89                fileroot = namepre
90                if len(G2frame.IntgOutList) > 1:
91                    fileroot += "_AZM"
92                    if 'Azimuth' in Sdata:
93                        fileroot += str(int(10*Sdata['Azimuth']))
94                    fileroot += "_" 
95                fileroot += namenum
96                # loop over selected formats
97                for dfmt in self.fmtlist:
98                    if not self.params[dfmt[1:]]: continue
99                    if self.params['SeparateDir']:
100                        subdir = dfmt[1:]
101                    else:
102                        subdir = ''
103                    fil = os.path.join(self.params['outdir'],subdir,fileroot)
104                    print('writing file '+fil+dfmt)
105                    G2IO.ExportPowder(G2frame,treename,fil,dfmt)
106       
107        if GSASIIpath.GetConfigValue('debug'):
108            import datetime
109            print ("Timer tick at {:%d %b %Y %H:%M:%S}\n".format(datetime.datetime.now()))
110
111    def StartLoop(self):
112        '''Save current Image params for use in future integrations
113        also label the window so users understand whatis being used
114        '''
115        print '\nStarting new autointegration\n'
116        G2frame = self.G2frame
117        # show current IMG base
118        self.ControlBaseLbl.SetLabel(G2frame.PatternTree.GetItemText(G2frame.Image))
119        if self.params['Mode'] == 'file':
120            'get file info'
121            GSASIIpath.IPyBreak()
122        else:
123            # load copy of Image Controls from current image and clean up
124            # items that should not be copied
125            self.ImageControls = copy.deepcopy(
126                G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(
127                    G2frame,G2frame.Image, 'Image Controls')))
128            self.ImageControls['showLines'] = True
129            self.ImageControls['ring'] = []
130            self.ImageControls['rings'] = []
131            self.ImageControls['ellipses'] = []
132            self.ImageControls['setDefault'] = False
133            del self.ImageControls['range']
134            del self.ImageControls['size']
135            del self.ImageControls['GonioAngles']
136            # load copy of Image Masks, keep thresholds
137            self.ImageMasks = copy.deepcopy(
138                G2frame.PatternTree.GetItemPyData(
139                    G2gd.GetPatternTreeItemId(G2frame,G2frame.Image, 'Masks')))
140            self.Thresholds = self.ImageMasks['Thresholds'][:]
141        # make sure all output directories exist
142        if self.params['SeparateDir']:
143            for dfmt in self.fmtlist:
144                if not self.params[dfmt[1:]]: continue
145                dir = os.path.join(self.params['outdir'],dfmt[1:])
146                if not os.path.exists(dir): os.makedirs(dir)
147        else:
148            if not os.path.exists(self.params['outdir']):
149                os.makedirs(self.params['outdir'])
150        if self.Reset: # special things to do after Reset has been pressed
151            # reset controls and masks for all IMG items in tree to master
152            for img in G2gd.GetPatternTreeDataNames(G2frame,['IMG ']):
153                # update controls from master
154                controlsDict = G2frame.PatternTree.GetItemPyData(
155                    G2gd.GetPatternTreeItemId(G2frame,G2frame.Image, 'Image Controls'))
156                controlsDict.update(self.ImageControls)
157                # update masks from master
158                ImageMasks = G2frame.PatternTree.GetItemPyData(
159                    G2gd.GetPatternTreeItemId(G2frame,G2frame.Image, 'Masks'))
160                ImageMasks.update(self.ImageMasks)
161            # delete all PWDR items created after last Start was pressed
162            idlist = []
163            item, cookie = G2frame.PatternTree.GetFirstChild(G2frame.root)
164            while item:
165                itemName = G2frame.PatternTree.GetItemText(item)
166                if itemName in G2frame.AutointPWDRnames:
167                    idlist.append(item)
168                item, cookie = G2frame.PatternTree.GetNextChild(G2frame.root, cookie)
169            for item in idlist:
170                G2frame.PatternTree.Delete(item)
171            self.Reset = False
172        G2frame.AutointPWDRnames = [] # list of created PWDR tree item names
173
174    def __init__(self,G2frame,PollTime=60.0):
175        def OnStart(event):
176            '''Called when the start button is pressed. Changes button label
177            to Pause. When Pause is pressed the label changes to Resume.
178            When either Start or Resume is pressed, the processing loop
179            is started. When Pause is pressed, the loop is stopped.
180            '''
181            #print self.params # for debug
182
183            # check inputs before starting
184            err = ''
185            #if not any([self.params[fmt] for fmt in self.fmtlist]):
186            #    err += '\nPlease select at least one output format\n'
187            if (self.params['Mode'] == 'file' and not
188                    os.path.exists(self.params['IMGfile'])):
189                err += '\nThe image controls file could not be found\n'
190            if (self.params['Mode'] == 'file' and
191                not self.params['IgnoreMask']
192                ) and not os.path.exists(self.params['MaskFile']): 
193                err += '\nThe mask file could not be found\n'
194            if err:
195                G2G.G2MessageBox(self,err)
196                return
197            # change button label
198            if btnstart.GetLabel() != 'Pause':
199                btnstart.SetLabel('Pause')
200                if self.timer.IsRunning(): self.timer.Stop()
201                self.StartLoop()
202                self.OnTimerLoop(None) # run once immediately and again after delay
203                self.timer.Start(int(1000*PollTime),oneShot=False)
204                self.Status.SetStatusText('Press Pause to delay integration or Reset to prepare to reintegrate all images')
205            else:
206                btnstart.SetLabel('Resume')
207                if self.timer.IsRunning(): self.timer.Stop()
208                print('\nPausing autointegration\n')
209                self.Status.SetStatusText('Press Resume to continue integration or Reset to prepare to reintegrate all images')
210
211        def OnReset(event):
212            '''Called when Reset button is pressed. This stops the
213            processing loop and resets the list of integrated files so
214            all images can be reintegrated.
215            '''
216            btnstart.SetLabel('Restart')
217            self.Status.SetStatusText('Press Restart to reload and re-integrate images matching filter')
218            if self.timer.IsRunning(): self.timer.Stop()
219            self.Reset = True
220            self.G2frame.IntegratedList = []
221           
222        def OnQuit(event):
223            '''Stop the processing loop and close the Frame
224            '''
225            if self.timer.IsRunning(): self.timer.Stop() # make sure we stop first
226            wx.CallAfter(self.Destroy)
227           
228        def OnBrowse(event):
229            '''Responds when the Browse button is pressed to load a file.
230            The routine determines which button was pressed and gets the
231            appropriate file type and loads it into the appropriate place
232            in the dict.
233            '''
234            if btn3 == event.GetEventObject():
235                dlg = wx.DirDialog(
236                    self, 'Select directory for output files',
237                    self.params['outdir'],wx.DD_DEFAULT_STYLE)
238                dlg.CenterOnParent()
239                try:
240                    if dlg.ShowModal() == wx.ID_OK:
241                        self.params['outdir'] = dlg.GetPath()
242                        fInp3.SetValue(self.params['outdir'])
243                finally:
244                    dlg.Destroy()
245                return
246            if btn1 == event.GetEventObject():
247                ext = '.imctrl'
248                title = 'Image control'
249            else:
250                ext = '.immask'
251                title = 'Image masks'               
252            dlg = wx.FileDialog(
253                self, 'Select name for '+title+' file to read',
254                '.', '',
255                title+'file (*'+ext+')|*'+ext,
256                wx.OPEN|wx.CHANGE_DIR)
257            dlg.CenterOnParent()
258            try:
259                if dlg.ShowModal() == wx.ID_OK:
260                    filename = dlg.GetPath()
261                    # make sure extension is correct
262                    #filename = os.path.splitext(filename)[0]+ext
263                    if btn1 == event.GetEventObject():
264                        fInp1.SetValue(filename)
265                    else:
266                        fInp2.SetValue(filename)
267                else:
268                    filename = None
269            finally:
270                dlg.Destroy()
271               
272        def OnRadioSelect(event):
273            '''Respond to a radiobutton selection and enable or
274            disable widgets accordingly. Also gets called when the
275            "Don't Use" flag for Mask use is called.
276            '''
277            lbl1.Disable()
278            fInp1.Disable()
279            btn1.Disable()
280            lbl2.Disable()
281            fInp2.Disable()
282            ign2.Disable()
283            btn2.Disable()
284            if r2.GetValue():
285                self.params['Mode'] = 'file'
286                fInp1.Enable()
287                btn1.Enable()
288                lbl1.Enable()
289                ign2.Enable()
290                if not self.params['IgnoreMask']:
291                    fInp2.Enable()
292                    btn2.Enable()
293                    lbl2.Enable()
294            else:
295                self.params['Mode'] = 'active'
296        ##################################################
297        # beginning of __init__ processing
298        ##################################################
299        self.G2frame = G2frame
300        self.params = {}
301        self.Reset = False
302        self.params['IMGfile'] = ''
303        self.params['MaskFile'] = ''
304        self.params['IgnoreMask'] = True
305        self.fmtlist = G2IO.ExportPowderList(G2frame)
306        self.timer = wx.Timer()
307        self.timer.Bind(wx.EVT_TIMER,self.OnTimerLoop)
308
309        controlsId = G2frame.PatternTree.GetSelection()
310        size,imagefile,imagetag = G2frame.PatternTree.GetImageLoc(G2frame.Image)       
311        self.imagedir,fileroot = os.path.split(imagefile)
312        self.params['filter'] = '*'+os.path.splitext(fileroot)[1]
313        self.params['outdir'] = os.path.abspath(self.imagedir)
314        wx.Frame.__init__(self, G2frame,title='Automatic Integration')
315        self.Status = self.CreateStatusBar()
316        self.Status.SetStatusText('Press Start to load and integrate images matching filter')
317        mnpnl = wx.Panel(self)
318        mnsizer = wx.BoxSizer(wx.VERTICAL)
319        sizer = wx.BoxSizer(wx.HORIZONTAL)
320        sizer.Add(wx.StaticText(mnpnl, wx.ID_ANY,'Integration based on: '))
321        self.ControlBaseLbl = wx.StaticText(mnpnl, wx.ID_ANY,'?')
322        self.ControlBaseLbl.SetLabel(G2frame.PatternTree.GetItemText(G2frame.Image))
323        sizer.Add(self.ControlBaseLbl)
324        mnsizer.Add(sizer,0,wx.ALIGN_LEFT,1)
325        # file filter stuff
326        sizer = wx.BoxSizer(wx.HORIZONTAL)
327        sizer.Add(wx.StaticText(mnpnl, wx.ID_ANY,'Image filter'))
328        flterInp = G2G.ValidatedTxtCtrl(mnpnl,self.params,'filter')
329        sizer.Add(flterInp)
330        mnsizer.Add(sizer,0,wx.ALIGN_RIGHT,1)
331        # box for integration controls & masks input
332        lbl = wx.StaticBox(mnpnl, wx.ID_ANY, "Integration Controls/Masks source")
333        lblsizr = wx.StaticBoxSizer(lbl, wx.VERTICAL)
334        r1 = wx.RadioButton(mnpnl, wx.ID_ANY, "Use Active Image",
335                            style = wx.RB_GROUP)
336        r1.Bind(wx.EVT_RADIOBUTTON, OnRadioSelect)
337        lblsizr.Add(r1)
338        r1.SetValue(True)
339        r2 = wx.RadioButton(mnpnl, wx.ID_ANY, "Use from file(s)")
340        lblsizr.Add(r2)
341        r2.Bind(wx.EVT_RADIOBUTTON, OnRadioSelect)
342        r2.Disable()         # deactivate this until implemented
343        # Image controls file
344        sizer = wx.BoxSizer(wx.HORIZONTAL)
345        sizer.Add((20,-1))
346        lbl1 = wx.StaticText(mnpnl, wx.ID_ANY,'IMG control file: ')
347        sizer.Add(lbl1)
348        fInp1 = G2G.ValidatedTxtCtrl(mnpnl,self.params,'IMGfile',
349                                       notBlank=False,size=(300,-1))
350        sizer.Add(fInp1)
351        btn1 = wx.Button(mnpnl,  wx.ID_ANY, "Browse")
352        btn1.Bind(wx.EVT_BUTTON, OnBrowse)
353        sizer.Add(btn1)
354        lblsizr.Add(sizer)
355        # Masks input file
356        sizer = wx.BoxSizer(wx.HORIZONTAL)
357        sizer.Add((20,-1))
358        lbl2 = wx.StaticText(mnpnl, wx.ID_ANY,'Mask file: ')
359        sizer.Add(lbl2)
360        fInp2 = G2G.ValidatedTxtCtrl(mnpnl,self.params,'MaskFile',
361                                       notBlank=False,size=(300,-1))
362        sizer.Add(fInp2)
363        ign2 = G2G.G2CheckBox(mnpnl,"Don't use",self.params,'IgnoreMask',
364                              OnChange=OnRadioSelect)
365        sizer.Add(ign2)
366        btn2 = wx.Button(mnpnl,  wx.ID_ANY, "Browse")
367        btn2.Bind(wx.EVT_BUTTON, OnBrowse)
368        sizer.Add(btn2)
369        lblsizr.Add(sizer)
370        mnsizer.Add(lblsizr)
371
372        # box for output selections
373        lbl = wx.StaticBox(mnpnl, wx.ID_ANY, "Output settings")
374        lblsizr = wx.StaticBoxSizer(lbl, wx.VERTICAL)
375        sizer = wx.BoxSizer(wx.HORIZONTAL)
376        sizer.Add(wx.StaticText(mnpnl, wx.ID_ANY,'Write to: '))
377        fInp3 = G2G.ValidatedTxtCtrl(mnpnl,self.params,'outdir',
378                                       notBlank=False,size=(300,-1))
379        sizer.Add(fInp3)
380        btn3 = wx.Button(mnpnl,  wx.ID_ANY, "Browse")
381        btn3.Bind(wx.EVT_BUTTON, OnBrowse)
382        sizer.Add(btn3)
383        lblsizr.Add(sizer)
384        #lblsizr.Add(wx.StaticText(mnpnl, wx.ID_ANY,'Select format(s): '))
385        sizer = wx.BoxSizer(wx.HORIZONTAL)
386        sizer.Add(wx.StaticText(mnpnl, wx.ID_ANY,'Select format(s): '))
387        for dfmt in self.fmtlist:
388            fmt = dfmt[1:]
389            self.params[fmt] = False
390            btn = G2G.G2CheckBox(mnpnl,dfmt,self.params,fmt)
391            sizer.Add(btn)
392        lblsizr.Add(sizer)
393        sizer = wx.BoxSizer(wx.HORIZONTAL)
394        sizer.Add(wx.StaticText(mnpnl, wx.ID_ANY,'Separate dir for each format: '))
395        self.params['SeparateDir'] = False
396        sizer.Add(G2G.G2CheckBox(mnpnl,'',self.params,'SeparateDir'))
397        lblsizr.Add(sizer)
398        mnsizer.Add(lblsizr,0,wx.ALIGN_CENTER,1)
399
400        # buttons on bottom
401        mnsizer.Add(wx.StaticText(mnpnl, wx.ID_ANY,'AutoIntegration controls'),0,wx.TOP,5)
402        sizer = wx.BoxSizer(wx.HORIZONTAL)
403        sizer.Add((20,-1))
404        btnstart = wx.Button(mnpnl,  wx.ID_ANY, "Start")
405        btnstart.Bind(wx.EVT_BUTTON, OnStart)
406        sizer.Add(btnstart)
407        btnstop = wx.Button(mnpnl,  wx.ID_ANY, "Reset")
408        btnstop.Bind(wx.EVT_BUTTON, OnReset)
409        sizer.Add(btnstop)
410        sizer.Add((20,-1),wx.EXPAND,1)
411        btnquit = wx.Button(mnpnl,  wx.ID_ANY, "Close")
412        btnquit.Bind(wx.EVT_BUTTON, OnQuit)
413        sizer.Add(btnquit)
414        sizer.Add((20,-1))
415        mnsizer.Add(sizer,0,wx.EXPAND|wx.BOTTOM|wx.TOP,5)
416       
417        # finish up window
418        mnpnl.SetSizer(mnsizer)
419        OnRadioSelect(None) # disable widgets
420        mnsizer.Fit(self)
421        self.CenterOnParent()
422        self.Show() 
423
424if __name__ == '__main__':
425    app = wx.PySimpleApp()
426    G2frame = wx.Frame(None) # create a top-level frame as a stand-in for the GSAS-II data tree
427    G2frame.Show() 
428    frm = AutoIntFrame(G2frame) # test the one above
429    app.MainLoop()
430 
Note: See TracBrowser for help on using the repository browser.