From d3ce58cbf43c9acce6244d8ee71e86380dca1694 Mon Sep 17 00:00:00 2001 From: Josh Hawkins <32435876+hawkeye217@users.noreply.github.com> Date: Fri, 20 Dec 2024 12:56:02 -0600 Subject: [PATCH] add average speed --- docs/docs/configuration/zones.md | 2 +- frigate/api/event.py | 2 ++ frigate/events/maintainer.py | 3 ++ frigate/track/tracked_object.py | 23 +++++++++---- .../overlay/detail/SearchDetailDialog.tsx | 34 ++++++++++++++++--- web/src/types/search.ts | 1 + 6 files changed, 52 insertions(+), 13 deletions(-) diff --git a/docs/docs/configuration/zones.md b/docs/docs/configuration/zones.md index 0edfea299..6570c78af 100644 --- a/docs/docs/configuration/zones.md +++ b/docs/docs/configuration/zones.md @@ -153,7 +153,7 @@ ui: unit_system: metric ``` -The maximum speed during the object's lifetime is saved in Frigate's database and can be seen in the UI in the Tracked Object Details pane in Explore. Current estimated speed can also be seen on the debug view as the third value in the object label. Current estimated speed, max estimated speed, and velocity angle (the angle of the direction the object is moving relative to the frame) of tracked objects is also sent through the `events` MQTT topic. See the [MQTT docs](../integrations/mqtt.md#frigateevents). +The average and maximum speed during the object's lifetime is saved in Frigate's database and can be seen in the UI in the Tracked Object Details pane in Explore. Current estimated speed can also be seen on the debug view as the third value in the object label. Current estimated speed, average estimated speed, max estimated speed, and velocity angle (the angle of the direction the object is moving relative to the frame) of tracked objects is also sent through the `events` MQTT topic. See the [MQTT docs](../integrations/mqtt.md#frigateevents). #### Best practices and caveats diff --git a/frigate/api/event.py b/frigate/api/event.py index d362a82bc..6c77d20fd 100644 --- a/frigate/api/event.py +++ b/frigate/api/event.py @@ -322,6 +322,7 @@ def events_explore(limit: int = 10): "top_score", "description", "sub_label_score", + "average_estimated_speed", "max_estimated_speed", ] }, @@ -595,6 +596,7 @@ def events_search(request: Request, params: EventsSearchQueryParams = Depends()) "top_score", "description", "sub_label_score", + "average_estimated_speed", "max_estimated_speed", ] } diff --git a/frigate/events/maintainer.py b/frigate/events/maintainer.py index 0dcfad509..a3d770f87 100644 --- a/frigate/events/maintainer.py +++ b/frigate/events/maintainer.py @@ -25,6 +25,8 @@ def should_update_db(prev_event: Event, current_event: Event) -> bool: or prev_event["entered_zones"] != current_event["entered_zones"] or prev_event["thumbnail"] != current_event["thumbnail"] or prev_event["end_time"] != current_event["end_time"] + or prev_event["average_estimated_speed"] + != current_event["average_estimated_speed"] or prev_event["max_estimated_speed"] != current_event["max_estimated_speed"] ): return True @@ -210,6 +212,7 @@ class EventProcessor(threading.Thread): "score": score, "top_score": event_data["top_score"], "attributes": attributes, + "average_estimated_speed": event_data["average_estimated_speed"], "max_estimated_speed": event_data["max_estimated_speed"], "type": "object", "max_severity": event_data.get("max_severity"), diff --git a/frigate/track/tracked_object.py b/frigate/track/tracked_object.py index e3bc62c5b..73ce8e541 100644 --- a/frigate/track/tracked_object.py +++ b/frigate/track/tracked_object.py @@ -62,7 +62,9 @@ class TrackedObject: self.frame = None self.active = True self.pending_loitering = False - self.estimated_speed = 0 + self.speed_history = [] + self.current_estimated_speed = 0 + self.average_estimated_speed = 0 self.max_estimated_speed = 0 self.velocity_angle = 0 self.previous = self.to_dict() @@ -197,16 +199,22 @@ class TrackedObject: ) if self.ui_config.unit_system == "metric": # Convert m/s to km/h - self.estimated_speed = speed_magnitude * 3.6 + self.current_estimated_speed = speed_magnitude * 3.6 elif self.ui_config.unit_system == "imperial": # Convert ft/s to mph - self.estimated_speed = speed_magnitude * 0.681818 + self.current_estimated_speed = speed_magnitude * 0.681818 + logger.debug( - f"Camera: {self.camera_config.name}, zone: {name}, tracked object ID: {self.obj_data['id']}, pixel velocity: {str(tuple(np.round(self.obj_data['estimate_velocity']).flatten().astype(int)))} estimated speed: {self.estimated_speed:.1f}" + f"Camera: {self.camera_config.name}, zone: {name}, tracked object ID: {self.obj_data['id']}, pixel velocity: {str(tuple(np.round(self.obj_data['estimate_velocity']).flatten().astype(int)))} estimated speed: {self.current_estimated_speed:.1f}" ) - if self.estimated_speed > self.max_estimated_speed: - self.max_estimated_speed = self.estimated_speed + self.speed_history.append(self.current_estimated_speed) + self.average_estimated_speed = sum(self.speed_history) / len( + self.speed_history + ) + + if self.current_estimated_speed > self.max_estimated_speed: + self.max_estimated_speed = self.current_estimated_speed # update loitering status self.pending_loitering = in_loitering_zone @@ -289,7 +297,8 @@ class TrackedObject: "current_attributes": self.obj_data["attributes"], "pending_loitering": self.pending_loitering, "max_severity": self.max_severity, - "estimated_speed": self.estimated_speed, + "current_estimated_speed": self.current_estimated_speed, + "average_estimated_speed": self.average_estimated_speed, "max_estimated_speed": self.max_estimated_speed, "velocity_angle": self.velocity_angle, } diff --git a/web/src/components/overlay/detail/SearchDetailDialog.tsx b/web/src/components/overlay/detail/SearchDetailDialog.tsx index dc03eef5a..6ad388b4d 100644 --- a/web/src/components/overlay/detail/SearchDetailDialog.tsx +++ b/web/src/components/overlay/detail/SearchDetailDialog.tsx @@ -316,6 +316,18 @@ function ObjectDetailsTab({ } }, [search]); + const averageEstimatedSpeed = useMemo(() => { + if (!search || !search.data?.average_estimated_speed) { + return undefined; + } + + if (search.data?.average_estimated_speed != 0) { + return search.data?.average_estimated_speed.toFixed(1); + } else { + return undefined; + } + }, [search]); + const maxEstimatedSpeed = useMemo(() => { if (!search || !search.data?.max_estimated_speed) { return undefined; @@ -439,12 +451,24 @@ function ObjectDetailsTab({ {score}%{subLabelScore && ` (${subLabelScore}%)`} - {maxEstimatedSpeed && ( + {(averageEstimatedSpeed || maxEstimatedSpeed) && (
-
Max Estimated Speed
-
- {maxEstimatedSpeed}{" "} - {config?.ui.unit_system == "imperial" ? "mph" : "kph"} +
Estimated Speeds
+
+ {averageEstimatedSpeed && ( +
+ {averageEstimatedSpeed}{" "} + {config?.ui.unit_system == "imperial" ? "mph" : "kph"}{" "} + (average) +
+ )} + {maxEstimatedSpeed && ( +
+ {maxEstimatedSpeed}{" "} + {config?.ui.unit_system == "imperial" ? "mph" : "kph"}{" "} + (maximum) +
+ )}
)} diff --git a/web/src/types/search.ts b/web/src/types/search.ts index 223370e9a..91fb33e50 100644 --- a/web/src/types/search.ts +++ b/web/src/types/search.ts @@ -55,6 +55,7 @@ export type SearchResult = { ratio: number; type: "object" | "audio" | "manual"; description?: string; + average_estimated_speed: number; max_estimated_speed: number; }; };