Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import wx
- import wx.glcanvas
- import numpy
- def makeWindow():
- global window
- window = ViewerWindow(None, tileShape = (3, 3), tileSize = 512)
- # Generate a test image to display -- a sequence of squares.
- width = 2056
- height = 2548
- data = numpy.zeros((width, height), dtype = numpy.uint16)
- base = 0
- for i in xrange(0, width, 512):
- for j in xrange(0, height, 512):
- data[i:i+512, j:j+512] = base
- base += 50
- # Downsample to make the image reasonably displayable on a normal monitor.
- window.viewer.setImage(data[::2, ::2])
- class App(wx.App):
- def OnInit(self):
- makeWindow()
- return True
- from OpenGL.GL import *
- ## Simple window that contains a GLViewer instance.
- class ViewerWindow(wx.Frame):
- def __init__(self, parent, tileShape, tileSize, *args, **kwargs):
- wx.Frame.__init__(self, parent, *args, **kwargs)
- self.viewer = GLViewer(self, tileShape, tileSize, **kwargs)
- self.Show()
- self.Bind(wx.EVT_SIZE, self.onSize)
- def onSize(self, event):
- self.viewer.setSize(list(self.GetSize()))
- event.Skip()
- class GLViewer(wx.glcanvas.GLCanvas):
- ## Instantiate.
- def __init__(self, parent, tileShape, tileSize, *args, **kwargs):
- wx.glcanvas.GLCanvas.__init__(self, parent, *args, **kwargs)
- ## Edge length of one tile.
- self.tileSize = tileSize
- ## Shape of our tile grid.
- self.tileShape = tileShape
- ## 2D array of Image instances. We'll create these when we get
- # some image data to work with.
- self.tiles = []
- ## Whether or not we've done some one-time initialization work.
- self.haveInitedGL = False
- self.scaleX = self.scaleY = 1.0
- wx.EVT_PAINT(self, self.OnPaint)
- def InitGL(self):
- self.w, self.h = self.GetClientSizeTuple()
- self.SetCurrent()
- glClearColor(0.3, 0.3, 0.3, 0.0) ## background color
- self.haveInitedGL = True
- ## Receive a new image and parcel it up into our smaller Image instances.
- # Create those instances at this time if we don't have them already.
- def setImage(self, newImage):
- self.SetCurrent()
- print "Updating new image to one of shape",newImage.shape
- # Ensure that we have the right amount of data to put into our
- # Images, by filling in any missing data with zeros. There's an
- # implicit assumption here that newImage is smaller than or
- # equal in size to our tiles' total combined area.
- width = self.tileShape[0] * self.tileSize
- height = self.tileShape[1] * self.tileSize
- paddedImage = numpy.zeros((width, height), dtype = newImage.dtype)
- paddedImage[:newImage.shape[0], :newImage.shape[1]] = newImage
- print "Made padded image of shape",paddedImage.shape
- for i in xrange(self.tileShape[0]):
- self.tiles.append([])
- for j in xrange(self.tileShape[1]):
- subData = paddedImage[
- i * self.tileSize : (i + 1) * self.tileSize,
- j * self.tileSize : (j + 1) * self.tileSize]
- self.tiles[i].append(Image(subData))
- wx.CallAfter(self.changeHistScale, newImage.min(), newImage.max())
- self.Refresh()
- ## Rescale our images so smin displays as black and smax as white.
- def changeHistScale(self, smin ,smax):
- for i in xrange(self.tileShape[0]):
- for j in xrange(self.tileShape[1]):
- self.tiles[i][j].refresh(smin, smax)
- self.Refresh(False)
- def setSize(self, size):
- xSize = float(self.tileShape[0] * self.tileSize)
- ySize = float(self.tileShape[1] * self.tileSize)
- self.scaleX = size[0] / xSize
- self.scaleY = size[1] / ySize
- self.w, self.h = size
- self.Refresh(0)
- def OnPaint(self, event):
- try:
- dc = wx.PaintDC(self)
- except:
- return
- if not self.haveInitedGL:
- self.InitGL()
- self.SetCurrent()
- glViewport(0, 0, self.w, self.h)
- glMatrixMode (GL_PROJECTION)
- glLoadIdentity ()
- glOrtho (0, self.w, 0, self.h, 1., -1.)
- glMatrixMode (GL_MODELVIEW)
- glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
- glPushMatrix()
- glLoadIdentity()
- glScalef(self.scaleX, self.scaleY, 1)
- glEnable(GL_TEXTURE_2D)
- for i in xrange(self.tileShape[0]):
- for j in xrange(self.tileShape[1]):
- glPushMatrix()
- glTranslatef(i * self.tileSize, j * self.tileSize, 0)
- self.tiles[i][j].render()
- glPopMatrix()
- glDisable(GL_TEXTURE_2D)
- glPopMatrix()
- glFlush()
- self.SwapBuffers()
- import OpenGL.GL as GL
- ## This class handles display of a single 2D array of pixel data.
- class Image:
- def __init__(self, imageData):
- self.imageData = imageData
- self.bindTexture()
- def bindTexture(self):
- pic_ny, pic_nx = self.imageData.shape
- # Generate texture sizes that are powers of 2
- tex_nx = 2
- while tex_nx < pic_nx:
- tex_nx *= 2
- tex_ny = 2
- while tex_ny < pic_ny:
- tex_ny *= 2
- self.picTexRatio_x = float(pic_nx) / tex_nx
- self.picTexRatio_y = float(pic_ny) / tex_ny
- self.textureID = GL.glGenTextures(1)
- GL.glBindTexture(GL.GL_TEXTURE_2D, self.textureID)
- # Define this new texture object based on self.imageData's geometry
- GL.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER,
- GL.GL_NEAREST)
- GL.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER,
- GL.GL_NEAREST)
- imgType = self.imageData.dtype.type
- GL.glTexImage2D(GL.GL_TEXTURE_2D,0, GL.GL_RGB, tex_nx,tex_ny, 0,
- GL.GL_LUMINANCE, GL.GL_UNSIGNED_SHORT, None)
- # Re-load our image data onto the card, e.g. because our blackpoint and
- # whitepoint have changed.
- def refresh(self, imageMin, imageMax):
- minMaxRange = float(imageMax - imageMin)
- if abs(imageMax - imageMin) < 1:
- minMaxRange = 1
- imgType = self.imageData.dtype.type
- fBias = -imageMin / minMaxRange
- f = ((1 << 16) - 1) / minMaxRange
- GL.glBindTexture(GL.GL_TEXTURE_2D, self.textureID)
- GL.glPixelTransferf(GL.GL_RED_SCALE, f)
- GL.glPixelTransferf(GL.GL_GREEN_SCALE, f)
- GL.glPixelTransferf(GL.GL_BLUE_SCALE, f)
- GL.glPixelTransferf(GL.GL_RED_BIAS, fBias)
- GL.glPixelTransferf(GL.GL_GREEN_BIAS, fBias)
- GL.glPixelTransferf(GL.GL_BLUE_BIAS, fBias)
- GL.glPixelTransferf(GL.GL_MAP_COLOR, False)
- GL.glPixelStorei(GL.GL_UNPACK_SWAP_BYTES,
- not self.imageData.dtype.isnative)
- GL.glPixelStorei(GL.GL_UNPACK_ALIGNMENT, self.imageData.itemsize)
- imgString = self.imageData.tostring()
- pic_ny, pic_nx = self.imageData.shape
- GL.glTexSubImage2D(GL.GL_TEXTURE_2D, 0, 0, 0, pic_nx, pic_ny,
- GL.GL_LUMINANCE, GL.GL_UNSIGNED_SHORT, imgString)
- def render(self):
- cx,cy = self.imageData.shape[-1]/2., self.imageData.shape[-2]/2.
- GL.glBindTexture(GL.GL_TEXTURE_2D, self.textureID)
- GL.glBegin(GL.GL_QUADS)
- pic_ny, pic_nx = self.imageData.shape
- ###//(0,0) at left bottom
- GL.glTexCoord2f(0, 0)
- GL.glVertex2i(0, 0)
- GL.glTexCoord2f(self.picTexRatio_x, 0)
- GL.glVertex2i(pic_nx, 0)
- GL.glTexCoord2f(self.picTexRatio_x, self.picTexRatio_y)
- GL.glVertex2i(pic_nx, pic_ny)
- GL.glTexCoord2f(0, self.picTexRatio_y)
- GL.glVertex2i(0, pic_ny)
- GL.glEnd()
- app = App(redirect = False)
- app.MainLoop()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement