Skip to content

Commit 5221c75

Browse files
authored
Merge pull request #36 from hawkeye217/object-speed
Object speed
2 parents ec56e92 + c708e3b commit 5221c75

File tree

8 files changed

+101
-21
lines changed

8 files changed

+101
-21
lines changed

docs/docs/configuration/zones.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@ ui:
153153
unit_system: metric
154154
```
155155

156-
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).
156+
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). These speed values are output as a number in miles per hour (mph) or kilometers per hour (kph), depending on how `unit_system` is configured in your `ui` config.
157157

158158
#### Best practices and caveats
159159

frigate/api/event.py

+19-2
Original file line numberDiff line numberDiff line change
@@ -316,7 +316,15 @@ def process_events():
316316
k: v
317317
for k, v in event.data.items()
318318
if k
319-
in ["type", "score", "top_score", "description", "sub_label_score"]
319+
in [
320+
"type",
321+
"score",
322+
"top_score",
323+
"description",
324+
"sub_label_score",
325+
"average_estimated_speed",
326+
"max_estimated_speed",
327+
]
320328
},
321329
"event_count": label_counts[event.label],
322330
}
@@ -581,7 +589,16 @@ def events_search(request: Request, params: EventsSearchQueryParams = Depends())
581589
processed_event["data"] = {
582590
k: v
583591
for k, v in event["data"].items()
584-
if k in ["type", "score", "top_score", "description"]
592+
if k
593+
in [
594+
"type",
595+
"score",
596+
"top_score",
597+
"description",
598+
"sub_label_score",
599+
"average_estimated_speed",
600+
"max_estimated_speed",
601+
]
585602
}
586603

587604
if event["id"] in search_results:

frigate/events/maintainer.py

+3
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ def should_update_db(prev_event: Event, current_event: Event) -> bool:
2525
or prev_event["entered_zones"] != current_event["entered_zones"]
2626
or prev_event["thumbnail"] != current_event["thumbnail"]
2727
or prev_event["end_time"] != current_event["end_time"]
28+
or prev_event["average_estimated_speed"]
29+
!= current_event["average_estimated_speed"]
2830
or prev_event["max_estimated_speed"] != current_event["max_estimated_speed"]
2931
):
3032
return True
@@ -211,6 +213,7 @@ def handle_object_detection(
211213
"score": score,
212214
"top_score": event_data["top_score"],
213215
"attributes": attributes,
216+
"average_estimated_speed": event_data["average_estimated_speed"],
214217
"max_estimated_speed": event_data["max_estimated_speed"],
215218
"type": "object",
216219
"max_severity": event_data.get("max_severity"),

frigate/track/tracked_object.py

+18-8
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,9 @@ def __init__(
6262
self.frame = None
6363
self.active = True
6464
self.pending_loitering = False
65-
self.estimated_speed = 0
65+
self.speed_history = []
66+
self.current_estimated_speed = 0
67+
self.average_estimated_speed = 0
6668
self.max_estimated_speed = 0
6769
self.velocity_angle = 0
6870
self.previous = self.to_dict()
@@ -193,20 +195,27 @@ def update(self, current_frame_time: float, obj_data, has_valid_frame: bool):
193195
self.camera_config.detect.fps,
194196
)
195197
if self.active
196-
else 0
198+
else (0, 0)
197199
)
198200
if self.ui_config.unit_system == "metric":
199201
# Convert m/s to km/h
200-
self.estimated_speed = speed_magnitude * 3.6
202+
self.current_estimated_speed = speed_magnitude * 3.6
201203
elif self.ui_config.unit_system == "imperial":
202204
# Convert ft/s to mph
203-
self.estimated_speed = speed_magnitude * 0.681818
205+
self.current_estimated_speed = speed_magnitude * 0.681818
206+
204207
logger.debug(
205-
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}"
208+
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}"
206209
)
207210

208-
if self.estimated_speed > self.max_estimated_speed:
209-
self.max_estimated_speed = self.estimated_speed
211+
if self.active:
212+
self.speed_history.append(self.current_estimated_speed)
213+
self.average_estimated_speed = sum(self.speed_history) / len(
214+
self.speed_history
215+
)
216+
217+
if self.current_estimated_speed > self.max_estimated_speed:
218+
self.max_estimated_speed = self.current_estimated_speed
210219

211220
# update loitering status
212221
self.pending_loitering = in_loitering_zone
@@ -289,7 +298,8 @@ def to_dict(self, include_thumbnail: bool = False):
289298
"current_attributes": self.obj_data["attributes"],
290299
"pending_loitering": self.pending_loitering,
291300
"max_severity": self.max_severity,
292-
"estimated_speed": self.estimated_speed,
301+
"current_estimated_speed": self.current_estimated_speed,
302+
"average_estimated_speed": self.average_estimated_speed,
293303
"max_estimated_speed": self.max_estimated_speed,
294304
"velocity_angle": self.velocity_angle,
295305
}

web/src/components/overlay/detail/SearchDetailDialog.tsx

+29-5
Original file line numberDiff line numberDiff line change
@@ -316,6 +316,18 @@ function ObjectDetailsTab({
316316
}
317317
}, [search]);
318318

319+
const averageEstimatedSpeed = useMemo(() => {
320+
if (!search || !search.data?.average_estimated_speed) {
321+
return undefined;
322+
}
323+
324+
if (search.data?.average_estimated_speed != 0) {
325+
return search.data?.average_estimated_speed.toFixed(1);
326+
} else {
327+
return undefined;
328+
}
329+
}, [search]);
330+
319331
const maxEstimatedSpeed = useMemo(() => {
320332
if (!search || !search.data?.max_estimated_speed) {
321333
return undefined;
@@ -439,12 +451,24 @@ function ObjectDetailsTab({
439451
{score}%{subLabelScore && ` (${subLabelScore}%)`}
440452
</div>
441453
</div>
442-
{maxEstimatedSpeed && (
454+
{(averageEstimatedSpeed || maxEstimatedSpeed) && (
443455
<div className="flex flex-col gap-1.5">
444-
<div className="text-sm text-primary/40">Max Estimated Speed</div>
445-
<div className="text-sm">
446-
{maxEstimatedSpeed}{" "}
447-
{config?.ui.unit_system == "imperial" ? "mph" : "kph"}
456+
<div className="text-sm text-primary/40">Estimated Speeds</div>
457+
<div className="flex flex-col space-y-0.5 text-sm">
458+
{averageEstimatedSpeed && (
459+
<div>
460+
{averageEstimatedSpeed}{" "}
461+
{config?.ui.unit_system == "imperial" ? "mph" : "kph"}{" "}
462+
<span className="text-primary/40">(average)</span>
463+
</div>
464+
)}
465+
{maxEstimatedSpeed && (
466+
<div>
467+
{maxEstimatedSpeed}{" "}
468+
{config?.ui.unit_system == "imperial" ? "mph" : "kph"}{" "}
469+
<span className="text-primary/40">(maximum)</span>
470+
</div>
471+
)}
448472
</div>
449473
</div>
450474
)}

web/src/components/settings/ZoneEditPane.tsx

+28-4
Original file line numberDiff line numberDiff line change
@@ -596,7 +596,13 @@ export default function ZoneEditPane({
596596
name="lineA"
597597
render={({ field }) => (
598598
<FormItem>
599-
<FormLabel>Line A distance</FormLabel>
599+
<FormLabel>
600+
Line A distance (
601+
{config?.ui.unit_system == "imperial"
602+
? "feet"
603+
: "meters"}
604+
)
605+
</FormLabel>
600606
<FormControl>
601607
<Input
602608
{...field}
@@ -612,7 +618,13 @@ export default function ZoneEditPane({
612618
name="lineB"
613619
render={({ field }) => (
614620
<FormItem>
615-
<FormLabel>Line B distance</FormLabel>
621+
<FormLabel>
622+
Line B distance (
623+
{config?.ui.unit_system == "imperial"
624+
? "feet"
625+
: "meters"}
626+
)
627+
</FormLabel>
616628
<FormControl>
617629
<Input
618630
{...field}
@@ -628,7 +640,13 @@ export default function ZoneEditPane({
628640
name="lineC"
629641
render={({ field }) => (
630642
<FormItem>
631-
<FormLabel>Line C distance</FormLabel>
643+
<FormLabel>
644+
Line C distance (
645+
{config?.ui.unit_system == "imperial"
646+
? "feet"
647+
: "meters"}
648+
)
649+
</FormLabel>
632650
<FormControl>
633651
<Input
634652
{...field}
@@ -644,7 +662,13 @@ export default function ZoneEditPane({
644662
name="lineD"
645663
render={({ field }) => (
646664
<FormItem>
647-
<FormLabel>Line D distance</FormLabel>
665+
<FormLabel>
666+
Line D distance (
667+
{config?.ui.unit_system == "imperial"
668+
? "feet"
669+
: "meters"}
670+
)
671+
</FormLabel>
648672
<FormControl>
649673
<Input
650674
{...field}

web/src/types/search.ts

+1
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ export type SearchResult = {
5555
ratio: number;
5656
type: "object" | "audio" | "manual";
5757
description?: string;
58+
average_estimated_speed: number;
5859
max_estimated_speed: number;
5960
};
6061
};

web/src/views/settings/MasksAndZonesView.tsx

+2-1
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,8 @@ export default function MasksAndZonesView({
240240
scaledWidth,
241241
scaledHeight,
242242
),
243-
distances: zoneData.distances.map((distance) => parseFloat(distance)),
243+
distances:
244+
zoneData.distances?.map((distance) => parseFloat(distance)) ?? [],
244245
isFinished: true,
245246
color: zoneData.color,
246247
}),

0 commit comments

Comments
 (0)