From d97b451d126aea3cf41b3cc5bfa34a0f0a5c9992 Mon Sep 17 00:00:00 2001 From: Josh Hawkins <32435876+hawkeye217@users.noreply.github.com> Date: Mon, 7 Jul 2025 09:33:19 -0500 Subject: [PATCH] Optionally show tracked object paths in debug view (#19025) --- .../api/defs/query/media_query_parameters.py | 1 + frigate/api/media.py | 1 + frigate/camera/state.py | 39 +++++++++++++++++++ web/public/locales/en/views/settings.json | 5 +++ .../components/camera/DebugCameraImage.tsx | 10 +++++ web/src/views/settings/ObjectSettingsView.tsx | 6 +++ 6 files changed, 62 insertions(+) diff --git a/frigate/api/defs/query/media_query_parameters.py b/frigate/api/defs/query/media_query_parameters.py index cf06c71e1..fd53af49a 100644 --- a/frigate/api/defs/query/media_query_parameters.py +++ b/frigate/api/defs/query/media_query_parameters.py @@ -18,6 +18,7 @@ class MediaLatestFrameQueryParams(BaseModel): zones: Optional[int] = None mask: Optional[int] = None motion: Optional[int] = None + paths: Optional[int] = None regions: Optional[int] = None quality: Optional[int] = 70 height: Optional[int] = None diff --git a/frigate/api/media.py b/frigate/api/media.py index 1e7c8179f..516a8e1f2 100644 --- a/frigate/api/media.py +++ b/frigate/api/media.py @@ -141,6 +141,7 @@ def latest_frame( "zones": params.zones, "mask": params.mask, "motion_boxes": params.motion, + "paths": params.paths, "regions": params.regions, } quality = params.quality diff --git a/frigate/camera/state.py b/frigate/camera/state.py index d863d1040..1b08a236f 100644 --- a/frigate/camera/state.py +++ b/frigate/camera/state.py @@ -228,6 +228,45 @@ class CameraState: position=self.camera_config.timestamp_style.position, ) + if draw_options.get("paths"): + for obj in tracked_objects.values(): + if obj["frame_time"] == frame_time and obj["path_data"]: + color = self.config.model.colormap.get( + obj["label"], (255, 255, 255) + ) + + path_points = [ + ( + int(point[0][0] * self.camera_config.detect.width), + int(point[0][1] * self.camera_config.detect.height), + ) + for point in obj["path_data"] + ] + + for point in path_points: + cv2.circle(frame_copy, point, 5, color, -1) + + for i in range(1, len(path_points)): + cv2.line( + frame_copy, + path_points[i - 1], + path_points[i], + color, + 2, + ) + + bottom_center = ( + int((obj["box"][0] + obj["box"][2]) / 2), + int(obj["box"][3]), + ) + cv2.line( + frame_copy, + path_points[-1], + bottom_center, + color, + 2, + ) + return frame_copy def finished(self, obj_id): diff --git a/web/public/locales/en/views/settings.json b/web/public/locales/en/views/settings.json index fc2b5aa7b..ffdfe6d1a 100644 --- a/web/public/locales/en/views/settings.json +++ b/web/public/locales/en/views/settings.json @@ -439,6 +439,11 @@ "desc": "Show a box of the region of interest sent to the object detector", "tips": "
Region Boxes
Bright green boxes will be overlaid on areas of interest in the frame that are being sent to the object detector.
" }, + "paths": { + "title": "Paths", + "desc": "Show significant points of the tracked object's path", + "tips": "Paths
Lines and circles will indicate significant points the tracked object has moved during its lifecycle.
" + }, "objectShapeFilterDrawing": { "title": "Object Shape Filter Drawing", "desc": "Draw a rectangle on the image to view area and ratio details", diff --git a/web/src/components/camera/DebugCameraImage.tsx b/web/src/components/camera/DebugCameraImage.tsx index 3d840d0d3..bc3b6a8c3 100644 --- a/web/src/components/camera/DebugCameraImage.tsx +++ b/web/src/components/camera/DebugCameraImage.tsx @@ -158,6 +158,16 @@ function DebugSettings({ handleSetOption, options }: DebugSettingsProps) { /> +