source: sasview/src/sas/perspectives/calculator/image_viewer.py @ 7168b8b

ESS_GUIESS_GUI_DocsESS_GUI_batch_fittingESS_GUI_bumps_abstractionESS_GUI_iss1116ESS_GUI_iss879ESS_GUI_iss959ESS_GUI_openclESS_GUI_orderingESS_GUI_sync_sascalccostrafo411magnetic_scattrelease-4.1.1release-4.1.2release-4.2.2release_4.0.1ticket-1009ticket-1094-headlessticket-1242-2d-resolutionticket-1243ticket-1249ticket885unittest-saveload
Last change on this file since 7168b8b was 7a04dbb, checked in by krzywon, 10 years ago

Removed the last vestiges of the SANS references and ran run.py. Tested
loading multiple file types and ran fits, p(r) and inversion. Help
windows loaded properly. Saving and loading projects and analyses acted
the same as before the conversion.

All unit tests run by utest_sasview.py passed.

  • Property mode set to 100644
File size: 16.8 KB
Line 
1import os
2import sys
3import wx
4import numpy as np
5import matplotlib
6matplotlib.interactive(False)
7#Use the WxAgg back end. The Wx one takes too long to render
8matplotlib.use('WXAgg')
9from sas.guiframe.local_perspectives.plotting.SimplePlot import PlotFrame
10#import matplotlib.pyplot as plt
11import matplotlib.image as mpimg
12import matplotlib.colors as colors
13from sas.guiframe.events import StatusEvent
14from sas.perspectives.calculator.calculator_widgets import InputTextCtrl
15from sas.dataloader.data_info import Data2D
16from sas.dataloader.data_info import Detector
17from sas.dataloader.manipulations import reader2D_converter
18_BOX_WIDTH = 60
19IS_WIN = True
20if sys.platform.count("win32") > 0:
21    _DIALOG_WIDTH = 400
22else:
23    _DIALOG_WIDTH = 480
24    IS_WIN = False
25
26class ImageView:
27    """
28    Open a file dialog to allow the user to select a given file.
29    Display the loaded data if available.
30    """
31    def __init__(self, parent=None):
32        """
33        Init
34        """
35        self.parent = parent
36       
37    def load(self):
38        """
39        load image files
40        """
41        parent = self.parent
42        if parent == None:
43            location = os.getcwd()
44        else:
45            location = parent._default_save_location
46        path_list = self.choose_data_file(location=location)
47        if path_list == None:
48            return
49        if len(path_list) >= 0 and not(path_list[0]is None):
50            if parent != None:
51                parent._default_save_location = os.path.dirname(path_list[0])
52        err_msg = ''
53        for file_path in path_list:
54            basename = os.path.basename(file_path)
55            _, extension = os.path.splitext(basename)
56            try:
57                img = mpimg.imread(file_path)
58                is_png = extension.lower() == '.png'
59                plot_frame = ImageFrame(parent, -1, basename, img)
60                plot_frame.Show(False)
61                #plot_frame.im_show(img)
62                ax = plot_frame.plotpanel
63                if not is_png:
64                    ax.subplot.set_ylim(ax.subplot.get_ylim()[::-1])
65                ax.subplot.set_xlabel('x [pixel]')
66                ax.subplot.set_ylabel('y [pixel]')
67                ax.figure.subplots_adjust(left=0.15, bottom=0.1, 
68                                          right=0.95, top=0.95)
69                plot_frame.SetTitle('Picture -- %s --'% basename)
70                plot_frame.Show(True)
71                if parent != None:
72                    parent.put_icon(plot_frame)
73            except:
74                print "parent", parent
75                raise
76                err_msg += "Failed to load '%s'.\n"% basename
77        if err_msg:
78            if parent is not None:
79                wx.PostEvent(parent, StatusEvent(status=err_msg, info="error"))
80            else:
81                print err_msg
82
83       
84    def choose_data_file(self, location=None):
85        """
86        Open a file dialog to allow loading a file
87        """
88        parent = self.parent
89        path = None
90        if location == None:
91            location = os.getcwd()
92        wlist = ''
93        elist = ["All images (*.png, *.bmp, *.gif, *.jpg, *.tif, *.tiff) | \
94                *.png; *.bmp; *.gif; *.jpg; *.tif; *.tiff", 
95                "PNG files (*.PNG, *.png) | *.png", 
96                "BMP files (*.BMP, *.bmp) | *.bmp", 
97                "GIF files (*.GIF, *.gif) | *.gif",
98                "JPG files (*.JPG, *.jpg) | *.jpg",
99                "TIF files (*.TIF, *.tif) | *.tif",
100                "TIFF files (*.TIFF, *.tiff) | *.tiff"]
101        if not IS_WIN:
102            del elist[0]
103        elist.append("All files (*.*) | *.*")
104        wlist = '|'.join(elist)       
105        style = wx.OPEN|wx.FD_MULTIPLE
106        dlg = wx.FileDialog(parent, "Image Viewer: Choose a image file", 
107                            location, "", wlist, style=style)
108        if dlg.ShowModal() == wx.ID_OK:
109            path = dlg.GetPaths()
110        else:
111            return None
112        dlg.Destroy()
113        return path
114
115class ImageFrame(PlotFrame):
116    """
117    Frame for simple plot
118    """
119    def __init__(self, parent, id, title, image=None, scale='log_{10}', 
120                 size=wx.Size(550, 470)): 
121        """
122        comment
123        :Param data: image array got from imread() of matplotlib [narray]
124        :param parent: parent panel/container
125        """
126        # Initialize the Frame object
127        PlotFrame.__init__(self, parent, id, title, scale, size)
128        self.parent = parent
129        self.data = image
130        self.file_name = title
131                   
132        menu = wx.Menu()
133        id = wx.NewId()
134        item = wx.MenuItem(menu, id, "&Convert to Data")
135        menu.AppendItem(item)
136        wx.EVT_MENU(self, id, self.on_set_data)
137        self.menu_bar.Append(menu, "&Image")
138
139        menu_help = wx.Menu()
140        id = wx.NewId()
141        item = wx.MenuItem(menu_help, id, "&HowTo")
142        menu_help.AppendItem(item)
143        wx.EVT_MENU(self, id, self.on_help)
144        self.menu_bar.Append(menu_help, "&Help")
145       
146        self.SetMenuBar(self.menu_bar)
147        self.im_show(image)
148   
149    def on_set_data(self, event):
150        """
151        Rescale the x y range, make 2D data and send it to data explore
152        """
153        title = self.file_name
154        self.panel = SetDialog(parent=self, title=title, image=self.data)
155        self.panel.ShowModal()
156
157    def on_help(self, event):   
158        """
159        Image Viewer help panel
160        """
161        from sas.perspectives.calculator.help_panel import  HelpWindow
162        # Get models help model_function path
163        import sas.perspectives.calculator as calmedia
164
165        media = calmedia.get_data_path(media='media')
166        path = os.path.join(media,"load_image_help.html") 
167        name = "Image Viewer"
168        frame = HelpWindow(self, -1, title=' Help: Image Viewer', 
169                           pageToOpen=path, size=(640, 450))   
170        try: 
171            frame.splitter.DetachWindow(frame.lpanel)
172            # Display only the right side one
173            frame.lpanel.Hide() 
174            frame.Show(True)
175        except:
176            frame.Destroy() 
177            msg = 'Display Error\n'
178            info = "Info"
179            wx.MessageBox(msg, info)
180           
181class SetDialog(wx.Dialog):
182    """
183    Dialog for Data Set
184    """
185    def __init__(self, parent, id=-1, title="Convert to Data", image=None, 
186                 size=(_DIALOG_WIDTH, 270)):
187        wx.Dialog.__init__(self, parent, id, title, size)
188        # parent
189        self.parent = parent
190        self.base = parent.parent
191        self.title = title
192        self.image = np.array(image)
193        self.z_ctrl = None
194        self.xy_ctrls = []
195        self.is_png = self._get_is_png()
196        self._build_layout()
197        my_title = "Convert Image to Data - %s -"% self.title
198        self.SetTitle(my_title)
199        self.SetSize(size)
200   
201    def _get_is_png(self):
202        """
203        Get if the image file is png
204        """
205        _, extension = os.path.splitext(self.title)
206        return extension.lower() == '.png'
207           
208    def _build_layout(self):
209        """
210        Layout
211        """
212        vbox = wx.BoxSizer(wx.VERTICAL)
213        zbox = wx.BoxSizer(wx.HORIZONTAL)
214        xbox = wx.BoxSizer(wx.HORIZONTAL)
215        ybox = wx.BoxSizer(wx.HORIZONTAL)
216        btnbox = wx.BoxSizer(wx.VERTICAL)
217       
218        sb_title = wx.StaticBox(self, -1, 'Transform Axes')
219        boxsizer = wx.StaticBoxSizer(sb_title, wx.VERTICAL)
220        z_title = wx.StaticText(self, -1, 'z values (range: 0 - 255) to:')
221        ztime_title = wx.StaticText(self, -1, 'z *')
222        x_title = wx.StaticText(self, -1, 'x values from pixel # to:')
223        xmin_title = wx.StaticText(self, -1, 'xmin:')
224        xmax_title = wx.StaticText(self, -1, 'xmax:')
225        y_title = wx.StaticText(self, -1, 'y values from pixel # to:')
226        ymin_title = wx.StaticText(self, -1, 'ymin: ')
227        ymax_title = wx.StaticText(self, -1, 'ymax:')
228        z_ctl = InputTextCtrl(self, -1, size=(_BOX_WIDTH , 20),
229                                style=wx.TE_PROCESS_ENTER)
230       
231        xmin_ctl = InputTextCtrl(self, -1, size=(_BOX_WIDTH, 20),
232                                style=wx.TE_PROCESS_ENTER)
233        xmax_ctl = InputTextCtrl(self, -1, size=(_BOX_WIDTH, 20),
234                                style=wx.TE_PROCESS_ENTER)
235        ymin_ctl = InputTextCtrl(self, -1, size=(_BOX_WIDTH, 20),
236                                style=wx.TE_PROCESS_ENTER)
237        ymax_ctl = InputTextCtrl(self, -1, size=(_BOX_WIDTH, 20),
238                                style=wx.TE_PROCESS_ENTER)
239        z_ctl.SetValue('1.0')
240        xmin_ctl.SetValue('-0.3')
241        xmax_ctl.SetValue('0.3')
242        ymin_ctl.SetValue('-0.3')
243        ymax_ctl.SetValue('0.3')
244        z_ctl.Bind(wx.EVT_TEXT, self._on_z_enter)
245        xmin_ctl.Bind(wx.EVT_TEXT, self._onparam)
246        xmax_ctl.Bind(wx.EVT_TEXT, self._onparam)
247        ymin_ctl.Bind(wx.EVT_TEXT, self._onparam)
248        ymax_ctl.Bind(wx.EVT_TEXT, self._onparam)
249        xbox.AddMany([(x_title , 0, wx.LEFT, 0), 
250                      (xmin_title , 0, wx.LEFT, 10), 
251                      (xmin_ctl , 0, wx.LEFT, 10), 
252                      (xmax_title , 0, wx.LEFT, 10), 
253                      (xmax_ctl , 0, wx.LEFT, 10)])
254        ybox.AddMany([(y_title , 0, wx.LEFT, 0), 
255                      (ymin_title , 0, wx.LEFT, 10), 
256                      (ymin_ctl , 0, wx.LEFT, 10), 
257                      (ymax_title , 0, wx.LEFT, 10), 
258                      (ymax_ctl , 0, wx.LEFT, 10)])     
259        zbox.AddMany([(z_title , 0, wx.LEFT, 0), 
260                      (ztime_title, 0, wx.LEFT, 10),
261                      (z_ctl , 0, wx.LEFT, 7), 
262                      ])   
263        msg = "The data rescaled will show up in the Data Explorer. \n"
264        msg += "*Note: Recommend to use an image with 8 bit Grey \n"
265        msg += "  scale (and with No. of pixels < 300 x 300).\n"
266        msg += "  Otherwise, z = 0.299R + 0.587G + 0.114B."
267        note_txt = wx.StaticText(self, -1, msg)
268        note_txt.SetForegroundColour("black")
269        hbox = wx.BoxSizer(wx.HORIZONTAL)
270        okButton = wx.Button(self, -1, 'OK')
271        okButton.Bind(wx.EVT_BUTTON, self.on_set)
272        cancelButton = wx.Button(self, -1, 'Cancel')
273        cancelButton.Bind(wx.EVT_BUTTON, self.OnClose)
274        btnbox.Add(okButton, 0, wx.LEFT | wx.BOTTOM, 5)
275        btnbox.Add(cancelButton, 0, wx.LEFT | wx.TOP, 5)
276        hbox.Add(note_txt, 0, wx.LEFT, 5)
277        hbox.Add(btnbox, 0, wx.LEFT, 15)
278        vbox.Add((10, 15))
279        boxsizer.Add(xbox, 1, wx.LEFT | wx.BOTTOM, 5)
280        boxsizer.Add(ybox, 1, wx.LEFT | wx.BOTTOM, 5)
281        boxsizer.Add(zbox, 1, wx.LEFT | wx.BOTTOM, 5)
282        vbox.Add(boxsizer, 0, wx.LEFT, 20)
283        vbox.Add(hbox, 0, wx.LEFT | wx.TOP, 15)
284        okButton.SetFocus()
285        # set sizer
286        self.SetSizer(vbox)
287        #pos = self.parent.GetPosition()
288        #self.SetPosition(pos)
289        self.z_ctrl = z_ctl
290        self.xy_ctrls = [[xmin_ctl, xmax_ctl], [ymin_ctl, ymax_ctl]]
291
292    def _onparamEnter(self, event=None):
293        """
294        By pass original txtcrl binding
295        """
296        pass   
297       
298    def _onparam(self, event=None):
299        """
300        Set to default
301        """
302        item = event.GetEventObject()
303        self._check_ctrls(item)
304
305    def _check_ctrls(self, item, is_button=False):
306        """
307        """
308        flag = True
309        item.SetBackgroundColour("white")
310        try:
311            val = float(item.GetValue()) 
312            if val < -10.0 or val > 10.0:
313                item.SetBackgroundColour("pink")
314                item.Refresh()
315                flag = False
316        except:
317            item.SetBackgroundColour("pink")
318            item.Refresh()
319            flag = False
320        if not flag and is_button:
321            err_msg = "The allowed range of the min and max values are \n"
322            err_msg += "between -10 and 10."
323            if self.base is not None:
324                wx.PostEvent(self.base, StatusEvent(status=err_msg, 
325                                                    info="error"))
326            else:
327                print err_msg
328        return flag
329
330    def _on_z_enter(self, event= None): 
331        """
332        On z factor enter
333        """
334        item = event.GetEventObject()
335        self._check_z_ctrl(item)
336       
337    def _check_z_ctrl(self, item, is_button=False):
338        """
339        """
340        flag = True
341        item.SetBackgroundColour("white")
342        try:
343            val = float(item.GetValue()) 
344            if val <= 0:
345                item.SetBackgroundColour("pink")
346                item.Refresh()
347                flag = False
348        except:
349            item.SetBackgroundColour("pink")
350            item.Refresh() 
351            flag = False
352        if not flag and is_button:
353            err_msg = "The z scale value should be larger than 0."
354            if self.base is not None:
355                wx.PostEvent(self.base, StatusEvent(status=err_msg, 
356                                                    info="error"))
357            else:
358                print err_msg
359        return flag
360   
361    def on_set(self, event):
362        """
363        Set image as data   
364        """
365        event.Skip()
366        # Check the textctrl values
367        for item_list in self.xy_ctrls:
368            for item in item_list:
369                 if not self._check_ctrls(item, True):
370                     return
371        if not self._check_z_ctrl(self.z_ctrl, True):
372            return
373        try:
374            image = self.image
375            xmin = float(self.xy_ctrls[0][0].GetValue())
376            xmax = float(self.xy_ctrls[0][1].GetValue())
377            ymin = float(self.xy_ctrls[1][0].GetValue())
378            ymax = float(self.xy_ctrls[1][1].GetValue())
379            zscale = float(self.z_ctrl.GetValue())
380            self.convert_image(image, xmin, xmax, ymin, ymax, zscale)
381        except:
382            err_msg = "Error occurred while converting Image to Data."
383            if self.base is not None:
384                wx.PostEvent(self.base, StatusEvent(status=err_msg, 
385                                                    info="error"))
386            else:
387                print err_msg
388           
389        self.OnClose(event)
390   
391    def convert_image(self, rgb, xmin, xmax, ymin, ymax, zscale):
392        """
393        Convert image to data2D
394        """
395        x_len = len(rgb[0])
396        y_len = len(rgb)
397        x_vals = np.linspace(xmin, xmax, num=x_len)
398        y_vals = np.linspace(ymin, ymax, num=y_len)
399        # Instantiate data object
400        output = Data2D()
401        output.filename = os.path.basename(self.title)
402        output.id = output.filename
403        detector = Detector()
404        detector.pixel_size.x = None
405        detector.pixel_size.y = None
406        # Store the sample to detector distance
407        detector.distance = None
408        output.detector.append(detector)
409        # Initiazed the output data object
410        output.data = zscale * self.rgb2gray(rgb)
411        output.err_data = np.zeros([x_len, y_len])
412        output.mask = np.ones([x_len, y_len], dtype=bool)
413        output.xbins = x_len
414        output.ybins = y_len
415        output.x_bins = x_vals
416        output.y_bins = y_vals
417        output.qx_data = np.array(x_vals)
418        output.qy_data = np.array(y_vals)
419        output.xmin = xmin
420        output.xmax = xmax
421        output.ymin = ymin
422        output.ymax = ymax
423        output.xaxis('\\rm{Q_{x}}', '\AA^{-1}')
424        output.yaxis('\\rm{Q_{y}}', '\AA^{-1}')
425        # Store loading process information
426        output.meta_data['loader'] = self.title.split('.')[-1] + "Reader"
427        output.is_data = True
428        output = reader2D_converter(output)
429        if self.base != None:
430            data = self.base.create_gui_data(output, self.title)
431            self.base.add_data({data.id:data})
432           
433    def rgb2gray(self, rgb):
434        """
435        RGB to Grey
436        """
437        if self.is_png:
438            # png image limits: 0 to 1, others 0 to 255
439            #factor = 255.0
440            rgb = rgb[::-1]
441        if rgb.ndim == 2:
442            grey = np.rollaxis(rgb, axis = 0)
443        else:
444            red, green, blue = np.rollaxis(rgb[...,:3], axis = -1)
445            grey = 0.299 * red + 0.587 * green + 0.114 * blue
446        max_i = rgb.max()
447        factor = 255.0 / max_i
448        grey *= factor
449        return np.array(grey)
450                     
451    def OnClose(self, event):
452        """
453        Close event
454        """
455        # clear event
456        event.Skip()
457        self.Destroy()
458                       
459if __name__ == "__main__":
460    app  = wx.App()
461    ImageView(None).load()
462    app.MainLoop()   
463   
464 
Note: See TracBrowser for help on using the repository browser.