Object area debugging and improvements (#16432)

* add ability to specify min and max area as percentages

* debug draw area and ratio

* docs

* update for best percentage
This commit is contained in:
Josh Hawkins
2025-02-09 15:48:23 -06:00
committed by GitHub
parent 83beacf84a
commit c8cec63cb9
8 changed files with 352 additions and 21 deletions

View File

@@ -1,4 +1,4 @@
import { useCallback, useEffect, useMemo } from "react";
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import ActivityIndicator from "@/components/indicators/activity-indicator";
import AutoUpdatingCameraImage from "@/components/camera/AutoUpdatingCameraImage";
import { CameraConfig, FrigateConfig } from "@/types/frigateConfig";
@@ -23,6 +23,9 @@ import { getIconForLabel } from "@/utils/iconUtil";
import { capitalizeFirstLetter } from "@/utils/stringUtil";
import { LuExternalLink, LuInfo } from "react-icons/lu";
import { Link } from "react-router-dom";
import DebugDrawingLayer from "@/components/overlay/DebugDrawingLayer";
import { Separator } from "@/components/ui/separator";
import { isDesktop } from "react-device-detect";
type ObjectSettingsViewProps = {
selectedCamera?: string;
@@ -37,6 +40,8 @@ export default function ObjectSettingsView({
}: ObjectSettingsViewProps) {
const { data: config } = useSWR<FrigateConfig>("config");
const containerRef = useRef<HTMLDivElement>(null);
const DEBUG_OPTIONS = [
{
param: "bbox",
@@ -130,6 +135,12 @@ export default function ObjectSettingsView({
[options, setOptions],
);
const [debugDraw, setDebugDraw] = useState(false);
useEffect(() => {
setDebugDraw(false);
}, [selectedCamera]);
const cameraConfig = useMemo(() => {
if (config && selectedCamera) {
return config.cameras[selectedCamera];
@@ -234,7 +245,7 @@ export default function ObjectSettingsView({
<span className="sr-only">Info</span>
</div>
</PopoverTrigger>
<PopoverContent className="w-80">
<PopoverContent className="w-80 text-sm">
{info}
</PopoverContent>
</Popover>
@@ -256,18 +267,74 @@ export default function ObjectSettingsView({
</div>
))}
</div>
{isDesktop && (
<>
<Separator className="my-2" />
<div className="flex w-full flex-row items-center justify-between">
<div className="mb-2 flex flex-col">
<div className="flex items-center gap-2">
<Label
className="mb-0 cursor-pointer capitalize text-primary"
htmlFor="debugdraw"
>
Object Shape Filter Drawing
</Label>
<Popover>
<PopoverTrigger asChild>
<div className="cursor-pointer p-0">
<LuInfo className="size-4" />
<span className="sr-only">Info</span>
</div>
</PopoverTrigger>
<PopoverContent className="w-80 text-sm">
Enable this option to draw a rectangle on the
camera image to show its area and ratio. These
values can then be used to set object shape filter
parameters in your config.
<div className="mt-2 flex items-center text-primary">
<Link
to="https://docs.frigate.video/configuration/object_filters#object-shape"
target="_blank"
rel="noopener noreferrer"
className="inline"
>
Read the documentation{" "}
<LuExternalLink className="ml-2 inline-flex size-3" />
</Link>
</div>
</PopoverContent>
</Popover>
</div>
<div className="mt-1 text-xs text-muted-foreground">
Draw a rectangle on the image to view area and ratio
details
</div>
</div>
<Switch
key={`$draw-${selectedCamera}`}
className="ml-1"
id="debug_draw"
checked={debugDraw}
onCheckedChange={(isChecked) => {
setDebugDraw(isChecked);
}}
/>
</div>
</>
)}
</div>
</div>
</TabsContent>
<TabsContent value="objectlist">
{ObjectList(memoizedObjects)}
<ObjectList cameraConfig={cameraConfig} objects={memoizedObjects} />
</TabsContent>
</Tabs>
</div>
{cameraConfig ? (
<div className="flex md:h-dvh md:max-h-full md:w-7/12 md:grow">
<div className="size-full min-h-10">
<div ref={containerRef} className="relative size-full min-h-10">
<AutoUpdatingCameraImage
camera={cameraConfig.name}
searchParams={searchParams}
@@ -275,6 +342,13 @@ export default function ObjectSettingsView({
className="size-full"
cameraClasses="relative w-full h-full flex flex-col justify-start"
/>
{debugDraw && (
<DebugDrawingLayer
containerRef={containerRef}
cameraWidth={cameraConfig.detect.width}
cameraHeight={cameraConfig.detect.height}
/>
)}
</div>
</div>
) : (
@@ -284,7 +358,12 @@ export default function ObjectSettingsView({
);
}
function ObjectList(objects?: ObjectType[]) {
type ObjectListProps = {
cameraConfig: CameraConfig;
objects?: ObjectType[];
};
function ObjectList({ cameraConfig, objects }: ObjectListProps) {
const { data: config } = useSWR<FrigateConfig>("config");
const colormap = useMemo(() => {
@@ -326,7 +405,7 @@ function ObjectList(objects?: ObjectType[]) {
{capitalizeFirstLetter(obj.label.replaceAll("_", " "))}
</div>
</div>
<div className="flex w-8/12 flex-row items-end justify-end">
<div className="flex w-8/12 flex-row items-center justify-end">
<div className="text-md mr-2 w-1/3">
<div className="flex flex-col items-end justify-end">
<p className="mb-1.5 text-sm text-primary-variant">
@@ -351,7 +430,25 @@ function ObjectList(objects?: ObjectType[]) {
<p className="mb-1.5 text-sm text-primary-variant">
Area
</p>
{obj.area ? obj.area.toString() : "-"}
{obj.area ? (
<>
<div className="text-xs">
px: {obj.area.toString()}
</div>
<div className="text-xs">
%:{" "}
{(
obj.area /
(cameraConfig.detect.width *
cameraConfig.detect.height)
)
.toFixed(4)
.toString()}
</div>
</>
) : (
"-"
)}
</div>
</div>
</div>