def __init__(self, **params):
     # Set here to avoid having it one instantiated by default
     if self.ptz==None: self.ptz=PTZ()
 def __init__(self, **params):
     # Set here to avoid having it one instantiated by default
     if self.ptz == None: self.ptz = PTZ()
class PtzTracker(Sheet):
    """
    Given an incoming Activity pattern, find the brightest pixel and
    output an activity pattern where all but this pixel is set to zero.
    Also controls a pan/tilt/zoom camera, instructing it to move so that
    the brightest pixel will be in the center of the sheet.
    """

    dest_ports=['Activity']
    src_ports=['Activity']

    ratio = param.Number(default=1.33,doc=
        "Ratio depends of the resolution of the camera, here 640x480.")

    fov_x = param.Number(default=76,doc=
        "Field of view along x in degrees, depends of the camera.")

    fov_y = param.Number(default=57,doc=
        """
        Field of view along y in degrees. It is calculate with the resolution
        of the camera, and its field of view. It also depends of the bounds used,
        here the size_normalization used is "fit_shortest". So Sheet coordinates
        along y for camera's image are between -0.5 and 0.5.
        The original calculation is fov_y=fov_x*0.5*2/ratio.
        """)

    ptz = param.ClassSelector(PTZ,default=None,doc="""
        An instance of ptzcamera.PTZ to be controlled.""")

    # Max Ranges (determined with uvcdynctrl -v -c)
    maxrange_x = param.Number(default=4480, doc=
        """Maximum position of the camera along x.""")

    maxrange_y = param.Number(default=1920, doc=
        """Maximum position of the camera along y.""")

    #Coordinates in degrees
    y_deg = 0
    x_deg = 0
    #Coordinates in degrees for uvcdynctrl(unit=1/64th of a degree)
    y_deg_uvc = 0
    x_deg_uvc = 0
    #Coordinates of the brightest pixel
    coor = (0,0)
    #Current postitions along x and y
    curr_y=0
    curr_x=0

    def __init__(self, **params):
        # Set here to avoid having it one instantiated by default
        if self.ptz==None: self.ptz=PTZ()

    def input_event(self,conn,data):
        self.input_data=data

    def determine_next_position(self,img):
        """
        Determine the next location to move in the specified image, using whatever
        criterion is appropriate for this class.  Returns a tuple of (pos,bbox),
        where pos is the (row,column) coordinate of the next position, and bbox
        is a bounding box around that coordinate, with whatever size is appropriate
        for this class.  Returns None if no appropriate location can be found.
        """
        raise NotImplementedError


    def draw_boxes(self,input_data,bboxmin,bboxmax):
        """
        Draws three boxes arond the returned location.
        """
        opencv.cvRectangle(self.input_data, opencv.cvPoint(np.int(bboxmin[0]),np.int(bboxmin[1])),opencv.cvPoint(np.int(bboxmax[0])
            ,np.int(bboxmax[1])),0,1)
        opencv.cvRectangle(self.input_data, opencv.cvPoint(np.int(bboxmin[0])-1,np.int(bboxmin[1])-1),opencv.cvPoint(np.int(bboxmax[0])
            +1,np.int(bboxmax[1])+1),0,1)
        opencv.cvRectangle(self.input_data, opencv.cvPoint(np.int(bboxmin[0])-2,np.int(bboxmin[1])-2),opencv.cvPoint(np.int(bboxmax[0])
            +2,np.int(bboxmax[1])+2),1,1)


    def move_camera(self,pos, bboxmin, bbboxmax,brightpixel):
        """
        Move the camera to centre the returned location.
        """
        #Determinate the centre of the returned location
        if (self.brightpixel==True):
            self.pos=pos
        else:
            self.pos=(((self.bboxmax[0]+self.bboxmin[0])/2,(self.bboxmax[1]+self.bboxmin[1])/2))

        #Find sheet coordinates of the specified position
        self.coor=self.matrixidx2sheet(*self.pos)

        self.y_deg=self.coor[1]*(self.fov_y/2)/0.5
        self.x_deg=self.coor[0]*(self.fov_x/2)/(self.ratio/2)

        # The unit of uvcdynctrl is 1/64th of a degree
        ## HACK problem with the scaling. so divide by 2.
        ##it doesn't come from the fov or resolution maybe from somewhere with the coordinates
        self.y_deg_uvc=self.y_deg*64/2
        self.x_deg_uvc=self.x_deg*64/2

        self.message("Coordinates of the new position: (%f,%f)" % (self.coor[0],self.coor[1]))
        self.verbose("Current position of the camera (%f,%f) along the two directions of the camera" % (self.curr_x,self.curr_y))
        self.verbose("Movements in degrees of uvcdynctrl (%f,%f)" % (self.x_deg_uvc,self.y_deg_uvc))

         #Use class PTZ in order to move the camera with uvcdynctrl
         # Max Ranges (determined with uvcdynctrl -v -c)
        if ((self.curr_y+self.y_deg_uvc<self.maxrange_y) and (self.curr_y+self.y_deg_uvc>-self.maxrange_y)):
            self.curr_y+=self.y_deg_uvc
            self.ptz.tilt(self.y_deg_uvc)
        else:
            self.message("The camera can't move further along y")

        if ((self.curr_x+self.x_deg_uvc<self.maxrange_x) and (self.curr_x+self.x_deg_uvc>-self.maxrange_x)):
            self.curr_x+=self.x_deg_uvc
            self.ptz.pan(self.x_deg_uvc)
        else:
            self.message("The camera can't move further along x")


    def process_current_time(self):
        if hasattr(self, 'input_data'):

            #Find the brightest pixel of the image, put it in white and other pixels in black
            result=self.determine_next_position(self.input_data)
            self.activity*=0

            if result: # Draw a box around the returned location
                self.pos,self.bboxmin,self.bboxmax,self.brightpixel=result
                self.draw_boxes(self.input_data,self.bboxmin,self.bboxmax)

            self.activity+=self.input_data
            self.send_output(src_port='Activity',data=self.activity)
            del self.input_data

            if not result:
                return # Else move camera

            self.move_camera(self.pos,self.bboxmin,self.bboxmax,self.brightpixel)
class PtzTracker(Sheet):
    """
    Given an incoming Activity pattern, find the brightest pixel and
    output an activity pattern where all but this pixel is set to zero.
    Also controls a pan/tilt/zoom camera, instructing it to move so that
    the brightest pixel will be in the center of the sheet.
    """

    dest_ports = ['Activity']
    src_ports = ['Activity']

    ratio = param.Number(
        default=1.33,
        doc="Ratio depends of the resolution of the camera, here 640x480.")

    fov_x = param.Number(
        default=76,
        doc="Field of view along x in degrees, depends of the camera.")

    fov_y = param.Number(default=57,
                         doc="""
        Field of view along y in degrees. It is calculate with the resolution
        of the camera, and its field of view. It also depends of the bounds used,
        here the size_normalization used is "fit_shortest". So Sheet coordinates
        along y for camera's image are between -0.5 and 0.5.
        The original calculation is fov_y=fov_x*0.5*2/ratio.
        """)

    ptz = param.ClassSelector(PTZ,
                              default=None,
                              doc="""
        An instance of ptzcamera.PTZ to be controlled.""")

    # Max Ranges (determined with uvcdynctrl -v -c)
    maxrange_x = param.Number(
        default=4480, doc="""Maximum position of the camera along x.""")

    maxrange_y = param.Number(
        default=1920, doc="""Maximum position of the camera along y.""")

    #Coordinates in degrees
    y_deg = 0
    x_deg = 0
    #Coordinates in degrees for uvcdynctrl(unit=1/64th of a degree)
    y_deg_uvc = 0
    x_deg_uvc = 0
    #Coordinates of the brightest pixel
    coor = (0, 0)
    #Current postitions along x and y
    curr_y = 0
    curr_x = 0

    def __init__(self, **params):
        # Set here to avoid having it one instantiated by default
        if self.ptz == None: self.ptz = PTZ()

    def input_event(self, conn, data):
        self.input_data = data

    def determine_next_position(self, img):
        """
        Determine the next location to move in the specified image, using whatever
        criterion is appropriate for this class.  Returns a tuple of (pos,bbox),
        where pos is the (row,column) coordinate of the next position, and bbox
        is a bounding box around that coordinate, with whatever size is appropriate
        for this class.  Returns None if no appropriate location can be found.
        """
        raise NotImplementedError

    def draw_boxes(self, input_data, bboxmin, bboxmax):
        """
        Draws three boxes arond the returned location.
        """
        opencv.cvRectangle(
            self.input_data,
            opencv.cvPoint(np.int(bboxmin[0]), np.int(bboxmin[1])),
            opencv.cvPoint(np.int(bboxmax[0]), np.int(bboxmax[1])), 0, 1)
        opencv.cvRectangle(
            self.input_data,
            opencv.cvPoint(np.int(bboxmin[0]) - 1,
                           np.int(bboxmin[1]) - 1),
            opencv.cvPoint(np.int(bboxmax[0]) + 1,
                           np.int(bboxmax[1]) + 1), 0, 1)
        opencv.cvRectangle(
            self.input_data,
            opencv.cvPoint(np.int(bboxmin[0]) - 2,
                           np.int(bboxmin[1]) - 2),
            opencv.cvPoint(np.int(bboxmax[0]) + 2,
                           np.int(bboxmax[1]) + 2), 1, 1)

    def move_camera(self, pos, bboxmin, bbboxmax, brightpixel):
        """
        Move the camera to centre the returned location.
        """
        #Determinate the centre of the returned location
        if (self.brightpixel == True):
            self.pos = pos
        else:
            self.pos = (((self.bboxmax[0] + self.bboxmin[0]) / 2,
                         (self.bboxmax[1] + self.bboxmin[1]) / 2))

        #Find sheet coordinates of the specified position
        self.coor = self.matrixidx2sheet(*self.pos)

        self.y_deg = self.coor[1] * (self.fov_y / 2) / 0.5
        self.x_deg = self.coor[0] * (self.fov_x / 2) / (self.ratio / 2)

        # The unit of uvcdynctrl is 1/64th of a degree
        ## HACK problem with the scaling. so divide by 2.
        ##it doesn't come from the fov or resolution maybe from somewhere with the coordinates
        self.y_deg_uvc = self.y_deg * 64 / 2
        self.x_deg_uvc = self.x_deg * 64 / 2

        self.message("Coordinates of the new position: (%f,%f)" %
                     (self.coor[0], self.coor[1]))
        self.verbose(
            "Current position of the camera (%f,%f) along the two directions of the camera"
            % (self.curr_x, self.curr_y))
        self.verbose("Movements in degrees of uvcdynctrl (%f,%f)" %
                     (self.x_deg_uvc, self.y_deg_uvc))

        #Use class PTZ in order to move the camera with uvcdynctrl
        # Max Ranges (determined with uvcdynctrl -v -c)
        if ((self.curr_y + self.y_deg_uvc < self.maxrange_y)
                and (self.curr_y + self.y_deg_uvc > -self.maxrange_y)):
            self.curr_y += self.y_deg_uvc
            self.ptz.tilt(self.y_deg_uvc)
        else:
            self.message("The camera can't move further along y")

        if ((self.curr_x + self.x_deg_uvc < self.maxrange_x)
                and (self.curr_x + self.x_deg_uvc > -self.maxrange_x)):
            self.curr_x += self.x_deg_uvc
            self.ptz.pan(self.x_deg_uvc)
        else:
            self.message("The camera can't move further along x")

    def process_current_time(self):
        if hasattr(self, 'input_data'):

            #Find the brightest pixel of the image, put it in white and other pixels in black
            result = self.determine_next_position(self.input_data)
            self.activity *= 0

            if result:  # Draw a box around the returned location
                self.pos, self.bboxmin, self.bboxmax, self.brightpixel = result
                self.draw_boxes(self.input_data, self.bboxmin, self.bboxmax)

            self.activity += self.input_data
            self.send_output(src_port='Activity', data=self.activity)
            del self.input_data

            if not result:
                return  # Else move camera

            self.move_camera(self.pos, self.bboxmin, self.bboxmax,
                             self.brightpixel)