Esempio n. 1
0
 def test_iou_no_intersection(self):
   """Test IoU with no intersection."""
   person = Person([], Rectangle(Point(0, 0), Point(0.5, 0.5)), 1)
   track = Track(
       Person([], Rectangle(Point(0.5, 0.5), Point(1, 1)), 1), 1000000)
   computed_iou = self.bbox_tracker._iou(person, track)
   self.assertAlmostEqual(computed_iou, 0.0, 6)
Esempio n. 2
0
 def test_iou(self):
   """Test IoU."""
   person = Person([], Rectangle(Point(0, 0), Point(1, 2 / 3)), 1)
   track = Track(
       Person([], Rectangle(Point(0, 1 / 3), Point(1, 1)), 1), 1000000)
   computed_iou = self.bbox_tracker._iou(person, track)
   self.assertAlmostEqual(computed_iou, 1 / 3, 6)
Esempio n. 3
0
def receive_point(message: telebot.types.Message):
    point = Point(date=datetime.fromtimestamp(message.date),
                  x=message.location.latitude,
                  y=message.location.longitude,
                  comment=str(datetime.fromtimestamp(message.date)))
    point.save()
    bot.send_message(message.chat.id, "Сохранено")
Esempio n. 4
0
def remove_last_point(message: telebot.types.Message):
    if not len(Point.select()):
        bot.send_message(message.chat.id, "Нет точек")
        return
    point = Point.select().order_by(Point.date.desc()).get()
    if point:
        point.delete_instance()
        bot.send_message(message.chat.id, "Последняя точка удалена")
Esempio n. 5
0
def break_line(message: telebot.types.Message):
    if not len(Point.select()):
        bot.send_message(message.chat.id, "Нет точек")
        return
    point = Point.select().order_by(Point.date.desc()).get()
    if point:
        point.is_newline = True
        point.save()
        bot.send_message(message.chat.id, "Линия прервана")
Esempio n. 6
0
 def __init__(self, x_center, y_center):
     size = 20
     self.corners = []
     self.corners.append(Point(x_center - size, y_center - size * 2))
     self.corners.append(
         Point(x_center + size, y_center - size * 2, self.corners[0]))
     self.corners.append(
         Point(x_center - size, y_center + size * 2, self.corners[0],
               self.corners[1]))
     self.corners.append(
         Point(x_center + size, y_center + size * 2, self.corners[0],
               self.corners[1], self.corners[2]))
Esempio n. 7
0
 def check_in(point, polygon):
     rightx = polygon.get_sorted_points()[-1].x
     leftx = polygon.get_sorted_points()[0].x
     upy = polygon.max_y
     downy = polygon.min_y
     point1 = Point.Point(random.uniform(leftx - 20., leftx - 10.), random.uniform(upy + 10., upy + 20.))
     test1 = Builder.__check_in_polygon(point1, point, polygon)
     #point1 = Point.Point([random.uniform(rightx + 10., rightx + 20.), random.uniform(upy + 10., upy + 20.)])
     #test2 = Builder.__check_in_polygon(point1, point, polygon)
     test2 = test1
     if test1 != test2:
         point1 = Point.Point(random.uniform(rightx + 10., rightx + 20.), random.uniform(downy - 20., downy - 10.))
         return Builder.__check_in_polygon(point1, point, polygon)
     else:
         return test1
Esempio n. 8
0
    def find_element(self, el):
        for i in range(len(self.square.matrix)):
            for j in range(len(self.square.matrix[i])):
                if self.square.matrix[i][j] == el:
                    return Point.Point(i, j)

        return False
