Improve Object Lifecycle pane (#16635)

* add path point tracking to backend

* types

* draw paths on lifecycle pane

* make points clickable

* don't display a path if we don't have any saved path points

* only object lifecycle points should have a click handler

* change to debug log

* better debug log message
This commit is contained in:
Josh Hawkins
2025-02-17 09:37:17 -07:00
committed by GitHub
parent 3f07d2d37c
commit 124d92daa9
6 changed files with 245 additions and 16 deletions
+2
View File
@@ -336,6 +336,7 @@ def events_explore(limit: int = 10):
"sub_label_score",
"average_estimated_speed",
"velocity_angle",
"path_data",
]
},
"event_count": label_counts[event.label],
@@ -622,6 +623,7 @@ def events_search(request: Request, params: EventsSearchQueryParams = Depends())
"sub_label_score",
"average_estimated_speed",
"velocity_angle",
"path_data",
]
}
+2
View File
@@ -28,6 +28,7 @@ def should_update_db(prev_event: Event, current_event: Event) -> bool:
or prev_event["average_estimated_speed"]
!= current_event["average_estimated_speed"]
or prev_event["velocity_angle"] != current_event["velocity_angle"]
or prev_event["path_data"] != current_event["path_data"]
):
return True
return False
@@ -217,6 +218,7 @@ class EventProcessor(threading.Thread):
"velocity_angle": event_data["velocity_angle"],
"type": "object",
"max_severity": event_data.get("max_severity"),
"path_data": event_data.get("path_data"),
},
}
+27
View File
@@ -2,6 +2,7 @@
import base64
import logging
import math
from collections import defaultdict
from statistics import median
from typing import Optional
@@ -66,6 +67,7 @@ class TrackedObject:
self.current_estimated_speed = 0
self.average_estimated_speed = 0
self.velocity_angle = 0
self.path_data = []
self.previous = self.to_dict()
@property
@@ -148,6 +150,7 @@ class TrackedObject:
"attributes": obj_data["attributes"],
"current_estimated_speed": self.current_estimated_speed,
"velocity_angle": self.velocity_angle,
"path_data": self.path_data,
}
thumb_update = True
@@ -300,6 +303,29 @@ class TrackedObject:
if self.obj_data["frame_time"] - self.previous["frame_time"] >= (1 / 3):
autotracker_update = True
# update path
width = self.camera_config.detect.width
height = self.camera_config.detect.height
bottom_center = (
round(obj_data["centroid"][0] / width, 4),
round(obj_data["box"][3] / height, 4),
)
# calculate a reasonable movement threshold (e.g., 5% of the frame diagonal)
threshold = 0.05 * math.sqrt(width**2 + height**2) / max(width, height)
if not self.path_data:
self.path_data.append((bottom_center, obj_data["frame_time"]))
elif (
math.dist(self.path_data[-1][0], bottom_center) >= threshold
or len(self.path_data) == 1
):
# check Euclidean distance before appending
self.path_data.append((bottom_center, obj_data["frame_time"]))
logger.debug(
f"Point tracking: {obj_data['id']}, {bottom_center}, {obj_data['frame_time']}"
)
self.obj_data.update(obj_data)
self.current_zones = current_zones
return (thumb_update, significant_change, autotracker_update)
@@ -336,6 +362,7 @@ class TrackedObject:
"current_estimated_speed": self.current_estimated_speed,
"average_estimated_speed": self.average_estimated_speed,
"velocity_angle": self.velocity_angle,
"path_data": self.path_data,
}
if include_thumbnail: