Ejemplo n.º 1
0
    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!"
Ejemplo n.º 2
0
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 )
Ejemplo n.º 3
0
    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 )
Ejemplo n.º 4
0
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
Ejemplo n.º 5
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()
Ejemplo n.º 6
0
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 )