Esempio n. 9
0
    def _loadAnimationData(self, obj):
        prot = self.protocol
        animationName = obj.getFileName(
        )  # assumes that obj.getFileName is the folder of animation
        animationPath = prot._getExtraPath(animationName)
        #animationName = animationPath.split('animation_')[-1]
        animationRoot = join(animationPath, animationName)

        animationSuffixes = ['.vmd', '.pdb', 'trajectory.txt']
        for s in animationSuffixes:
            f = animationRoot + s
            if not exists(f):
                self.errorMessage('Animation file "%s" not found. ' % f)
                return

        # Load animation trajectory points
        trajectoryPoints = np.loadtxt(animationRoot + 'trajectory.txt')
        data = PathData(dim=trajectoryPoints.shape[1])

        for i, row in enumerate(trajectoryPoints):
            data.addPoint(Point(pointId=i + 1, data=list(row), weight=1))

        self.trajectoriesWindow.setPathData(data)
        self.trajectoriesWindow.setAnimationName(animationName)
        self.trajectoriesWindow._onUpdateClick()

        def _showVmd():
            vmdFn = animationRoot + '.vmd'
            VmdView(' -e %s' % vmdFn).show()

        self.getTkRoot().after(500, _showVmd)
Esempio n. 10
0
def add_lines_for_step_dependencies(recipe, step):
    for dependency in step.depends_on:
        dep_step = recipe.steps[dependency]
        split_x = step.svg.svg_x - x_spacing
        color = dep_step.temperature
        start = Point(x=dep_step.svg.svg_x, y=dep_step.svg.svg_y)
        end = Point(x=step.svg.svg_x, y=step.svg.svg_y)
        if dep_step.svg.svg_x >= split_x:
            line = Line(start=start, end=end, color=color)
            recipe.timeline.lines.append(line)
        else:
            middle = Point(x=split_x, y=dep_step.svg.svg_y)
            line1 = Line(start=start, end=middle, color=color)
            line2 = Line(start=middle, end=end, color=color)
            recipe.timeline.lines.append(line1)
            recipe.timeline.lines.append(line2)
Esempio n. 11
0
async def index(request):

    points = Point.select()

    init_point = points[0] if points else default_point_factory()

    lines = [line for line in split_list(points, lambda p: p.is_newline)]

    return {
        "points": points,
        "token": yandex,
        "init_point": init_point,
        "lines": lines
    }
Esempio n. 12
0
    def __init__(self):
        self.screen_width = 600
        self.screen_height = 300
        self.window = None
        self.screen = None
        self._pygame_setup()
        self.assets = load_assets()
        self.block_size = 16
        self.focus = Point(0, 0)
        self.biome = "normal"
        self.fullscreen = False

        pygame.display.set_caption('Onward')
        pygame.display.set_icon(self.assets["other"]["icon"])
Esempio n. 13
0
def add_timeline_to_data(recipe):
    deepest_y = 0
    for step in recipe.steps:
        if step.svg.y > deepest_y:
            deepest_y = step.svg.y
    height = y_offset * 2 + y_spacing * (deepest_y - 1)
    recipe.timeline = Timeline(height=height)

    for step in recipe.steps:
        position_on_timeline = Point(x=step.svg.svg_x, y=step.svg.svg_y)
        circle = Circle(color=step.temperature,
                        center=position_on_timeline,
                        step_type=step.step_type)
        recipe.timeline.circles.append(circle)
        add_lines_for_step_dependencies(recipe, step)
Esempio n. 14
0
    def loadData(self):
        """ Iterate over the images and their deformations 
        to create a Data object with theirs Points.
        """
        particles = self.protocol.outputParticles

        data = Data()
        for i, particle in enumerate(particles):
            pointData = map(float, particle._xmipp_nmaDisplacements)
            data.addPoint(
                Point(pointId=particle.getObjId(),
                      data=pointData,
                      weight=particle._xmipp_cost.get()))

        return data
Esempio n. 15
0
    def loadData(self):
        """ Iterate over the images and the output matrix txt file
        and create a Data object with theirs Points.
        """
        matrix = np.loadtxt(self.protocol.getOutputMatrixFile())
        particles = self.protocol.getInputParticles()

        data = Data()
        for i, particle in enumerate(particles):
            data.addPoint(
                Point(pointId=particle.getObjId(),
                      data=matrix[i, :],
                      weight=particle._xmipp_cost.get()))

        return data
