diff --git a/moonwalk.py b/moonwalk.py index 2866a07..f9cb4a4 100644 --- a/moonwalk.py +++ b/moonwalk.py @@ -18,21 +18,33 @@ import numpy as np # from deep_sort_realtime.deepsort_tracker import DeepSort from sort import Sort from collections import defaultdict +import math + Interval = float # seconds logger = logging.getLogger('moonwalk') +colorset = [(0, 0, 0), + (0, 0, 255), + (0, 255, 0), + (0, 255, 255), + (255, 0, 0), + (255, 0, 255), + (255, 255, 0) + ] + + @dataclass class Params: visual_variability: float = 0 - video_fps: float = 25 - tracker_fps: float = 25 + # video_fps: float = 60 + tracker_fps: float = 5.6 # iou = None - emitter_speed: float = 1 # objects per second - object_velocity: float = 40 # pixels/second + emitter_speed: float = 4 # objects per second + object_velocity: float = 80 # pixels/second velocity_decay: float = 1 # make system a bit springy def add_listener(self, attr: str, callback: callable): @@ -109,6 +121,20 @@ class ObjectEmitter: self.lastEmit = 0 return [obj] return [] + +class MissingDict(dict): + """ + collections.defaultdict does not accept arguments, but this is what we want/need. + This implementation should do the trick + """ + def __init__(self, factory: callable, values={}): + self.update(values) + self.factory = factory + + def __missing__(self, key): + self[key] = self.factory(key) + return self[key] + class Canvas: @@ -162,14 +188,22 @@ class Canvas: self.labels[field.name] = pyglet.text.Label(f"{field.name}: {field.default}", x=20, y=30 + 15*(i+1), color=(255,255,255,255), batch=self.batch_info) # TODO: Add a number next to the box using pyglet.graphics.Group() - self.track_shapes = defaultdict(lambda: pyglet.shapes.Box(0,0,0,0,color=(0,255,0),thickness=2, batch=self.batch_bounding_boxes)) + self.track_shapes = MissingDict(self.getTrackBboxShapes) - self.tracker = Sort(max_age=5, min_hits=2, iou_threshold=0) #DeepSort(max_age=5) + self.tracker = Sort(max_age=5, min_hits=1, iou_threshold=0) #DeepSort(max_age=5) pyglet.clock.schedule_interval(self.on_track, 1/self.params.tracker_fps) self.interval_items: list[pyglet.clock._ScheduledIntervalItem] = [i for i in pyglet.clock._default._schedule_interval_items if i.func == self.on_track] self.params.add_listener('tracker_fps', self.on_tracker_fps_change) + + def getTrackBboxShapes(self, track_id): + color = colorset[int(track_id) % len(colorset)] + return [ + pyglet.shapes.Box(0,0,0,0,color=color,thickness=2, batch=self.batch_bounding_boxes), + pyglet.text.Label(f"{track_id:.0f}", x=0, y=0, anchor_y='top', color=color, batch=self.batch_info), + # pyglet.shapes.Lab(0,0,0,0,color=(0,255,0),thickness=2, batch=self.batch_bounding_boxes) + ] def on_tracker_fps_change(self, field, old_value, new_value): """ @@ -303,10 +337,20 @@ class Canvas: for track in self.tracks: nr = track[4] - self.track_shapes[nr].x = track[0] - self.track_shapes[nr].y = track[1] - self.track_shapes[nr].width = track[2] - track[0] - self.track_shapes[nr].height = track[3] - track[1] + for shape in self.track_shapes[nr]: + if shape.x == 0 and shape.y == 0: + # set initial position + shape.x = track[0] + shape.y = track[1] + shape.width = track[2] - track[0] + shape.height = track[3] - track[1] + else: + # exponential decay + shape.x = exponentialDecay(shape.x, track[0], 12, dt) + shape.y = exponentialDecay(shape.y, track[1], 12, dt) + shape.width = exponentialDecay(shape.width, track[2] - track[0], 12, dt) + shape.height = exponentialDecay(shape.height, track[3] - track[1], 12, dt) + # TODO: shape in DetectedObject # rectangle = shapes.Rectangle(250, 300, 400, 200, color=(255, 22, 20), batch=batch) @@ -316,7 +360,12 @@ class Canvas: # id(objects) - +def exponentialDecay(a, b, decay, dt): + """Exponential decay as alternative to Lerp + Introduced by Freya Holmér: https://www.youtube.com/watch?v=LSNQuFEDOyQ + """ + return b + (a-b) * math.exp(-decay * dt) + if __name__ == "__main__":