add average speed

This commit is contained in:
Josh Hawkins 2024-12-20 12:56:02 -06:00
parent 03db156c20
commit d3ce58cbf4
6 changed files with 52 additions and 13 deletions

View File

@ -153,7 +153,7 @@ ui:
unit_system: metric 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 #### Best practices and caveats

View File

@ -322,6 +322,7 @@ def events_explore(limit: int = 10):
"top_score", "top_score",
"description", "description",
"sub_label_score", "sub_label_score",
"average_estimated_speed",
"max_estimated_speed", "max_estimated_speed",
] ]
}, },
@ -595,6 +596,7 @@ def events_search(request: Request, params: EventsSearchQueryParams = Depends())
"top_score", "top_score",
"description", "description",
"sub_label_score", "sub_label_score",
"average_estimated_speed",
"max_estimated_speed", "max_estimated_speed",
] ]
} }

View File

@ -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["entered_zones"] != current_event["entered_zones"]
or prev_event["thumbnail"] != current_event["thumbnail"] or prev_event["thumbnail"] != current_event["thumbnail"]
or prev_event["end_time"] != current_event["end_time"] 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"] or prev_event["max_estimated_speed"] != current_event["max_estimated_speed"]
): ):
return True return True
@ -210,6 +212,7 @@ class EventProcessor(threading.Thread):
"score": score, "score": score,
"top_score": event_data["top_score"], "top_score": event_data["top_score"],
"attributes": attributes, "attributes": attributes,
"average_estimated_speed": event_data["average_estimated_speed"],
"max_estimated_speed": event_data["max_estimated_speed"], "max_estimated_speed": event_data["max_estimated_speed"],
"type": "object", "type": "object",
"max_severity": event_data.get("max_severity"), "max_severity": event_data.get("max_severity"),

View File

@ -62,7 +62,9 @@ class TrackedObject:
self.frame = None self.frame = None
self.active = True self.active = True
self.pending_loitering = False 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.max_estimated_speed = 0
self.velocity_angle = 0 self.velocity_angle = 0
self.previous = self.to_dict() self.previous = self.to_dict()
@ -197,16 +199,22 @@ class TrackedObject:
) )
if self.ui_config.unit_system == "metric": if self.ui_config.unit_system == "metric":
# Convert m/s to km/h # 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": elif self.ui_config.unit_system == "imperial":
# Convert ft/s to mph # Convert ft/s to mph
self.estimated_speed = speed_magnitude * 0.681818 self.current_estimated_speed = speed_magnitude * 0.681818
logger.debug( 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.speed_history.append(self.current_estimated_speed)
self.max_estimated_speed = self.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 # update loitering status
self.pending_loitering = in_loitering_zone self.pending_loitering = in_loitering_zone
@ -289,7 +297,8 @@ class TrackedObject:
"current_attributes": self.obj_data["attributes"], "current_attributes": self.obj_data["attributes"],
"pending_loitering": self.pending_loitering, "pending_loitering": self.pending_loitering,
"max_severity": self.max_severity, "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, "max_estimated_speed": self.max_estimated_speed,
"velocity_angle": self.velocity_angle, "velocity_angle": self.velocity_angle,
} }

View File

@ -316,6 +316,18 @@ function ObjectDetailsTab({
} }
}, [search]); }, [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(() => { const maxEstimatedSpeed = useMemo(() => {
if (!search || !search.data?.max_estimated_speed) { if (!search || !search.data?.max_estimated_speed) {
return undefined; return undefined;
@ -439,12 +451,24 @@ function ObjectDetailsTab({
{score}%{subLabelScore && ` (${subLabelScore}%)`} {score}%{subLabelScore && ` (${subLabelScore}%)`}
</div> </div>
</div> </div>
{maxEstimatedSpeed && ( {(averageEstimatedSpeed || maxEstimatedSpeed) && (
<div className="flex flex-col gap-1.5"> <div className="flex flex-col gap-1.5">
<div className="text-sm text-primary/40">Max Estimated Speed</div> <div className="text-sm text-primary/40">Estimated Speeds</div>
<div className="text-sm"> <div className="flex flex-col space-y-0.5 text-sm">
{maxEstimatedSpeed}{" "} {averageEstimatedSpeed && (
{config?.ui.unit_system == "imperial" ? "mph" : "kph"} <div>
{averageEstimatedSpeed}{" "}
{config?.ui.unit_system == "imperial" ? "mph" : "kph"}{" "}
<span className="text-primary/40">(average)</span>
</div>
)}
{maxEstimatedSpeed && (
<div>
{maxEstimatedSpeed}{" "}
{config?.ui.unit_system == "imperial" ? "mph" : "kph"}{" "}
<span className="text-primary/40">(maximum)</span>
</div>
)}
</div> </div>
</div> </div>
)} )}

View File

@ -55,6 +55,7 @@ export type SearchResult = {
ratio: number; ratio: number;
type: "object" | "audio" | "manual"; type: "object" | "audio" | "manual";
description?: string; description?: string;
average_estimated_speed: number;
max_estimated_speed: number; max_estimated_speed: number;
}; };
}; };