Esempio n. 16
0
 def get_polygons_from_shape(shape):
     parts = list(shape.parts)
     del parts[0]
     num = len(shape.points)
     buf = []
     res_polygons = []
     for i in xrange(num):
         if len(parts) > 0 and i == parts[0] and len(buf) > 0:
             res_polygons.append(Polygon.Polygon(buf))
             buf = []
             del parts[0]
         pt = shape.points[i]
         buf.append(Point.Point(pt[0], pt[1]))
     if len(buf) > 0:
         res_polygons.append(Polygon.Polygon(buf))
     return res_polygons
Esempio n. 17
0
 def get_sorted_polygons_from_shape(shape, now_ind):
     parts = shape.parts
     current_part = 1
     num = len(shape.points)
     buf = []
     res_polygons = []
     for i in xrange(num):
         if len(parts) > current_part and i == parts[current_part] and len(buf) > 0:
             res_polygons.append(SortedPolygon.SortedPolygon(buf, now_ind))
             now_ind += 1
             buf = []
             current_part += 1
         pt = shape.points[i]
         buf.append(Point.Point(pt[0], pt[1]))
     if len(buf) > 0:
         res_polygons.append(SortedPolygon.SortedPolygon(buf, now_ind))
         now_ind += 1
     return res_polygons, now_ind
Esempio n. 18
0
    def test_area(self):
        """Test area."""
        track = Track(
            Person([
                KeyPoint(BodyPart(0), Point(0.1, 0.2), 1),
                KeyPoint(BodyPart(1), Point(0.3, 0.4), 0.9),
                KeyPoint(BodyPart(2), Point(0.4, 0.6), 0.9),
                KeyPoint(BodyPart(3), Point(0.7, 0.8), 0.1)
            ], Rectangle(Point(0, 0), Point(0, 0)), 1), 1000000)

        area = self.kpt_tracker._area(track)
        expected_area = (0.4 - 0.1) * (0.6 - 0.2)
        self.assertAlmostEqual(area, expected_area, 6)
Esempio n. 19
0
import asyncio
from asyncbot import bot
from webserver import WebServer
from data import Point

server = WebServer()


if __name__ == '__main__':

    # Create database if not exists
    Point.create_table()

    loop = asyncio.get_event_loop()
    loop.create_task(server.run())
    loop.create_task(bot.async_polling())
    loop.run_forever()
Esempio n. 20
0
 def set_focus(self, x, y):
     self.focus = Point(x, y)
Esempio n. 21
0
    def test_oks_returns_zero(self):
        """Compute OKS returns 0.0 with less than 2 valid keypoints."""
        person = Person([
            KeyPoint(BodyPart(0), Point(0.2, 0.2), 1),
            KeyPoint(BodyPart(1), Point(0.4, 0.4), 0.1),
            KeyPoint(BodyPart(2), Point(0.6, 0.6), 0.9),
            KeyPoint(BodyPart(3), Point(0.8, 0.8), 0.8)
        ], Rectangle(Point(0, 0), Point(0, 0)), 1)
        track = Track(
            Person([
                KeyPoint(BodyPart(0), Point(0.2, 0.2), 1),
                KeyPoint(BodyPart(1), Point(0.4, 0.4), 0.8),
                KeyPoint(BodyPart(2), Point(0.6, 0.6), 0.1),
                KeyPoint(BodyPart(3), Point(0.8, 0.8), 0.1)
            ], Rectangle(Point(0, 0), Point(0, 0)), 1), 1000000)

        oks = self.kpt_tracker._object_keypoint_similarity(person, track)
        self.assertAlmostEqual(oks, 0.0, 6)
