mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-04-09 08:37:37 +03:00
Display more scores in Tracking Details (#22799)
Some checks are pending
CI / AMD64 Build (push) Waiting to run
CI / ARM Build (push) Waiting to run
CI / Jetson Jetpack 6 (push) Waiting to run
CI / AMD64 Extra Build (push) Blocked by required conditions
CI / ARM Extra Build (push) Blocked by required conditions
CI / Synaptics Build (push) Blocked by required conditions
CI / Assemble and push default build (push) Blocked by required conditions
Some checks are pending
CI / AMD64 Build (push) Waiting to run
CI / ARM Build (push) Waiting to run
CI / Jetson Jetpack 6 (push) Waiting to run
CI / AMD64 Extra Build (push) Blocked by required conditions
CI / ARM Extra Build (push) Blocked by required conditions
CI / Synaptics Build (push) Blocked by required conditions
CI / Assemble and push default build (push) Blocked by required conditions
* add computed and top score to timeline entries * frontend * docs
This commit is contained in:
parent
dfe365cd28
commit
5d2a725428
@ -24,6 +24,12 @@ For object filters, any single detection below `min_score` will be ignored as a
|
||||
|
||||
In frame 2, the score is below the `min_score` value, so Frigate ignores it and it becomes a 0.0. The computed score is the median of the score history (padding to at least 3 values), and only when that computed score crosses the `threshold` is the object marked as a true positive. That happens in frame 4 in the example.
|
||||
|
||||
The **top score** is the highest computed score the tracked object has ever reached during its lifetime. Because the computed score rises and falls as new frames come in, the top score can be thought of as the peak confidence Frigate had in the object. In Frigate's UI (such as the Tracking Details pane in Explore), you may see all three values:
|
||||
|
||||
- **Score** — the raw detector score for that single frame.
|
||||
- **Computed Score** — the median of the most recent score history at that moment. This is the value compared against `threshold`.
|
||||
- **Top Score** — the highest computed score reached so far for the tracked object.
|
||||
|
||||
### Minimum Score
|
||||
|
||||
Any detection below `min_score` will be immediately thrown out and never tracked because it is considered a false positive. If `min_score` is too low then false positives may be detected and tracked which can confuse the object tracker and may lead to wasted resources. If `min_score` is too high then lower scoring true positives like objects that are further away or partially occluded may be thrown out which can also confuse the tracker and cause valid tracked objects to be lost or disjointed.
|
||||
|
||||
@ -116,6 +116,8 @@ class TimelineProcessor(threading.Thread):
|
||||
),
|
||||
"attribute": "",
|
||||
"score": event_data["score"],
|
||||
"computed_score": event_data.get("computed_score"),
|
||||
"top_score": event_data.get("top_score"),
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@ -400,6 +400,7 @@ class TrackedObject:
|
||||
"start_time": self.obj_data["start_time"],
|
||||
"end_time": self.obj_data.get("end_time", None),
|
||||
"score": self.obj_data["score"],
|
||||
"computed_score": self.computed_score,
|
||||
"box": self.obj_data["box"],
|
||||
"area": self.obj_data["area"],
|
||||
"ratio": self.obj_data["ratio"],
|
||||
|
||||
@ -62,7 +62,10 @@
|
||||
"zones": "Zones",
|
||||
"ratio": "Ratio",
|
||||
"area": "Area",
|
||||
"score": "Score"
|
||||
"score": "Score",
|
||||
"computedScore": "Computed Score",
|
||||
"topScore": "Top Score",
|
||||
"toggleAdvancedScores": "Toggle advanced scores"
|
||||
}
|
||||
},
|
||||
"annotationSettings": {
|
||||
|
||||
@ -9,7 +9,12 @@ import { FrigateConfig } from "@/types/frigateConfig";
|
||||
import { formatUnixTimestampToDateTime } from "@/utils/dateUtil";
|
||||
import { use24HourTime } from "@/hooks/use-date-utils";
|
||||
import { getIconForLabel } from "@/utils/iconUtil";
|
||||
import { LuCircle, LuFolderX } from "react-icons/lu";
|
||||
import {
|
||||
LuChevronDown,
|
||||
LuChevronRight,
|
||||
LuCircle,
|
||||
LuFolderX,
|
||||
} from "react-icons/lu";
|
||||
import { cn } from "@/lib/utils";
|
||||
import HlsVideoPlayer from "@/components/player/HlsVideoPlayer";
|
||||
import { baseUrl } from "@/api/baseUrl";
|
||||
@ -899,6 +904,7 @@ function LifecycleIconRow({
|
||||
const { t } = useTranslation(["views/explore", "components/player"]);
|
||||
const { data: config } = useSWR<FrigateConfig>("config");
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const [showAdvancedScores, setShowAdvancedScores] = useState(false);
|
||||
const navigate = useNavigate();
|
||||
const isAdmin = useIsAdmin();
|
||||
|
||||
@ -993,12 +999,31 @@ function LifecycleIconRow({
|
||||
[item.data.box],
|
||||
);
|
||||
|
||||
const score = useMemo(() => {
|
||||
if (item.data.score !== undefined) {
|
||||
return (item.data.score * 100).toFixed(0) + "%";
|
||||
}
|
||||
return "N/A";
|
||||
}, [item.data.score]);
|
||||
const currentScore = useMemo(
|
||||
() =>
|
||||
item.data.score !== undefined
|
||||
? (item.data.score * 100).toFixed(0) + "%"
|
||||
: null,
|
||||
[item.data.score],
|
||||
);
|
||||
const computedScore = useMemo(
|
||||
() =>
|
||||
item.data.computed_score !== undefined &&
|
||||
item.data.computed_score !== null &&
|
||||
item.data.computed_score > 0
|
||||
? (item.data.computed_score * 100).toFixed(0) + "%"
|
||||
: null,
|
||||
[item.data.computed_score],
|
||||
);
|
||||
const topScore = useMemo(
|
||||
() =>
|
||||
item.data.top_score !== undefined &&
|
||||
item.data.top_score !== null &&
|
||||
item.data.top_score > 0
|
||||
? (item.data.top_score * 100).toFixed(0) + "%"
|
||||
: null,
|
||||
[item.data.top_score],
|
||||
);
|
||||
|
||||
return (
|
||||
<div
|
||||
@ -1034,8 +1059,50 @@ function LifecycleIconRow({
|
||||
<span className="text-primary-variant">
|
||||
{t("trackingDetails.lifecycleItemDesc.header.score")}
|
||||
</span>
|
||||
<span className="font-medium text-primary">{score}</span>
|
||||
<span className="font-medium text-primary">
|
||||
{currentScore ?? "N/A"}
|
||||
</span>
|
||||
{(computedScore || topScore) && (
|
||||
<button
|
||||
type="button"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
setShowAdvancedScores((v) => !v);
|
||||
}}
|
||||
className="ml-1 inline-flex items-center text-primary-variant hover:text-primary"
|
||||
aria-expanded={showAdvancedScores}
|
||||
aria-label={t(
|
||||
"trackingDetails.lifecycleItemDesc.header.toggleAdvancedScores",
|
||||
)}
|
||||
>
|
||||
{showAdvancedScores ? (
|
||||
<LuChevronDown className="size-3.5" />
|
||||
) : (
|
||||
<LuChevronRight className="size-3.5" />
|
||||
)}
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
{showAdvancedScores && computedScore && (
|
||||
<div className="flex items-center gap-1.5">
|
||||
<span className="text-primary-variant">
|
||||
{t(
|
||||
"trackingDetails.lifecycleItemDesc.header.computedScore",
|
||||
)}
|
||||
</span>
|
||||
<span className="font-medium text-primary">
|
||||
{computedScore}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
{showAdvancedScores && topScore && (
|
||||
<div className="flex items-center gap-1.5">
|
||||
<span className="text-primary-variant">
|
||||
{t("trackingDetails.lifecycleItemDesc.header.topScore")}
|
||||
</span>
|
||||
<span className="font-medium text-primary">{topScore}</span>
|
||||
</div>
|
||||
)}
|
||||
<div className="flex items-center gap-1.5">
|
||||
<span className="text-primary-variant">
|
||||
{t("trackingDetails.lifecycleItemDesc.header.ratio")}
|
||||
|
||||
@ -17,6 +17,8 @@ export type TrackingDetailsSequence = {
|
||||
camera: string;
|
||||
label: string;
|
||||
score: number;
|
||||
computed_score?: number;
|
||||
top_score?: number;
|
||||
sub_label: string;
|
||||
box?: [number, number, number, number];
|
||||
region: [number, number, number, number];
|
||||
|
||||
Loading…
Reference in New Issue
Block a user