def __init__( self, config = SubControllerConfig() ): self.robotType = config.robotType self.tracker = ColourTracker() self.tracker.setTrackedHue( config.trackedHue, config.maxAbsHueDiff ) self.tracker.setTrackedSaturation( config.trackedSaturation, config.maxAbsSaturationDiff ) self.tracker.setTrackedValue( config.trackedValue, config.maxAbsValueDiff ) self.frame = None self.lastTurnDirection = self.LEFT self.forwardSpeed = config.forwardSpeed self.absYawSpeed = abs( config.yawSpeed ) self.screenRadiusOfCloseBuoy = config.screenRadiusOfCloseBuoy self.lastCameraFrameTime = 0.0 # Create a client object self.playerClient = playerc_client( None, config.playerServerAddress, config.playerServerPort ) # Connect it if self.playerClient.connect() != 0: raise playerc_error_str() # Create a proxy for position3d:0 self.playerPos3d = playerc_position3d( self.playerClient, 0 ) if self.playerPos3d.subscribe( PLAYERC_OPEN_MODE ) != 0: raise playerc_error_str() self.playerCamera = playerc_camera( self.playerClient, 0 ) if self.playerCamera.subscribe( PLAYERC_OPEN_MODE ) != 0: raise playerc_error_str() if self.playerClient.datamode( PLAYERC_DATAMODE_PULL ) != 0: raise playerc_error_str() if self.playerClient.set_replace_rule( -1, -1, PLAYER_MSGTYPE_DATA, -1, 1 ) != 0: raise playerc_error_str() print "Connected to Player!"
class SubController: LEFT = "Left" RIGHT = "Right" #--------------------------------------------------------------------------- def __init__( self, config = SubControllerConfig() ): self.robotType = config.robotType self.tracker = ColourTracker() self.tracker.setTrackedHue( config.trackedHue, config.maxAbsHueDiff ) self.tracker.setTrackedSaturation( config.trackedSaturation, config.maxAbsSaturationDiff ) self.tracker.setTrackedValue( config.trackedValue, config.maxAbsValueDiff ) self.frame = None self.lastTurnDirection = self.LEFT self.forwardSpeed = config.forwardSpeed self.absYawSpeed = abs( config.yawSpeed ) self.screenRadiusOfCloseBuoy = config.screenRadiusOfCloseBuoy self.lastCameraFrameTime = 0.0 # Create a client object self.playerClient = playerc_client( None, config.playerServerAddress, config.playerServerPort ) # Connect it if self.playerClient.connect() != 0: raise playerc_error_str() # Create a proxy for position3d:0 self.playerPos3d = playerc_position3d( self.playerClient, 0 ) if self.playerPos3d.subscribe( PLAYERC_OPEN_MODE ) != 0: raise playerc_error_str() self.playerCamera = playerc_camera( self.playerClient, 0 ) if self.playerCamera.subscribe( PLAYERC_OPEN_MODE ) != 0: raise playerc_error_str() if self.playerClient.datamode( PLAYERC_DATAMODE_PULL ) != 0: raise playerc_error_str() if self.playerClient.set_replace_rule( -1, -1, PLAYER_MSGTYPE_DATA, -1, 1 ) != 0: raise playerc_error_str() print "Connected to Player!" #--------------------------------------------------------------------------- def __del__( self ): self.shutdown() #--------------------------------------------------------------------------- def shutdown( self ): if self.playerCamera != None: self.playerCamera.unsubscribe() if self.playerPos3d != None: self.playerPos3d.unsubscribe() if self.playerClient != None: self.playerClient.disconnect() #--------------------------------------------------------------------------- #@Profiling.printTiming def getImage( self ): self.lastCameraFrameTime = self.playerCamera.info.datatime if self.playerCamera.compression != PLAYER_CAMERA_COMPRESS_RAW: self.playerCamera.decompress() if self.playerCamera.compression != PLAYER_CAMERA_COMPRESS_RAW: print( "Error: Unable to decompress frame" ); return None cvImage = cv.CreateImageHeader( ( self.playerCamera.width, self.playerCamera.height ), cv.IPL_DEPTH_8U, 3 ) cv.SetData( cvImage, self.playerCamera.image[:self.playerCamera.image_count], self.playerCamera.width*3 ) return cvImage #--------------------------------------------------------------------------- def update( self ): newFrameAvailable = False if self.playerClient.peek( 0 ): self.playerClient.read() if self.isNewFrameAvailable(): self.getAndProcessFrame() newFrameAvailable = True forwardSpeed = 0.0 yawSpeed = 0.0 blobData = self.tracker.getBlobData() if blobData.visible: halfFrameWidth = self.frame.width / 2.0 radiusOfCloseBuoy = self.screenRadiusOfCloseBuoy*self.frame.width if blobData.centreX < halfFrameWidth * 0.9: command = "Go Left" yawSpeed = self.absYawSpeed self.lastTurnDirection = self.LEFT elif blobData.centreX > halfFrameWidth * 1.1: command = "Go Right" yawSpeed = -self.absYawSpeed self.lastTurnDirection = self.RIGHT else: if blobData.radius < radiusOfCloseBuoy: command = "Go Forward" forwardSpeed = self.forwardSpeed else: command = "Stay Still" print "Buoy Visible at ( " + str( blobData.centreX ) + ", " + str( blobData.centreY ) + " ) - " + command else: print "Can't see buoy - turning " + self.lastTurnDirection.lower() # Turn to search for the buoy if self.lastTurnDirection == self.LEFT: yawSpeed = self.absYawSpeed else: yawSpeed = -self.absYawSpeed # Steer the AUV if self.playerPos3d != None: self.playerPos3d.set_velocity( forwardSpeed, 0.0, 0.0, # x, y, z 0.0, 0.0, yawSpeed, # roll, pitch, yaw 0 ) # State return newFrameAvailable #--------------------------------------------------------------------------- def isNewFrameAvailable( self ): return self.lastCameraFrameTime != self.playerCamera.info.datatime #--------------------------------------------------------------------------- @Profiling.printTiming def getAndProcessFrame( self ): self.frame = self.getImage() self.processedFrameData = self.tracker.processFrame( self.frame )
def __init__( self, config = SubControllerConfig() ): self.displayPixBuf = None self.lastCameraFrameTime = 0.0 self.frameNumber = 0 self.displayOriginX = 150 self.displayOriginY = 200 self.displayScale = 100 self.draggingDisplay = False self.lastDragPos = None self.subPos = None self.subHeading = None self.subState = self.SUB_STATE_MOVING_TO_GATE self.robotType = config.robotType self.tracker = ColourTracker() self.tracker.setTrackedHue( config.trackedHue, config.maxAbsHueDiff ) self.tracker.setTrackedSaturation( config.trackedSaturation, config.maxAbsSaturationDiff ) self.tracker.setTrackedValue( config.trackedValue, config.maxAbsValueDiff ) self.lastTurnDirection = self.LEFT self.forwardSpeed = config.forwardSpeed self.absYawSpeed = abs( config.yawSpeed ) self.screenRadiusOfCloseBuoy = config.screenRadiusOfCloseBuoy self.connectToPlayer() # Get map # Get the position of the Buoy buoyPose = self.playerSim.get_pose2d( "Buoy" ) if buoyPose[ 0 ] == 0: self.buoyPos = Vector2D( buoyPose[ 1 ], buoyPose[ 2 ] ) else: print "Warning: Unable to get Buoy pose" # Get the position of the Gate gatePose = self.playerSim.get_pose2d( "Gate" ) if gatePose[ 0 ] == 0: GATE_WIDTH = 0.9 HALF_GATE_WIDTH = GATE_WIDTH / 2.0 # We can only deal with point features so enter the # gate posts as two separate entities sinAngle = math.sin( gatePose[ 3 ] ) cosAngle = math.cos( gatePose[ 3 ] ) leftGateX = gatePose[ 1 ] - HALF_GATE_WIDTH*cosAngle leftGateY = gatePose[ 2 ] - HALF_GATE_WIDTH*sinAngle rightGateX = gatePose[ 1 ] + HALF_GATE_WIDTH*cosAngle rightGateY = gatePose[ 2 ] + HALF_GATE_WIDTH*sinAngle self.leftGatePos = Vector2D( leftGateX, leftGateY ) self.rightGatePos = Vector2D( rightGateX, rightGateY ) else: print "Warning: Unable to get Gate pose" self.fixedLandmarks = [ self.buoyPos, self.leftGatePos, self.rightGatePos ] self.gateTargetPos = (self.leftGatePos + self.rightGatePos)/2.0 + Vector2D( -0.25, 0.0 ) # Setup the GUI builder = gtk.Builder() builder.add_from_file( os.path.dirname( __file__ ) + "/BRLControl.glade" ) self.window = builder.get_object( "winMain" ) self.dwgDisplay = builder.get_object( "dwgDisplay" ) self.dwgMap = builder.get_object( "dwgMap" ) self.tbxOutputFile = builder.get_object( "tbxOutputFile" ) builder.connect_signals( self ) self.window.show() updateLoop = self.update() gobject.idle_add( updateLoop.next )
class MainWindow: PLAYER_SERVER_ADDRESS = 'localhost' PLAYER_SERVER_PORT = 6665 SCALE_UP = 1.25 SCALE_DOWN = 1.0 / SCALE_UP MIN_SCALE = 10.0 MAX_SCALE = 1000000.0 SUB_STATE_MOVING_TO_BUOY = "MovingToBuoy" SUB_STATE_MOVING_TO_GATE = "MovingToGate" LEFT = "Left" RIGHT = "Right" #--------------------------------------------------------------------------- def __init__( self, config = SubControllerConfig() ): self.displayPixBuf = None self.lastCameraFrameTime = 0.0 self.frameNumber = 0 self.displayOriginX = 150 self.displayOriginY = 200 self.displayScale = 100 self.draggingDisplay = False self.lastDragPos = None self.subPos = None self.subHeading = None self.subState = self.SUB_STATE_MOVING_TO_GATE self.robotType = config.robotType self.tracker = ColourTracker() self.tracker.setTrackedHue( config.trackedHue, config.maxAbsHueDiff ) self.tracker.setTrackedSaturation( config.trackedSaturation, config.maxAbsSaturationDiff ) self.tracker.setTrackedValue( config.trackedValue, config.maxAbsValueDiff ) self.lastTurnDirection = self.LEFT self.forwardSpeed = config.forwardSpeed self.absYawSpeed = abs( config.yawSpeed ) self.screenRadiusOfCloseBuoy = config.screenRadiusOfCloseBuoy self.connectToPlayer() # Get map # Get the position of the Buoy buoyPose = self.playerSim.get_pose2d( "Buoy" ) if buoyPose[ 0 ] == 0: self.buoyPos = Vector2D( buoyPose[ 1 ], buoyPose[ 2 ] ) else: print "Warning: Unable to get Buoy pose" # Get the position of the Gate gatePose = self.playerSim.get_pose2d( "Gate" ) if gatePose[ 0 ] == 0: GATE_WIDTH = 0.9 HALF_GATE_WIDTH = GATE_WIDTH / 2.0 # We can only deal with point features so enter the # gate posts as two separate entities sinAngle = math.sin( gatePose[ 3 ] ) cosAngle = math.cos( gatePose[ 3 ] ) leftGateX = gatePose[ 1 ] - HALF_GATE_WIDTH*cosAngle leftGateY = gatePose[ 2 ] - HALF_GATE_WIDTH*sinAngle rightGateX = gatePose[ 1 ] + HALF_GATE_WIDTH*cosAngle rightGateY = gatePose[ 2 ] + HALF_GATE_WIDTH*sinAngle self.leftGatePos = Vector2D( leftGateX, leftGateY ) self.rightGatePos = Vector2D( rightGateX, rightGateY ) else: print "Warning: Unable to get Gate pose" self.fixedLandmarks = [ self.buoyPos, self.leftGatePos, self.rightGatePos ] self.gateTargetPos = (self.leftGatePos + self.rightGatePos)/2.0 + Vector2D( -0.25, 0.0 ) # Setup the GUI builder = gtk.Builder() builder.add_from_file( os.path.dirname( __file__ ) + "/BRLControl.glade" ) self.window = builder.get_object( "winMain" ) self.dwgDisplay = builder.get_object( "dwgDisplay" ) self.dwgMap = builder.get_object( "dwgMap" ) self.tbxOutputFile = builder.get_object( "tbxOutputFile" ) builder.connect_signals( self ) self.window.show() updateLoop = self.update() gobject.idle_add( updateLoop.next ) #--------------------------------------------------------------------------- def connectToPlayer( self ): try: # Create a client object to connect to Player self.playerClient = playerc_client( None, self.PLAYER_SERVER_ADDRESS, self.PLAYER_SERVER_PORT ) # Connect it if self.playerClient.connect() != 0: raise Exception( playerc_error_str() ) # Create a proxy for simulation:0 self.playerSim = playerc_simulation( self.playerClient, 0 ) if self.playerSim.subscribe( PLAYERC_OPEN_MODE ) != 0: raise Exception( playerc_error_str() ) # And for the camera self.playerCamera = playerc_camera( self.playerClient, 0 ) if self.playerCamera.subscribe( PLAYERC_OPEN_MODE ) != 0: raise Exception( playerc_error_str() ) # Create a proxy for position3d.0 self.playerPos3d = playerc_position3d( self.playerClient, 0 ) if self.playerPos3d.subscribe( PLAYERC_OPEN_MODE ) != 0: raise Exception( playerc_error_str() ) if self.playerClient.datamode( PLAYERC_DATAMODE_PULL ) != 0: raise Exception( playerc_error_str() ) if self.playerClient.set_replace_rule( -1, -1, PLAYER_MSGTYPE_DATA, -1, 1 ) != 0: raise Exception( playerc_error_str() ) except Exception as e: self.ShowErrorMessage( "Exception when connecting to Player - " + str( e ) ) sys.exit( -1 ) print "Connected to Player!" #--------------------------------------------------------------------------- def onMainWinDestroy( self, widget, data = None ): gtk.main_quit() #--------------------------------------------------------------------------- def main( self ): # All PyGTK applications must have a gtk.main(). Control ends here # and waits for an event to occur (like a key press or mouse event). gtk.main() #--------------------------------------------------------------------------- def ShowErrorMessage( self, msg ): dialog = gtk.MessageDialog( parent=None, flags=gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, type=gtk.MESSAGE_ERROR, buttons=gtk.BUTTONS_OK, message_format=msg ) dialog.set_title( "Error" ) dialog.run() dialog.destroy() #--------------------------------------------------------------------------- def onDwgDisplayExposeEvent( self, widget, event ): if self.displayPixBuf != None: imgRect = self.getImageRectangleInWidget( widget, self.displayPixBuf.get_width(), self.displayPixBuf.get_height() ) imgOffsetX = imgRect.x imgOffsetY = imgRect.y # Get the total area that needs to be redrawn imgRect = imgRect.intersect( event.area ) srcX = imgRect.x - imgOffsetX srcY = imgRect.y - imgOffsetY widget.window.draw_pixbuf( widget.get_style().fg_gc[ gtk.STATE_NORMAL ], self.displayPixBuf, srcX, srcY, imgRect.x, imgRect.y, imgRect.width, imgRect.height ) #--------------------------------------------------------------------------- def onDwgMapExposeEvent( self, widget, event ): (windowWidth, windowHeight) = widget.window.get_size() originX = self.displayOriginX originY = self.displayOriginY scaleX = self.displayScale scaleY = -self.displayScale graphicsContext = widget.window.new_gc() graphicsContext.set_rgb_fg_color( gtk.gdk.Color( 65535, 65535, 65535 ) ) widget.window.draw_rectangle( graphicsContext, filled=True, x=0, y=0, width=windowWidth, height=windowHeight ) # Draw the landmarks for fixedLandmark in self.fixedLandmarks: x = int( originX + scaleX*fixedLandmark.x ) y = int( originY + scaleY*fixedLandmark.y ) innerRadius = 0.05*scaleX outerRadius = 0.25*scaleX graphicsContext.set_rgb_fg_color( gtk.gdk.Color( 0, 0, 0 ) ) self.drawCircle( widget.window, graphicsContext, x, y, innerRadius, filled = True ) graphicsContext.set_rgb_fg_color( gtk.gdk.Color( 65535/2, 65535/2, 65535/2 ) ) self.drawCircle( widget.window, graphicsContext, x, y, outerRadius, filled = False ) # Draw the AUV if self.subPos != None: graphicsContext.set_rgb_fg_color( gtk.gdk.Color( 0, 0, 0 ) ) subRenderPos = ( originX + scaleX*self.subPos.x, originY + scaleY*self.subPos.y ) self.drawCircle( widget.window, graphicsContext, subRenderPos[ 0 ], subRenderPos[ 1 ], 0.05*self.displayScale, filled=True ) yaw = self.subHeading headingX = math.cos( yaw + math.pi/2.0 )*scaleX*0.10 headingY = math.sin( yaw + math.pi/2.0 )*scaleY*0.10 widget.window.draw_line( graphicsContext, int( subRenderPos[ 0 ] ), int( subRenderPos[ 1 ] ), int( subRenderPos[ 0 ] + headingX ), int( subRenderPos[ 1 ] + headingY ) ) #--------------------------------------------------------------------------- def onDwgMapScrollEvent( self, widget, event = None ): if event.direction == gtk.gdk.SCROLL_UP: self.displayScale *= self.SCALE_UP else: self.displayScale *= self.SCALE_DOWN if self.displayScale < self.MIN_SCALE: self.displayScale = self.MIN_SCALE if self.displayScale > self.MAX_SCALE: self.displayScale = self.MAX_SCALE self.dwgMap.queue_draw() #--------------------------------------------------------------------------- def onDwgMapButtonPressEvent( self, widget, event = None ): if event.button == 1: self.draggingDisplay = True self.lastDragPos = ( event.x, event.y ) #--------------------------------------------------------------------------- def onDwgMapButtonReleaseEvent( self, widget, event = None ): if event.button == 1: self.draggingDisplay = False #--------------------------------------------------------------------------- def onDwgMapMotionNotifyEvent( self, widget, event = None ): if self.draggingDisplay == True: newDragPos = ( event.x, event.y ) if newDragPos != self.lastDragPos: self.displayOriginX += newDragPos[ 0 ] - self.lastDragPos[ 0 ] self.displayOriginY += newDragPos[ 1 ] - self.lastDragPos[ 1 ] self.lastDragPos = newDragPos self.dwgMap.queue_draw() #--------------------------------------------------------------------------- def drawCircle( self, drawable, graphicsContext, x, y, radius, filled ): topLeftX = int( x - radius ) topLeftY = int( y - radius ) width = height = int( radius * 2 ) drawable.draw_arc( graphicsContext, filled, topLeftX, topLeftY, width, height, 0, 360 * 64 ) #--------------------------------------------------------------------------- def getImageRectangleInWidget( self, widget, imageWidth, imageHeight ): # Centre the image inside the widget widgetX, widgetY, widgetWidth, widgetHeight = widget.get_allocation() imgRect = gtk.gdk.Rectangle( 0, 0, widgetWidth, widgetHeight ) if widgetWidth > imageWidth: imgRect.x = (widgetWidth - imageWidth) / 2 imgRect.width = imageWidth if widgetHeight > imageHeight: imgRect.y = (widgetHeight - imageHeight) / 2 imgRect.height = imageHeight return imgRect #--------------------------------------------------------------------------- def isNewFrameAvailable( self ): return self.lastCameraFrameTime != self.playerCamera.info.datatime #--------------------------------------------------------------------------- def update( self ): while 1: if self.playerClient.peek( 0 ): self.playerClient.read() if self.isNewFrameAvailable(): cameraFrameTime = self.playerCamera.info.datatime if self.playerCamera.compression != PLAYER_CAMERA_COMPRESS_RAW: self.playerCamera.decompress() if self.playerCamera.compression != PLAYER_CAMERA_COMPRESS_RAW: print "Error: Unable to decompress frame" sys.exit( -1 ) # Give the image to OpenCV as a very inefficient way to # save it as a jpeg rgbImage = cv.CreateImageHeader( ( self.playerCamera.width, self.playerCamera.height ), cv.IPL_DEPTH_8U, 3 ) cv.SetData( rgbImage, self.playerCamera.image[:self.playerCamera.image_count], self.playerCamera.width*3 ) processedFrameData = self.tracker.processFrame( rgbImage ) self.frame = rgbImage # Get the submarine's pose subPose = self.playerSim.get_pose2d( "Sub" ) subFound = ( subPose[ 0 ] == 0 ) if subFound: self.subPos = Vector2D( subPose[ 1 ], subPose[ 2 ] ) self.subHeading = subPose[ 3 ] self.updateSubControl() else: print "Warning: Unable to get Sub pose" # Display the image self.displayPixBuf = gtk.gdk.pixbuf_new_from_data( processedFrameData, #rgbImage.tostring(), gtk.gdk.COLORSPACE_RGB, False, rgbImage.depth, rgbImage.width, rgbImage.height, rgbImage.width*rgbImage.nChannels ) # Resize the drawing area if necessary if self.dwgDisplay.get_size_request() != ( rgbImage.width, rgbImage.height ): self.dwgDisplay.set_size_request( rgbImage.width, rgbImage.height ) self.dwgDisplay.queue_draw() self.dwgMap.queue_draw() self.lastCameraFrameTime = cameraFrameTime yield True yield False #--------------------------------------------------------------------------- def updateSubControl( self ): ARRIVAL_DISTANCE = 0.1 subLocator = SubLocator( self.subPos, self.subHeading ) steerToTargetBehaviour = SteerToTarget( subLocator ) if self.subState == self.SUB_STATE_MOVING_TO_BUOY: forwardSpeed = 0.0 yawSpeed = 0.0 blobData = self.tracker.getBlobData() if blobData.visible: halfFrameWidth = self.frame.width / 2.0 radiusOfCloseBuoy = self.screenRadiusOfCloseBuoy*self.frame.width if blobData.centreX < halfFrameWidth * 0.9: command = "Go Left" yawSpeed = self.absYawSpeed self.lastTurnDirection = self.LEFT elif blobData.centreX > halfFrameWidth * 1.1: command = "Go Right" yawSpeed = -self.absYawSpeed self.lastTurnDirection = self.RIGHT else: if blobData.radius < radiusOfCloseBuoy: command = "Go Forward" forwardSpeed = self.forwardSpeed halfRadius = radiusOfCloseBuoy / 2.0 if blobData.radius > halfRadius: # Slow down as we approach the buoy slowDownAmount = (blobData.radius - halfRadius)/halfRadius forwardSpeed - (0.9*forwardSpeed)*slowDownAmount else: command = "Stay Still" self.subState = self.SUB_STATE_MOVING_TO_GATE print "Buoy Visible at ( " + str( blobData.centreX ) + ", " + str( blobData.centreY ) + " ) - " + command else: print "Can't see buoy - turning " + self.lastTurnDirection.lower() # Turn to search for the buoy if self.lastTurnDirection == self.LEFT: yawSpeed = self.absYawSpeed else: yawSpeed = -self.absYawSpeed # Steer the AUV self.applySteeringResult( ( forwardSpeed, yawSpeed ) ) else: # self.subState == self.SUB_STATE_MOVING_TO_GATE # Move to gate target pos # Check to see if we have arrived curPos = subLocator.GetPosition() distanceToTargetPos = ( self.gateTargetPos - curPos ).Length() if distanceToTargetPos < ARRIVAL_DISTANCE: self.subState = self.SUB_STATE_MOVING_TO_BUOY else: # Use reactive steering behaviours to try and get to the target position steeringResult = None #self.avoidWallBehaviour.update() if steeringResult == None: steerToTargetBehaviour.setTargetPos( self.gateTargetPos ) steeringResult = steerToTargetBehaviour.update() self.applySteeringResult( steeringResult ) #--------------------------------------------------------------------------- def applySteeringResult( self, steeringResult ): """Sends a steering result in the form of a forward speed and heading speed down to the robot""" if steeringResult != None: self.playerPos3d.set_velocity( steeringResult[ 0 ], 0.0, 0.0, # x, y, z 0.0, 0.0, steeringResult[ 1 ], # roll, pitch, yaw 0 ) # State
def __init__( self ): self.groundTruthData = BuoyGroundTruth.Data() self.loadKeyFrameDataFromFile() self.curFramePixBuf = None self.settingFrame = False self.tracker = ColourTracker() #self.tracker.setTrackedHue( self.TRACKED_HUE, self.MAX_ABS_HUE_DIFF ) #self.tracker.setTrackedSaturation( self.TRACKED_SATURATION, self.MAX_ABS_SATURATION_DIFF ) #self.tracker.setTrackedValue( self.TRACKED_VALUE, self.MAX_ABS_VALUE_DIFF ) # Create a new window self.window = gtk.Window( gtk.WINDOW_TOPLEVEL) self.window.connect( "destroy", self.destroy ) # Sets the border width of the window. self.window.set_border_width(10) # Layout box names have the format layoutBox_Level_Number layoutBox_A_0 = gtk.VBox() # Add a menu uiManager = gtk.UIManager() accelGroup = uiManager.get_accel_group() self.window.add_accel_group( accelGroup ) actionGroup = gtk.ActionGroup( "MenuActions" ) # Create actions actionGroup.add_actions( [ ( "Quit", gtk.STOCK_QUIT, None, "<Control>q", None, self.destroy ), ( "File", None, "_File" ), ( "ClearKeyFrames", None, "_Clear Key Frames", None, None, self.clearKeyFrames ), ( "Save", gtk.STOCK_SAVE, None, "<Control>s", None, self.saveKeyFrameDataToFile )] ) uiManager.insert_action_group( actionGroup, 0 ) # Setup and show the menu bar uiManager.add_ui_from_string( self.UI ) menuBar = uiManager.get_widget( "/MenuBar" ) layoutBox_A_0.pack_start( menuBar, False ) menuBar.show() layoutBox_B_0 = gtk.HBox() layoutBox_C_0 = gtk.VBox() # Load video and get information about the video file self.videoCapture = cv.CaptureFromFile( "../data/buoy.avi" ) self.numFrames = int( cv.GetCaptureProperty( self.videoCapture, cv.CV_CAP_PROP_FRAME_COUNT ) ) self.frameWidth = int( cv.GetCaptureProperty( self.videoCapture, cv.CV_CAP_PROP_FRAME_WIDTH ) ) self.frameHeight = int( cv.GetCaptureProperty( self.videoCapture, cv.CV_CAP_PROP_FRAME_HEIGHT ) ) # Setup an drawing area to show the current frame self.dwgCurFrame = gtk.DrawingArea() self.dwgCurFrame.add_events( gtk.gdk.BUTTON_PRESS_MASK ) self.dwgCurFrame.connect( "expose_event", self.onDwgCurFrameExpose ) self.dwgCurFrame.connect( "button-press-event", self.onDwgCurFrameButtonPress ) self.dwgCurFrame.set_size_request( self.frameWidth, self.frameHeight ) layoutBox_C_0.pack_start( self.dwgCurFrame ) self.dwgCurFrame.show() layoutBox_D_0 = gtk.HBox() # Add buttons to move back and forth through the video self.btnPrevFrame = gtk.Button( "<" ) self.btnPrevFrame.connect( "clicked", self.gotoPrevFrame ) layoutBox_D_0.pack_start( self.btnPrevFrame ) self.btnPrevFrame.show() # Create a textbox to show the current frame number self.tbxFrameNumber = gtk.Entry() self.tbxFrameNumber.connect( "focus-out-event", self.onTbxFrameNumberFocusOut ) self.tbxFrameNumber.connect( "key-press-event", self.onTbxFrameNumberKeyPressed ) layoutBox_D_0.pack_start( self.tbxFrameNumber ) self.tbxFrameNumber.show() lblFrameNumber = gtk.Label( " / " + str( self.numFrames ) ) layoutBox_D_0.pack_start( lblFrameNumber ) lblFrameNumber.show() self.btnNextFrame = gtk.Button( ">" ) self.btnNextFrame.connect( "clicked", self.gotoNextFrame ) layoutBox_D_0.pack_start( self.btnNextFrame ) self.btnNextFrame.show() layoutBox_C_0.pack_start( layoutBox_D_0 ) layoutBox_D_0.show() # Add the controls for editing keyframes layoutBox_C_1 = gtk.VBox() layoutBox_D_0 = gtk.HBox() lblKeyFrameType = gtk.Label( "KeyFrame Type:" ) layoutBox_D_0.pack_start( lblKeyFrameType ) lblKeyFrameType.show() self.cbxKeyFrameType = gtk.combo_box_new_text() for keyFrameType in BuoyGroundTruth.KEYFRAME_TYPE_LIST: self.cbxKeyFrameType.append_text( keyFrameType ) self.cbxKeyFrameType.connect( "changed", self.setupControlsForKeyFrame ) layoutBox_D_0.pack_start( self.cbxKeyFrameType ) self.cbxKeyFrameType.show() self.chkBuoyVisible = gtk.CheckButton( "Buoy Visible" ) self.chkBuoyVisible.set_sensitive( False ) layoutBox_D_1 = gtk.HBox() lblKeyFrameCentreX = gtk.Label( "Centre X:" ) layoutBox_D_1.pack_start( lblKeyFrameCentreX ) lblKeyFrameCentreX.show() self.tbxKeyFrameCentreX = gtk.Entry() layoutBox_D_1.pack_start( self.tbxKeyFrameCentreX ) self.tbxKeyFrameCentreX.connect( "focus-out-event", self.setKeyFrameDataFromControls ) self.tbxKeyFrameCentreX.show() layoutBox_D_2 = gtk.HBox() lblKeyFrameCentreY = gtk.Label( "Centre Y:" ) layoutBox_D_2.pack_start( lblKeyFrameCentreY ) lblKeyFrameCentreY.show() self.tbxKeyFrameCentreY = gtk.Entry() layoutBox_D_2.pack_start( self.tbxKeyFrameCentreY ) self.tbxKeyFrameCentreY.connect( "focus-out-event", self.setKeyFrameDataFromControls ) self.tbxKeyFrameCentreY.show() layoutBox_D_3 = gtk.HBox() lblKeyFrameRadius = gtk.Label( "Radius:" ) layoutBox_D_3.pack_start( lblKeyFrameRadius ) lblKeyFrameRadius.show() self.tbxKeyFrameRadius = gtk.Entry() layoutBox_D_3.pack_start( self.tbxKeyFrameRadius ) self.tbxKeyFrameRadius.connect( "focus-out-event", self.setKeyFrameDataFromControls ) self.tbxKeyFrameRadius.show() layoutBox_C_1.pack_start( layoutBox_D_0, fill=False ) layoutBox_D_0.show() layoutBox_C_1.pack_start( self.chkBuoyVisible ) self.chkBuoyVisible.show() layoutBox_C_1.pack_start( layoutBox_D_1, fill=False ) layoutBox_D_1.show() layoutBox_C_1.pack_start( layoutBox_D_2, fill=False ) layoutBox_D_2.show() layoutBox_C_1.pack_start( layoutBox_D_3, fill=False ) layoutBox_D_3.show() self.chkEnableTracker = gtk.CheckButton( "Enable Tracker" ) self.chkEnableTracker.connect( "toggled", self.onChkEnableTrackerToggled ) layoutBox_C_1.pack_start( self.chkEnableTracker ) self.chkEnableTracker.show() self.btnResetTracker = gtk.Button( "Reset Tracker" ) self.btnResetTracker.connect( "clicked", self.resetTracker ) layoutBox_C_1.pack_start( self.btnResetTracker ) self.btnResetTracker.show() layoutBox_B_0.pack_start( layoutBox_C_0 ) layoutBox_C_0.show() layoutBox_B_0.pack_start( layoutBox_C_1 ) layoutBox_C_1.show() layoutBox_A_0.pack_start( layoutBox_B_0 ) layoutBox_B_0.show() self.setCurFrameIdx( 0 ) # Add the root layout box to the main window self.window.add( layoutBox_A_0 ) layoutBox_A_0.show() # Finished so show the window self.window.show()
class MainWindow: UI = ''' <ui> <menubar name="MenuBar"> <menu action="File"> <menuitem action="ClearKeyFrames"/> <menuitem action="Save"/> <separator/> <menuitem action="Quit"/> </menu> </menubar> </ui>''' TRACKED_HUE = 15.0 MAX_ABS_HUE_DIFF = 5.0 TRACKED_SATURATION = 70.0 MAX_ABS_SATURATION_DIFF = 5.0 TRACKED_VALUE = 60.0 MAX_ABS_VALUE_DIFF = 15.0 #--------------------------------------------------------------------------- def __init__( self ): self.groundTruthData = BuoyGroundTruth.Data() self.loadKeyFrameDataFromFile() self.curFramePixBuf = None self.settingFrame = False self.tracker = ColourTracker() #self.tracker.setTrackedHue( self.TRACKED_HUE, self.MAX_ABS_HUE_DIFF ) #self.tracker.setTrackedSaturation( self.TRACKED_SATURATION, self.MAX_ABS_SATURATION_DIFF ) #self.tracker.setTrackedValue( self.TRACKED_VALUE, self.MAX_ABS_VALUE_DIFF ) # Create a new window self.window = gtk.Window( gtk.WINDOW_TOPLEVEL) self.window.connect( "destroy", self.destroy ) # Sets the border width of the window. self.window.set_border_width(10) # Layout box names have the format layoutBox_Level_Number layoutBox_A_0 = gtk.VBox() # Add a menu uiManager = gtk.UIManager() accelGroup = uiManager.get_accel_group() self.window.add_accel_group( accelGroup ) actionGroup = gtk.ActionGroup( "MenuActions" ) # Create actions actionGroup.add_actions( [ ( "Quit", gtk.STOCK_QUIT, None, "<Control>q", None, self.destroy ), ( "File", None, "_File" ), ( "ClearKeyFrames", None, "_Clear Key Frames", None, None, self.clearKeyFrames ), ( "Save", gtk.STOCK_SAVE, None, "<Control>s", None, self.saveKeyFrameDataToFile )] ) uiManager.insert_action_group( actionGroup, 0 ) # Setup and show the menu bar uiManager.add_ui_from_string( self.UI ) menuBar = uiManager.get_widget( "/MenuBar" ) layoutBox_A_0.pack_start( menuBar, False ) menuBar.show() layoutBox_B_0 = gtk.HBox() layoutBox_C_0 = gtk.VBox() # Load video and get information about the video file self.videoCapture = cv.CaptureFromFile( "../data/buoy.avi" ) self.numFrames = int( cv.GetCaptureProperty( self.videoCapture, cv.CV_CAP_PROP_FRAME_COUNT ) ) self.frameWidth = int( cv.GetCaptureProperty( self.videoCapture, cv.CV_CAP_PROP_FRAME_WIDTH ) ) self.frameHeight = int( cv.GetCaptureProperty( self.videoCapture, cv.CV_CAP_PROP_FRAME_HEIGHT ) ) # Setup an drawing area to show the current frame self.dwgCurFrame = gtk.DrawingArea() self.dwgCurFrame.add_events( gtk.gdk.BUTTON_PRESS_MASK ) self.dwgCurFrame.connect( "expose_event", self.onDwgCurFrameExpose ) self.dwgCurFrame.connect( "button-press-event", self.onDwgCurFrameButtonPress ) self.dwgCurFrame.set_size_request( self.frameWidth, self.frameHeight ) layoutBox_C_0.pack_start( self.dwgCurFrame ) self.dwgCurFrame.show() layoutBox_D_0 = gtk.HBox() # Add buttons to move back and forth through the video self.btnPrevFrame = gtk.Button( "<" ) self.btnPrevFrame.connect( "clicked", self.gotoPrevFrame ) layoutBox_D_0.pack_start( self.btnPrevFrame ) self.btnPrevFrame.show() # Create a textbox to show the current frame number self.tbxFrameNumber = gtk.Entry() self.tbxFrameNumber.connect( "focus-out-event", self.onTbxFrameNumberFocusOut ) self.tbxFrameNumber.connect( "key-press-event", self.onTbxFrameNumberKeyPressed ) layoutBox_D_0.pack_start( self.tbxFrameNumber ) self.tbxFrameNumber.show() lblFrameNumber = gtk.Label( " / " + str( self.numFrames ) ) layoutBox_D_0.pack_start( lblFrameNumber ) lblFrameNumber.show() self.btnNextFrame = gtk.Button( ">" ) self.btnNextFrame.connect( "clicked", self.gotoNextFrame ) layoutBox_D_0.pack_start( self.btnNextFrame ) self.btnNextFrame.show() layoutBox_C_0.pack_start( layoutBox_D_0 ) layoutBox_D_0.show() # Add the controls for editing keyframes layoutBox_C_1 = gtk.VBox() layoutBox_D_0 = gtk.HBox() lblKeyFrameType = gtk.Label( "KeyFrame Type:" ) layoutBox_D_0.pack_start( lblKeyFrameType ) lblKeyFrameType.show() self.cbxKeyFrameType = gtk.combo_box_new_text() for keyFrameType in BuoyGroundTruth.KEYFRAME_TYPE_LIST: self.cbxKeyFrameType.append_text( keyFrameType ) self.cbxKeyFrameType.connect( "changed", self.setupControlsForKeyFrame ) layoutBox_D_0.pack_start( self.cbxKeyFrameType ) self.cbxKeyFrameType.show() self.chkBuoyVisible = gtk.CheckButton( "Buoy Visible" ) self.chkBuoyVisible.set_sensitive( False ) layoutBox_D_1 = gtk.HBox() lblKeyFrameCentreX = gtk.Label( "Centre X:" ) layoutBox_D_1.pack_start( lblKeyFrameCentreX ) lblKeyFrameCentreX.show() self.tbxKeyFrameCentreX = gtk.Entry() layoutBox_D_1.pack_start( self.tbxKeyFrameCentreX ) self.tbxKeyFrameCentreX.connect( "focus-out-event", self.setKeyFrameDataFromControls ) self.tbxKeyFrameCentreX.show() layoutBox_D_2 = gtk.HBox() lblKeyFrameCentreY = gtk.Label( "Centre Y:" ) layoutBox_D_2.pack_start( lblKeyFrameCentreY ) lblKeyFrameCentreY.show() self.tbxKeyFrameCentreY = gtk.Entry() layoutBox_D_2.pack_start( self.tbxKeyFrameCentreY ) self.tbxKeyFrameCentreY.connect( "focus-out-event", self.setKeyFrameDataFromControls ) self.tbxKeyFrameCentreY.show() layoutBox_D_3 = gtk.HBox() lblKeyFrameRadius = gtk.Label( "Radius:" ) layoutBox_D_3.pack_start( lblKeyFrameRadius ) lblKeyFrameRadius.show() self.tbxKeyFrameRadius = gtk.Entry() layoutBox_D_3.pack_start( self.tbxKeyFrameRadius ) self.tbxKeyFrameRadius.connect( "focus-out-event", self.setKeyFrameDataFromControls ) self.tbxKeyFrameRadius.show() layoutBox_C_1.pack_start( layoutBox_D_0, fill=False ) layoutBox_D_0.show() layoutBox_C_1.pack_start( self.chkBuoyVisible ) self.chkBuoyVisible.show() layoutBox_C_1.pack_start( layoutBox_D_1, fill=False ) layoutBox_D_1.show() layoutBox_C_1.pack_start( layoutBox_D_2, fill=False ) layoutBox_D_2.show() layoutBox_C_1.pack_start( layoutBox_D_3, fill=False ) layoutBox_D_3.show() self.chkEnableTracker = gtk.CheckButton( "Enable Tracker" ) self.chkEnableTracker.connect( "toggled", self.onChkEnableTrackerToggled ) layoutBox_C_1.pack_start( self.chkEnableTracker ) self.chkEnableTracker.show() self.btnResetTracker = gtk.Button( "Reset Tracker" ) self.btnResetTracker.connect( "clicked", self.resetTracker ) layoutBox_C_1.pack_start( self.btnResetTracker ) self.btnResetTracker.show() layoutBox_B_0.pack_start( layoutBox_C_0 ) layoutBox_C_0.show() layoutBox_B_0.pack_start( layoutBox_C_1 ) layoutBox_C_1.show() layoutBox_A_0.pack_start( layoutBox_B_0 ) layoutBox_B_0.show() self.setCurFrameIdx( 0 ) # Add the root layout box to the main window self.window.add( layoutBox_A_0 ) layoutBox_A_0.show() # Finished so show the window self.window.show() #--------------------------------------------------------------------------- def setCurFrameIdx( self, frameIdx ): if self.settingFrame: raise "NotReentrant" self.settingFrame = True # Clip the frame index to a valid number if frameIdx < 0: frameIdx = 0 elif frameIdx >= self.numFrames: frameIdx = self.numFrames - 1 # Display the select frame self.curFrameIdx = frameIdx cv.SetCaptureProperty( self.videoCapture, cv.CV_CAP_PROP_POS_FRAMES, frameIdx ) baseFrame = cv.QueryFrame( self.videoCapture ) pythonFrame = cv.CloneImage( baseFrame ) cv.CvtColor( pythonFrame, pythonFrame, cv.CV_BGR2RGB ) if self.chkEnableTracker.get_active(): # We may process the same frame multiple times (i.e. if the screen is redrawn) # This shouldn't be a problem as this program is only for debug purposes so such # issues should be noticable if TRACKER_NEEDS_RGB: self.processFrame( pythonFrame ) else: self.processFrame( baseFrame ) self.curFramePixBuf = gtk.gdk.pixbuf_new_from_data( pythonFrame.tostring(), gtk.gdk.COLORSPACE_RGB, False, pythonFrame.depth, pythonFrame.width, pythonFrame.height, pythonFrame.width*pythonFrame.nChannels ) # Update the text-box that displays the current frame number self.tbxFrameNumber.set_text( str( frameIdx + 1 ) ) # Display the buoy position buoyData = self.groundTruthData.getBuoyData( frameIdx ) self.chkBuoyVisible.set_active( buoyData.visible ) self.tbxKeyFrameCentreX.set_text( str( buoyData.centreX ) ) self.tbxKeyFrameCentreY.set_text( str( buoyData.centreY ) ) self.tbxKeyFrameRadius.set_text( str( buoyData.radius ) ) keyFrameType = self.groundTruthData.getKeyFrameType( frameIdx ) for keyFrameTypeIdx in range( len( BuoyGroundTruth.KEYFRAME_TYPE_LIST ) ): if BuoyGroundTruth.KEYFRAME_TYPE_LIST[ keyFrameTypeIdx ] == keyFrameType: self.cbxKeyFrameType.set_active( keyFrameTypeIdx ) break # Redraw the frame self.dwgCurFrame.queue_draw() self.settingFrame = False #--------------------------------------------------------------------------- def setupControlsForKeyFrame( self, widget, data = None ): if self.cbxKeyFrameType.get_active_text() == BuoyGroundTruth.KEYFRAME_TYPE_VISIBLE: self.tbxKeyFrameCentreX.set_sensitive( True ) self.tbxKeyFrameCentreY.set_sensitive( True ) self.tbxKeyFrameRadius.set_sensitive( True ) else: self.tbxKeyFrameCentreX.set_sensitive( False ) self.tbxKeyFrameCentreY.set_sensitive( False ) self.tbxKeyFrameRadius.set_sensitive( False ) if not self.settingFrame: if self.cbxKeyFrameType.get_active_text() != BuoyGroundTruth.KEYFRAME_TYPE_VISIBLE: self.chkBuoyVisible.set_active( False ) self.tbxKeyFrameCentreX.set_text( "0.0" ) self.tbxKeyFrameCentreY.set_text( "0.0" ) self.tbxKeyFrameRadius.set_text( "0.0" ) self.setKeyFrameDataFromControls() #--------------------------------------------------------------------------- def setKeyFrameDataFromControls( self, widget = None, data = None ): centreX = tryParseFloat( self.tbxKeyFrameCentreX.get_text(), 0.0 ) centreY = tryParseFloat( self.tbxKeyFrameCentreY.get_text(), 0.0 ) radius = tryParseFloat( self.tbxKeyFrameRadius.get_text(), 0.0 ) keyFrame = KeyFrame( self.cbxKeyFrameType.get_active_text(), centreX, centreY, radius ) if keyFrame.type == BuoyGroundTruth.KEYFRAME_TYPE_NONE: # Keyframes of type None don't need to be stored if self.curFrameIdx in self.keyFrames.keys(): del self.keyFrames[ self.curFrameIdx ] else: self.keyFrames[ self.curFrameIdx ] = keyFrame # Reset everything self.setCurFrameIdx( self.curFrameIdx ) #--------------------------------------------------------------------------- def gotoPrevFrame( self, widget, data = None ): self.setCurFrameIdx( self.curFrameIdx - 1 ) #--------------------------------------------------------------------------- def gotoNextFrame( self, widget, data = None ): self.setCurFrameIdx( self.curFrameIdx + 1 ) #--------------------------------------------------------------------------- def getImageRectangleInWidget( self, widget ): # Centre the image inside the widget widgetX, widgetY, widgetWidth, widgetHeight = widget.get_allocation() imgRect = gtk.gdk.Rectangle( 0, 0, widgetWidth, widgetHeight ) if widgetWidth > self.frameWidth: imgRect.x = (widgetWidth - self.frameWidth) / 2 imgRect.width = self.frameWidth if widgetHeight > self.frameHeight: imgRect.y = (widgetHeight - self.frameHeight) / 2 imgRect.height = self.frameHeight return imgRect #--------------------------------------------------------------------------- def onDwgCurFrameExpose( self, widget, event ): if self.curFramePixBuf != None: imgRect = self.getImageRectangleInWidget( widget ) imgOffsetX = imgRect.x imgOffsetY = imgRect.y # Get the total area that needs to be redrawn imgRect = imgRect.intersect( event.area ) srcX = imgRect.x - imgOffsetX srcY = imgRect.y - imgOffsetY widget.window.draw_pixbuf( widget.get_style().fg_gc[ gtk.STATE_NORMAL ], self.curFramePixBuf, srcX, srcY, imgRect.x, imgRect.y, imgRect.width, imgRect.height ) # Now draw the circle for the buoy on top buoyData = self.groundTruthData.getBuoyData( self.curFrameIdx ) if buoyData.visible: arcX = int( imgOffsetX + buoyData.centreX - buoyData.radius ) arcY = int( imgOffsetY + buoyData.centreY - buoyData.radius ) arcWidth = arcHeight = int( buoyData.radius * 2 ) drawFilledArc = False graphicsContext = widget.window.new_gc() widget.window.draw_arc( graphicsContext, drawFilledArc, arcX, arcY, arcWidth, arcHeight, 0, 360 * 64 ) widget.window.draw_points( graphicsContext, [ ( int( imgOffsetX + buoyData.centreX ), int( imgOffsetY + buoyData.centreY ) ) ] ) if self.chkEnableTracker.get_active(): blobData = self.tracker.getBlobData() if blobData.visible: arcX = int( imgOffsetX + blobData.centreX - blobData.radius ) arcY = int( imgOffsetY + blobData.centreY - blobData.radius ) arcWidth = arcHeight = int( blobData.radius * 2 ) drawFilledArc = False graphicsContext = widget.window.new_gc() graphicsContext.set_rgb_fg_color( gtk.gdk.Color( 65535, 65535, 65535 ) ) widget.window.draw_arc( graphicsContext, drawFilledArc, arcX, arcY, arcWidth, arcHeight, 0, 360 * 64 ) widget.window.draw_points( graphicsContext, [ ( int( imgOffsetX + blobData.centreX ), int( imgOffsetY + blobData.centreY ) ) ] ) #--------------------------------------------------------------------------- def onDwgCurFrameButtonPress( self, widget, event ): buoyData = self.groundTruthData.getBuoyData( self.curFrameIdx ) if buoyData.visible: imgRect = self.getImageRectangleInWidget( widget ) self.tbxKeyFrameCentreX.set_text( str( event.x - imgRect.x ) ) self.tbxKeyFrameCentreY.set_text( str( event.y - imgRect.y ) ) self.setKeyFrameDataFromControls() #--------------------------------------------------------------------------- def onTbxFrameNumberFocusOut( self, widget, data = None ): try: self.setCurFrameIdx( int( self.tbxFrameNumber.get_text() ) - 1 ) except: pass # Catch errors that may occur whilst parsing an integer #--------------------------------------------------------------------------- def onTbxFrameNumberKeyPressed( self, widget, keyPressEvent ): if gtk.gdk.keyval_name( keyPressEvent.keyval ) == "Return": self.onTbxFrameNumberFocusOut( widget ) #--------------------------------------------------------------------------- def destroy( self, widget, data = None ): # Shutdown #if None != self.videoCapture: # cv.ReleaseCapture( self.videoCapture ) gtk.main_quit() #--------------------------------------------------------------------------- def main(self): # All PyGTK applications must have a gtk.main(). Control ends here # and waits for an event to occur (like a key press or mouse event). gtk.main() #--------------------------------------------------------------------------- def saveKeyFrameDataToFile( self, data ): self.setKeyFrameDataFromControls() # Save any changes being made to the current keyframe self.groundTruthData.saveKeyFramesToFile( "keyframes.yaml" ) #--------------------------------------------------------------------------- def loadKeyFrameDataFromFile( self ): self.groundTruthData.loadKeyFramesFromFile( "keyframes.yaml" ) #--------------------------------------------------------------------------- def clearKeyFrames( self, data = None ): self.groundTruthData.clearKeyFrames() self.setCurFrameIdx( int( self.tbxFrameNumber.get_text() ) - 1 ) #--------------------------------------------------------------------------- def resetTracker( self, widget ): self.tracker.reset() #--------------------------------------------------------------------------- def onChkEnableTrackerToggled( self, widget ): if widget.get_active(): self.tracker.reset() # Lets the tracker process the frame self.setCurFrameIdx( int( self.tbxFrameNumber.get_text() ) - 1 ) else: self.dwgCurFrame.queue_draw() @Profiling.printTiming def processFrame( self, frame ): self.tracker.processFrame( frame )