Esempio n. 22
0
    def test_oks(self):
        """Test OKS."""
        person = Person([
            KeyPoint(BodyPart(0), Point(0.2, 0.2), 1),
            KeyPoint(BodyPart(1), Point(0.4, 0.4), 0.8),
            KeyPoint(BodyPart(2), Point(0.6, 0.6), 0.1),
            KeyPoint(BodyPart(3), Point(0.8, 0.7), 0.8)
        ], Rectangle(Point(0, 0), Point(0, 0)), 1)
        track = Track(
            Person([
                KeyPoint(BodyPart(0), Point(0.2, 0.2), 1),
                KeyPoint(BodyPart(1), Point(0.4, 0.4), 0.8),
                KeyPoint(BodyPart(2), Point(0.6, 0.6), 0.9),
                KeyPoint(BodyPart(3), Point(0.8, 0.8), 0.8)
            ], Rectangle(Point(0, 0), Point(0, 0)), 1), 1000000)

        oks = self.kpt_tracker._object_keypoint_similarity(person, track)

        box_area = (0.8 - 0.2) * (0.8 - 0.2)
        x = 2 * self.tracker_config.keypoint_tracker_params.keypoint_falloff[3]
        d = 0.1
        expected_oks = (1 + 1 + math.exp(-1 * (d**2) / (2 * box_area *
                                                        (x**2)))) / 3

        self.assertAlmostEqual(oks, expected_oks, 6)
