Advertisement
Guest User

Untitled

a guest
Jun 2nd, 2011
123
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 9.16 KB | None | 0 0
  1. import numpy
  2. from OpenGL.GL import *
  3. import threading
  4. import wx
  5. import wx.glcanvas
  6.  
  7. import numpy
  8. import OpenGL.GL as GL
  9. import threading
  10.  
  11. ## Maps numpy datatypes to OpenGL datatypes
  12. dtypeToGlTypeMap = {
  13.     numpy.uint8: GL.GL_UNSIGNED_BYTE,
  14.     numpy.uint16: GL.GL_UNSIGNED_SHORT,
  15.     numpy.int16: GL.GL_SHORT,
  16.     numpy.float32: GL.GL_FLOAT,
  17.     numpy.float64: GL.GL_FLOAT,
  18.     numpy.int32: GL.GL_FLOAT,
  19.     numpy.uint32: GL.GL_FLOAT,
  20.     numpy.complex64: GL.GL_FLOAT,
  21.     numpy.complex128: GL.GL_FLOAT,
  22. }
  23.  
  24. ## Maps numpy datatypes to the maximum value the datatype can represent
  25. dtypeToMaxValMap = {
  26.     numpy.uint16: (1 << 16) - 1,
  27.     numpy.int16: (1 << 15) - 1,
  28.     numpy.uint8: (1 << 8) - 1,
  29.     numpy.bool_: (1 << 8) - 1,
  30.     numpy.float32: 1
  31. }
  32.  
  33. ## This class handles display of a single 2D array of pixel data.
  34. class Image:
  35.     def __init__(self):
  36.         self.imageData = None
  37.         self.imageMin = None
  38.         self.imageMax = None
  39.         self.textureID = None
  40.         self.color = (1, 1, 1)
  41.         self.lock = threading.Lock()
  42.        
  43.         self.bindTexture()
  44.         self.refresh()
  45.  
  46.     def bindTexture(self):
  47.         if self.imageData is None:
  48.             return
  49.         self.lock.acquire()
  50.         pic_ny, pic_nx = self.imageData.shape
  51.  
  52.         if self.imageMin == 0 and self.imageMax == 0:
  53.             self.imageMin = self.imageData.min()
  54.             self.imageMax = self.imageData.max()
  55.  
  56.         # Generate texture sizes that are powers of 2
  57.         tex_nx = 2
  58.         while tex_nx < pic_nx:
  59.             tex_nx *= 2
  60.         tex_ny = 2
  61.         while tex_ny < pic_ny:
  62.             tex_ny *= 2
  63.  
  64.         self.picTexRatio_x = float(pic_nx) / tex_nx
  65.         self.picTexRatio_y = float(pic_ny) / tex_ny
  66.  
  67.         self.textureID = GL.glGenTextures(1)
  68.         GL.glBindTexture(GL.GL_TEXTURE_2D, self.textureID)
  69.  
  70.         # Define this new texture object based on self.imageData's geometry
  71.         GL.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER,
  72.                 GL.GL_NEAREST)
  73.         GL.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER,
  74.                 GL.GL_NEAREST)
  75.  
  76.         imgType = self.imageData.dtype.type
  77.         if imgType not in dtypeToGlTypeMap:
  78.             raise ValueError, "Unsupported data mode %s" % str(imgType)
  79.         GL.glTexImage2D(GL.GL_TEXTURE_2D,0,  GL.GL_RGB, tex_nx,tex_ny, 0,
  80.                      GL.GL_LUMINANCE, dtypeToGlTypeMap[imgType], None)
  81.         self.lock.release()
  82.  
  83.     def refresh(self):
  84.         if self.imageData is None:
  85.             return
  86.         self.bindTexture()
  87.         minMaxRange = float(self.imageMax - self.imageMin)
  88.         if abs(self.imageMax - self.imageMin) < 1:
  89.             minMaxRange = 1
  90.  
  91.         imgType = self.imageData.dtype.type
  92.         fBias = -self.imageMin / minMaxRange
  93.         f = dtypeToMaxValMap[imgType] / minMaxRange
  94.        
  95.         GL.glBindTexture(GL.GL_TEXTURE_2D, self.textureID)
  96.  
  97.         GL.glPixelTransferf(GL.GL_RED_SCALE,   f)
  98.         GL.glPixelTransferf(GL.GL_GREEN_SCALE, f)
  99.         GL.glPixelTransferf(GL.GL_BLUE_SCALE,  f)
  100.  
  101.         GL.glPixelTransferf(GL.GL_RED_BIAS,   fBias)
  102.         GL.glPixelTransferf(GL.GL_GREEN_BIAS, fBias)
  103.         GL.glPixelTransferf(GL.GL_BLUE_BIAS,  fBias)
  104.  
  105.         GL.glPixelTransferf(GL.GL_MAP_COLOR, False)
  106.  
  107.         GL.glPixelStorei(GL.GL_UNPACK_SWAP_BYTES,
  108.                 not self.imageData.dtype.isnative)
  109.         GL.glPixelStorei(GL.GL_UNPACK_ALIGNMENT, self.imageData.itemsize)
  110.        
  111.         imgString = self.imageData.tostring()
  112.  
  113.         pic_ny, pic_nx = self.imageData.shape
  114.  
  115.         if imgType not in dtypeToGlTypeMap:
  116.             raise ValueError, "Unsupported data mode %s" % str(imgType)
  117.         GL.glTexSubImage2D(GL.GL_TEXTURE_2D, 0, 0, 0, pic_nx, pic_ny,
  118.                 GL.GL_LUMINANCE, dtypeToGlTypeMap[imgType], imgString)
  119.  
  120.  
  121.     def render(self):
  122.         if self.imageData is None or self.textureID is None:
  123.             return
  124.         self.refresh()
  125.        
  126.         GL.glPushMatrix()
  127.  
  128.         GL.glColor3fv(self.color)
  129.        
  130.         GL.glBindTexture(GL.GL_TEXTURE_2D, self.textureID)
  131.  
  132.         GL.glBegin(GL.GL_QUADS)
  133.        
  134.         pic_ny, pic_nx = self.imageData.shape
  135.  
  136.         ###//(0,0) at left bottom
  137.         GL.glTexCoord2f(0, 0)
  138.         GL.glVertex2i(0, 0)
  139.            
  140.         GL.glTexCoord2f(self.picTexRatio_x, 0)
  141.         GL.glVertex2i(pic_nx, 0)
  142.            
  143.         GL.glTexCoord2f(self.picTexRatio_x, self.picTexRatio_y)
  144.         GL.glVertex2i(pic_nx, pic_ny)
  145.            
  146.         GL.glTexCoord2f(0, self.picTexRatio_y)
  147.         GL.glVertex2i(0, pic_ny)
  148.  
  149.         GL.glEnd()
  150.         GL.glPopMatrix()
  151.  
  152.  
  153.     ## Free the allocated GL texture
  154.     def wipe(self):
  155.         self.lock.acquire()
  156.         if self.textureID is not None:
  157.             GL.glDeleteTextures(self.textureID)
  158.         self.textureID = None
  159.         self.lock.release()
  160.    
  161.  
  162.     ## Accept a new array of image data.
  163.     def updateImage(self, imageData, imageMin, imageMax):
  164.         self.imageData = imageData
  165.         self.imageMin = imageMin
  166.         self.imageMax = imageMax
  167.  
  168.         self.wipe()
  169.         self.refresh()
  170.  
  171.  
  172.  
  173. colors = [(255, 0, 0), (0, 255, 0), (0, 0, 255)]
  174.  
  175.  
  176. ## Simple window that contains a GLViewer instance.
  177. class ViewerWindow(wx.Frame):
  178.     def __init__(self, parent, **kwargs):
  179.         title = "Multi-wavelength view"
  180.         wx.Frame.__init__(self, parent, title = title,
  181.                 style = wx.DEFAULT_FRAME_STYLE)
  182.  
  183.         sizer = wx.BoxSizer(wx.VERTICAL)
  184.         self.viewer = GLViewer(self, size = (512, 512), **kwargs)
  185.  
  186.         sizer.Add(self.viewer)
  187.         self.SetSizerAndFit(sizer)
  188.  
  189.         ## This lock prevents us from trying to update more than one
  190.         # viewer at a time, evading some OpenGL errors.
  191.         self.lock = threading.Lock()
  192.  
  193.         self.Show()
  194.  
  195.  
  196.     ## Display a new image in the viewer, or hide the viewer if it's
  197.     # been disconnected.
  198.     def processNewImage(self, camId):
  199.         if not self.viewer.haveInitedGL:
  200.             return
  201.         self.lock.acquire()
  202.  
  203.         data = numpy.random.random_integers(0, 10, (512, 512)).astype(numpy.uint16)
  204.  
  205.         self.viewer.updateImage(camId, data, 0, 10)
  206.  
  207.         color = colors[camId]
  208.         # Remap from [0, 255] to [0, 1]
  209.         color = [c / 255.0 for c in color]
  210.         self.viewer.setColor(camId, color, False)
  211.  
  212.         self.viewer.Refresh()
  213.        
  214.         self.lock.release()
  215.            
  216.  
  217.  
  218. ## OpenGL canvas for displaying multiple camera views layered on top of each
  219. # other.
  220. class GLViewer(wx.glcanvas.GLCanvas):
  221.     ## Instantiate.
  222.     def __init__(self, parent,
  223.                  style = 0, size = wx.DefaultSize):
  224.         wx.glcanvas.GLCanvas.__init__(self, parent, style = style, size = size)
  225.  
  226.         ## List of Image instances
  227.         self.imgList = []
  228.         for i in xrange(3):
  229.             self.imgList.append(Image())
  230.  
  231.         ## Whether or not we've done some one-time initialization work.
  232.         self.haveInitedGL = False
  233.  
  234.         wx.EVT_PAINT(self, self.OnPaint)
  235.         # Do nothing on background erasure, to avoid flickering.
  236.         wx.EVT_ERASE_BACKGROUND(self, lambda event: event)
  237.    
  238.        
  239.     def InitGL(self):
  240.         self.w, self.h = self.GetClientSizeTuple()
  241.         self.SetCurrent()
  242.         glClearColor(0.3, 0.3, 0.3, 0.0)   ## background color
  243.  
  244.         self.haveInitedGL = True
  245.  
  246.  
  247.     def updateImage(self, index, data, imageMin, imageMax):
  248.         self.pic_ny, self.pic_nx = data.shape
  249.         self.imgList[index].updateImage(data, imageMin, imageMax)
  250.  
  251.  
  252.     def setColor(self, imgidx, color, RefreshNow=1):
  253.         self.imgList[imgidx].color = color
  254.         if RefreshNow:
  255.             self.Refresh(0)
  256.            
  257.  
  258.     def OnPaint(self, event):
  259.         try:
  260.             dc = wx.PaintDC(self)
  261.         except:
  262.             return
  263.  
  264.         if not self.haveInitedGL:
  265.             self.InitGL()
  266.            
  267.         self.SetCurrent()
  268.  
  269.         glViewport(0, 0, self.w, self.h)
  270.         glMatrixMode (GL_PROJECTION)
  271.         glLoadIdentity ()
  272.         glOrtho (0, self.w, 0, self.h, 1., -1.)
  273.         glMatrixMode (GL_MODELVIEW)
  274.         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
  275.         glPushMatrix()
  276.         glLoadIdentity()
  277.  
  278.         glEnable(GL_TEXTURE_2D)
  279.         glEnable(GL_BLEND)
  280.         glBlendFunc(GL_ONE, GL_ONE)
  281.  
  282.         for image in self.imgList:
  283.             if image.imageData is not None:
  284.                 image.render()
  285.  
  286.         glDisable(GL_TEXTURE_2D)
  287.         glDisable(GL_BLEND)
  288.  
  289.         glFlush()
  290.         glPopMatrix()
  291.         self.SwapBuffers()
  292.  
  293.  
  294.     def OnReload(self, event=None):
  295.         self.Refresh(False)
  296.  
  297.  
  298. app = wx.App(False)
  299. window = ViewerWindow(None)
  300.  
  301. import time
  302. def eventSpammer():
  303.     while True:
  304.         for i in xrange(3):
  305.             event = wx.CommandEvent(wx.wxEVT_COMMAND_BUTTON_CLICKED, i)
  306.             wx.PostEvent(window, event)
  307.         time.sleep(.05)
  308.  
  309.  
  310. def onNewImageReady(event):
  311.     window.processNewImage(event.GetId())
  312.  
  313. # Listen to events
  314. for i in xrange(3):
  315.     wx.EVT_BUTTON(window, i, onNewImageReady)
  316. print "Event listeners started"
  317.  
  318. threading.Thread(target = eventSpammer).start()
  319. print "Spammer started"
  320. app.MainLoop()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement