From 91cea8dcff63c217e7f7e24d28ceac4830a9c69e Mon Sep 17 00:00:00 2001 From: Stefan van der Walt Date: Sun, 1 Nov 2009 23:08:49 +0200 Subject: [PATCH] Add Chris's plugin utility converter and wxpython plugin. --- scikits/image/io/_plugin_util.py | 69 +++++++++++++++++++++++++++++ scikits/image/io/wxpython_plugin.py | 53 ++++++++++++++++++++++ 2 files changed, 122 insertions(+) create mode 100644 scikits/image/io/_plugin_util.py create mode 100644 scikits/image/io/wxpython_plugin.py diff --git a/scikits/image/io/_plugin_util.py b/scikits/image/io/_plugin_util.py new file mode 100644 index 00000000..e92a185e --- /dev/null +++ b/scikits/image/io/_plugin_util.py @@ -0,0 +1,69 @@ +import numpy as np + +# utilities to make life easier for plugin writers. + + +def prepare_for_display(npy_img): + '''Convert a 2D or 3D numpy array of any dtype into a + 3D numpy array with dtype uint8. This array will + be suitable for use in passing to gui toolkits for + image display purposes. + + Parameters + ---------- + npy_img : ndarray, 2D or 3D + The image to convert for display + + Returns + ------- + out : ndarray, 3D dtype=np.uint8 + The converted image. This is guaranteed to be a contiguous array. + + Notes + ----- + If the input image is floating point, it is assumed that the data + is in the range of 0.0 - 1.0. No check is made to assert this + condition. The image is then scaled to be in the range 0 - 255 + and then cast to np.uint8 + + For all other dtypes, the array is simply cast to np.uint8 + + If a 2D array is passed, the single channel is replicated + to the 2nd and 3rd channels. + + If the array contains an alpha channel, this channel is + ignored. + + ''' + if len(npy_img.shape) < 2: + raise ValueError('Image must be 2D or 3D array') + + height = npy_img.shape[0] + width = npy_img.shape[1] + + out = np.empty((height, width, 3), dtype=np.uint8) + + if len(npy_img.shape) == 2 or \ + (len(npy_img.shape) == 3 and npy_img.shape[2] == 1): + if npy_img.dtype in [np.float32, np.float64]: + out[:,:,0] = npy_img*255 + out[:,:,1] = out[:,:,0] + out[:,:,2] = out[:,:,0] + else: + out[:,:,0] = npy_img + out[:,:,1] = npy_img + out[:,:,2] = npy_img + + elif len(npy_img.shape) == 3: + if npy_img.shape[2] == 3 or npy_img.shape[2] == 4: + if npy_img.dtype in [np.float32, np.float64]: + out[:,:,:3] = (npy_img[:,:,:3])*255 + else: + out[:,:,:3] = npy_img[:,:,:3] + else: + raise ValueError('Image must have 1, 3, or 4 channels') + + else: + raise ValueError('Image must have 2 or 3 dimensions') + + return out \ No newline at end of file diff --git a/scikits/image/io/wxpython_plugin.py b/scikits/image/io/wxpython_plugin.py new file mode 100644 index 00000000..136577b8 --- /dev/null +++ b/scikits/image/io/wxpython_plugin.py @@ -0,0 +1,53 @@ +import numpy as np +import plugin +from _plugin_util import prepare_for_display + +try: + import wx +except ImportError: + pass +else: + + # idea shamelessly taken from here: + # http://wiki.wxpython.org/WorkingWithImages + + class ImagePanel(wx.Panel): + def __init__(self, parent, id): + wx.Panel.__init__(self, parent, id) + self.bitmap = None + self.Bind(wx.EVT_PAINT, self.OnPaint) + + def display(self, npy_img): + self.bitmap = self.get_bitmap(npy_img) + self.Refresh(True) + + def OnPaint(self, evt): + dc = wx.PaintDC(self) + if self.bitmap: + dc.DrawBitmap(self.bitmap, 0, 0) + + def get_bitmap(self, npy_img): + width = npy_img.shape[1] + height = npy_img.shape[0] + wx_img = wx.EmptyImage(width, height) + wx_img.SetData(npy_img.data) + return wx.BitmapFromImage(wx_img) + + + class ImageFrame(wx.Frame): + def __init__(self, img): + self.img = img + width = img.shape[1] + height = img.shape[0] + wx.Frame.__init__(self, None, -1, 'wx', wx.DefaultPosition, + wx.Size(width, height)) + + self.iPanel = ImagePanel(self, -1) + self.iPanel.display(self.img) + + def wx_imshow(img): + f = ImageFrame(prepare_for_display(img)) + f.CenterOnScreen() + f.Show() + + plugin.register('wx', show=wx_imshow)