Esempio n. 23
0
    def test_keypoint_tracker(self):
        """Test Keypoint tracker."""

        # Timestamp: 0. Person becomes the only track
        persons = [
            Person([
                KeyPoint(BodyPart(0), Point(0.2, 0.2), 1),
                KeyPoint(BodyPart(1), Point(0.4, 0.4), 0.8),
                KeyPoint(BodyPart(2), Point(0.6, 0.6), 0.9),
                KeyPoint(BodyPart(3), Point(0.8, 0.8), 0.0)
            ], Rectangle(Point(0, 0), Point(0, 0)), 1)
        ]

        persons = self.kpt_tracker.apply(persons, 0)
        tracks = self.kpt_tracker._tracks
        self.assertEqual(len(persons), 1)
        self.assertEqual(persons[0].id, 1)
        self.assertEqual(len(tracks), 1)
        self.assertEqual(tracks[0].person.id, 1)
        self.assertEqual(tracks[0].last_timestamp, 0)

        # Timestamp: 100000. First person is linked with track 1. Second person
        # spawns a new track (id = 2).
        persons = [
            Person([
                KeyPoint(BodyPart(0), Point(0.2, 0.2), 1),
                KeyPoint(BodyPart(1), Point(0.4, 0.4), 0.8),
                KeyPoint(BodyPart(2), Point(0.6, 0.6), 0.9),
                KeyPoint(BodyPart(3), Point(0.8, 0.8), 0.8)
            ], Rectangle(Point(0, 0), Point(0, 0)), 1),
            Person(
                [
                    KeyPoint(BodyPart(0), Point(0.8, 0.8), 0.8),
                    KeyPoint(BodyPart(1), Point(0.6, 0.6), 0.3),
                    KeyPoint(BodyPart(2), Point(0.4, 0.4),
                             0.1),  # Low confidence.
                    KeyPoint(BodyPart(3), Point(0.2, 0.2), 0.8)
                ],
                Rectangle(Point(0, 0), Point(0, 0)),
                1)
        ]

        persons = self.kpt_tracker.apply(persons, 100000)
        tracks = self.kpt_tracker._tracks
        self.assertEqual(len(persons), 2)
        self.assertEqual(persons[0].id, 1)
        self.assertEqual(persons[1].id, 2)
        self.assertEqual(len(tracks), 2)
        self.assertEqual(tracks[0].person.id, 1)
        self.assertEqual(tracks[0].last_timestamp, 100000)
        self.assertEqual(tracks[1].person.id, 2)
        self.assertEqual(tracks[1].last_timestamp, 100000)

        # Timestamp: 900000. First person is linked with track 2. Second person
        # spawns a new track (id = 3).
        persons = [  # Links with id = 2.
            Person(
                [
                    KeyPoint(BodyPart(0), Point(0.6, 0.7), 0.7),
                    KeyPoint(BodyPart(1), Point(0.5, 0.6), 0.7),
                    KeyPoint(BodyPart(2), Point(0.0, 0.0),
                             0.1),  # Low confidence.
                    KeyPoint(BodyPart(3), Point(0.2, 0.1), 1.0)
                ],
                Rectangle(Point(0, 0), Point(0, 0)),
                1),
            # Becomes id = 3.
            Person(
                [
                    KeyPoint(BodyPart(0), Point(0.5, 0.1), 0.6),
                    KeyPoint(BodyPart(1), Point(0.9, 0.3), 0.6),
                    KeyPoint(BodyPart(2), Point(0.1, 0.1), 0.9),
                    KeyPoint(BodyPart(3), Point(0.4, 0.4), 0.1)
                ],  # Low confidence.
                Rectangle(Point(0, 0), Point(0, 0)),
                1)
        ]

        persons = self.kpt_tracker.apply(persons, 900000)
        tracks = self.kpt_tracker._tracks
        self.assertEqual(len(persons), 2)
        self.assertEqual(persons[0].id, 2)
        self.assertEqual(persons[1].id, 3)
        self.assertEqual(len(tracks), 3)
        self.assertEqual(tracks[0].person.id, 2)
        self.assertEqual(tracks[0].last_timestamp, 900000)
        self.assertEqual(tracks[1].person.id, 3)
        self.assertEqual(tracks[1].last_timestamp, 900000)
        self.assertEqual(tracks[2].person.id, 1)
        self.assertEqual(tracks[2].last_timestamp, 100000)

        # Timestamp: 1200000. First person spawns a new track (id = 4), even though
        # it has the same keypoints as track 1. This is because the age exceeds
        # 1000 msec. The second person links with id 2. The third person spawns a
        # new track (id = 5).
        persons = [  # Becomes id = 4.
            Person([
                KeyPoint(BodyPart(0), Point(0.2, 0.2), 1.0),
                KeyPoint(BodyPart(1), Point(0.4, 0.4), 0.8),
                KeyPoint(BodyPart(2), Point(0.6, 0.6), 0.9),
                KeyPoint(BodyPart(3), Point(0.8, 0.8), 0.8)
            ], Rectangle(Point(0, 0), Point(0, 0)), 1),
            # Links with id = 2.
            Person(
                [
                    KeyPoint(BodyPart(0), Point(0.55, 0.7), 0.7),
                    KeyPoint(BodyPart(1), Point(0.5, 0.6), 0.9),
                    KeyPoint(BodyPart(2), Point(1.0, 1.0),
                             0.1),  # Low confidence.
                    KeyPoint(BodyPart(3), Point(0.8, 0.1), 0.0)
                ],  # Low confidence.
                Rectangle(Point(0, 0), Point(0, 0)),
                1),
            # Becomes id = 5.
            Person(
                [
                    KeyPoint(BodyPart(0), Point(0.1, 0.1),
                             0.1),  # Low confidence.
                    KeyPoint(BodyPart(1), Point(0.2, 0.2), 0.9),
                    KeyPoint(BodyPart(2), Point(0.3, 0.3), 0.7),
                    KeyPoint(BodyPart(3), Point(0.4, 0.4), 0.8)
                ],
                Rectangle(Point(0, 0), Point(0, 0)),
                1)
        ]

        persons = self.kpt_tracker.apply(persons, 1200000)
        tracks = self.kpt_tracker._tracks
        self.assertEqual(len(persons), 3)
        self.assertEqual(persons[0].id, 4)
        self.assertEqual(persons[1].id, 2)
        self.assertEqual(len(tracks), 4)
        self.assertEqual(tracks[0].person.id, 2)
        self.assertEqual(tracks[0].last_timestamp, 1200000)
        self.assertEqual(tracks[1].person.id, 4)
        self.assertEqual(tracks[1].last_timestamp, 1200000)
        self.assertEqual(tracks[2].person.id, 5)
        self.assertEqual(tracks[2].last_timestamp, 1200000)
        self.assertEqual(tracks[3].person.id, 3)
        self.assertEqual(tracks[3].last_timestamp, 900000)

        # Timestamp: 1300000. First person spawns a new track (id = 6). Since
        # max_tracks is 4, the oldest track (id = 3) is removed.
        persons = [  # Becomes id = 6.
            Person([
                KeyPoint(BodyPart(0), Point(0.1, 0.8), 1.0),
                KeyPoint(BodyPart(1), Point(0.2, 0.9), 0.6),
                KeyPoint(BodyPart(2), Point(0.2, 0.9), 0.5),
                KeyPoint(BodyPart(3), Point(0.8, 0.2), 0.4)
            ], Rectangle(Point(0, 0), Point(0, 0)), 1)
        ]

        persons = self.kpt_tracker.apply(persons, 1300000)
        tracks = self.kpt_tracker._tracks
        self.assertEqual(len(persons), 1)
        self.assertEqual(persons[0].id, 6)
        self.assertEqual(len(tracks), 4)
        self.assertEqual(tracks[0].person.id, 6)
        self.assertEqual(tracks[0].last_timestamp, 1300000)
        self.assertEqual(tracks[1].person.id, 2)
        self.assertEqual(tracks[1].last_timestamp, 1200000)
        self.assertEqual(tracks[2].person.id, 4)
        self.assertEqual(tracks[2].last_timestamp, 1200000)
        self.assertEqual(tracks[3].person.id, 5)
        self.assertEqual(tracks[3].last_timestamp, 1200000)
