Beispiel #1
0
 def __init__(self, port=ImageServer.default_port, start_server=True, *args, **kwargs):
   self.logger = logging.getLogger(self.__class__.__name__)
   self.rect = None  # selected rectangular region to serve (default: entire image)
   self.server = ImageServer(port=port, start_server=start_server)  # RPC-exports self, can start a server thread (what about other args to ImageServer?)
   if self.gui and not kwargs.get('fullscr', True):  # NOTE can't rely on self.is_Fullscr Window.__init__() hasn't been called yet
     cv2.namedWindow(self.imageWinName)  # try to open this before the pyglet window so that it doesn't steal focus
     cv2.waitKey(1)
   Window.__init__(self, *args, **kwargs)  # NOTE this likely calls flip a few times to calibrate, so we need everything to be initialized beforehand
Beispiel #2
0
class ImageServerWindow(Window):
  """A variant of psychopy.visual.Window (running on pyglet) that automatically posts screen images over RPC.
  
  Usage:
  
  # Create an ImageServerWindow (drop-in replacement for psychopy.visual.Window)
  from lumos.output import ImageServerWindow
  win = ImageServerWindow(size=(800, 600), fullscr=True, screen=0, allowGUI=False, allowStencil=False,
    monitor=u'testMonitor', color=u'black', colorSpace=u'rgb')
  ...
  win.flip()  # must call this when each frame is complete - augments original flip(), copies rendered frame for serving
  ...
  
  # You can also specify a rectangular region to serve
  win.setRect((int(win.size[0] / 4), int(win.size[1] / 4), int(win.size[0] / 2), int(win.size[1] / 2)))  # (x, y, w, h)
  
  # It's a good idea to close the window when done; this cleanly releases backend server thread
  win.close()
  """
  
  flipVertical = False  # flip image along on vertical axis to correct for upside-down error
  gui = False  # image window may steal focus; enable for debugging only
  imageWinName = "Image Server Window"
  
  def __init__(self, port=ImageServer.default_port, start_server=True, *args, **kwargs):
    self.logger = logging.getLogger(self.__class__.__name__)
    self.rect = None  # selected rectangular region to serve (default: entire image)
    self.server = ImageServer(port=port, start_server=start_server)  # RPC-exports self, can start a server thread (what about other args to ImageServer?)
    if self.gui and not kwargs.get('fullscr', True):  # NOTE can't rely on self.is_Fullscr Window.__init__() hasn't been called yet
      cv2.namedWindow(self.imageWinName)  # try to open this before the pyglet window so that it doesn't steal focus
      cv2.waitKey(1)
    Window.__init__(self, *args, **kwargs)  # NOTE this likely calls flip a few times to calibrate, so we need everything to be initialized beforehand
  
  def flip(self, clearBuffer=True):
    Window.flip(self, clearBuffer=False)  # draw everything, but don't clear buffer yet so that we can capture it
    self.updatePygletImage()  # TODO use Window._getFrame() instead? or _getRegionOfFrame?
    if clearBuffer:
      Window.clearBuffer(self)  # now that we have captured the image, clear the buffer
  
  # TODO rpc.enable this and then rpc.export(self, name='window') to allow remote calls like 'window.setRect' (similarly, window.moveRect?)
  def setRect(self, rect):
    """Set rectangular region to serve with a list/tuple/array: win.setRect((x, y, w, h))"""
    if rect is not None and len(rect) == 4:
      self.rect = rect  # TODO perform bounds checking
    else:
      self.logger.error("Invalid selection rect: {}".format(rect))
  
  def updatePygletImage(self):
    # * Grab raw image from current color buffer
    # TODO Handle FBO mode (currently assumes back color buffer is directly written to)
    rawImage = pyglet.image.get_buffer_manager().get_color_buffer().get_image_data()
    if self.rect is not None:
      rawImage = rawImage.get_region(*self.rect)  # select rectangular region
    #self.logger.debug("rawImage: width: {}, height: {}, format: {}, pitch {}".format(rawImage.width, rawImage.height, rawImage.format, rawImage.pitch))
    
    # * Get image bytes, convert to numpy array
    imageBytes = rawImage.get_data(rawImage.format, rawImage.pitch)  # returns a bytes array
    imageRGBA = np.ndarray(shape=(rawImage.height, rawImage.width, len(rawImage.format)), buffer=imageBytes, dtype=np.uint8, strides=(rawImage.pitch, len(rawImage.format), 1))
    
    # * Convert array to desired format (assuming raw image is RGBA and we want BGR)
    # ** Method 1: Slice out the first 3 color channels (RGB), convert RGB to BGR
    # NOTE: OpenCV chokes on the result when trying to display (or do anything else), if source image was actually 4-channel (strides issue?)
    #imageRGB = imageRGBA[:, :, 0:3]
    #self.logger.debug("imageRGB: shape: {}, dtype: {}, min: {}, max: {}".format(imageRGB.shape, imageRGB.dtype, np.min(imageRGB), np.max(imageRGB)))
    #imageBGR = cv2.cvtColor(imageRGB, cv.CV_RGB2BGR)
    # ** Method 2: Split color channels, dropping alpha, and recombine in desired order
    imageR, imageG, imageB, _ = cv2.split(imageRGBA)
    imageBGR = cv2.merge((imageB, imageG, imageR))
    if self.flipVertical:
      imageBGR = cv2.flip(imageBGR, 0)
    
    # Cache latest image for serving; optionally, display it
    self.server.write(imageBGR)
    if self.gui and not self._isFullScr:
        cv2.imshow(self.imageWinName, imageBGR)
        cv2.waitKey(1)  # NOTE: OpenCV window doesn't show up without this, even though pyglet is running (why?)
  
  def close(self):
    self.server.stop()
    Window.close(self)