Esempio n. 24
0
    def _postprocess(self, keypoints_with_scores: np.ndarray,
                     image_height: int, image_width: int,
                     detection_threshold: float) -> List[Person]:
        """Returns a list "Person" corresponding to the input image.

    Note that coordinates are expressed in (x, y) format for drawing
    utilities.

    Args:
      keypoints_with_scores: Output of the MultiPose TFLite model.
      image_height: height of the image in pixels.
      image_width: width of the image in pixels.
      detection_threshold: minimum confidence score for an entity to be
        considered.

    Returns:
      A list of Person(keypoints, bounding_box, scores), each containing:
        * the coordinates of all keypoints of the detected entity;
        * the bounding boxes of the entity.
        * the confidence core of the entity.
    """

        _, num_instances, _ = keypoints_with_scores.shape
        list_persons = []
        for idx in range(num_instances):
            # Skip a detected pose if its confidence score is below the threshold
            person_score = keypoints_with_scores[0, idx, 55]
            if person_score < detection_threshold:
                continue

            # Extract the keypoint coordinates and scores
            kpts_y = keypoints_with_scores[0, idx, range(0, 51, 3)]
            kpts_x = keypoints_with_scores[0, idx, range(1, 51, 3)]
            scores = keypoints_with_scores[0, idx, range(2, 51, 3)]

            # Create the list of keypoints
            keypoints = []
            for i in range(scores.shape[0]):
                keypoints.append(
                    KeyPoint(
                        BodyPart(i),
                        Point(int(kpts_x[i] * image_width),
                              int(kpts_y[i] * image_height)), scores[i]))

            # Calculate the bounding box
            rect = [
                keypoints_with_scores[0, idx,
                                      51], keypoints_with_scores[0, idx, 52],
                keypoints_with_scores[0, idx,
                                      53], keypoints_with_scores[0, idx, 54]
            ]
            bounding_box = Rectangle(
                Point(int(rect[1] * image_width), int(rect[0] * image_height)),
                Point(int(rect[3] * image_width), int(rect[2] * image_height)))

            # Create a Person instance corresponding to the detected entity.
            list_persons.append(Person(keypoints, bounding_box, person_score))
        if self._tracker:
            list_persons = self._tracker.apply(list_persons,
                                               time.time() * 1000)

        return list_persons
Esempio n. 25
0
 def test_iou_full_overlap(self):
   """Test IoU full overlap."""
   person = Person([], Rectangle(Point(0, 0), Point(1, 1)), 1)
   track = Track(Person([], Rectangle(Point(0, 0), Point(1, 1)), 1), 1000000)
   computed_iou = self.bbox_tracker._iou(person, track)
   self.assertAlmostEqual(computed_iou, 1.0, 6)
Esempio n. 26
0
 def mid_point(points):
     return Point(sum(points) / len(points))
Esempio n. 27
0
  def test_bounding_box_tracker(self):
    """Test BoundingBoxTracker."""

    # Timestamp: 0. Person becomes the first two tracks
    persons = [
        Person([], Rectangle(Point(0, 0), Point(0.5, 0.5)), 1),
        Person(
            [],
            Rectangle(Point(0, 0), Point(1, 1)),
            1,
        )
    ]
    persons = self.bbox_tracker.apply(persons, 0)
    tracks = self.bbox_tracker._tracks
    self.assertEqual(len(persons), 2)
    self.assertEqual(persons[0].id, 1)
    self.assertEqual(persons[1].id, 2)
    self.assertEqual(len(tracks), 2)
    self.assertEqual(tracks[0].person.id, 1)
    self.assertEqual(tracks[0].last_timestamp, 0)
    self.assertEqual(tracks[1].person.id, 2)
    self.assertEqual(tracks[1].last_timestamp, 0)

    # Timestamp: 100000. First person is linked with track 1. Second person
    # spawns a new track (id = 2).
    persons = [
        Person([], Rectangle(Point(0.1, 0.1), Point(0.5, 0.5)), 1),
        Person([], Rectangle(Point(0.3, 0.2), Point(0.9, 0.9)), 1)
    ]
    persons = self.bbox_tracker.apply(persons, 100000)
    tracks = self.bbox_tracker._tracks
    self.assertEqual(len(persons), 2)
    self.assertEqual(persons[0].id, 1)
    self.assertEqual(persons[1].id, 3)
    self.assertEqual(len(tracks), 3)
    self.assertEqual(tracks[0].person.id, 1)
    self.assertEqual(tracks[0].last_timestamp, 100000)
    self.assertEqual(tracks[1].person.id, 3)
    self.assertEqual(tracks[1].last_timestamp, 100000)
    self.assertEqual(tracks[2].person.id, 2)
    self.assertEqual(tracks[2].last_timestamp, 0)

    # Timestamp: 1050000. First person is linked with track 1. Second person is
    # identical to track 2, but is not linked because track 2 is deleted due to
    # age. Instead it spawns track 4.
    persons = [
        Person([], Rectangle(Point(0.1, 0.1), Point(0.5, 0.55)), 1),
        Person([], Rectangle(Point(0, 0), Point(1, 1)), 1)
    ]
    persons = self.bbox_tracker.apply(persons, 1050000)
    tracks = self.bbox_tracker._tracks
    self.assertEqual(len(persons), 2)
    self.assertEqual(persons[0].id, 1)
    self.assertEqual(persons[1].id, 4)
    self.assertEqual(len(tracks), 3)
    self.assertEqual(tracks[0].person.id, 1)
    self.assertEqual(tracks[0].last_timestamp, 1050000)
    self.assertEqual(tracks[1].person.id, 4)
    self.assertEqual(tracks[1].last_timestamp, 1050000)
    self.assertEqual(tracks[2].person.id, 3)
    self.assertEqual(tracks[2].last_timestamp, 100000)