import { useCallback, useEffect, useMemo } from "react"; import ActivityIndicator from "@/components/indicators/activity-indicator"; import AutoUpdatingCameraImage from "@/components/camera/AutoUpdatingCameraImage"; import { CameraConfig, FrigateConfig } from "@/types/frigateConfig"; import { Toaster } from "@/components/ui/sonner"; import { Label } from "@/components/ui/label"; import useSWR from "swr"; import Heading from "@/components/ui/heading"; import { Switch } from "@/components/ui/switch"; import { usePersistence } from "@/hooks/use-persistence"; import { Skeleton } from "@/components/ui/skeleton"; import { useCameraActivity } from "@/hooks/use-camera-activity"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; import { ObjectType } from "@/types/ws"; import useDeepMemo from "@/hooks/use-deep-memo"; import { Card } from "@/components/ui/card"; import { getIconForLabel } from "@/utils/iconUtil"; import { capitalizeFirstLetter } from "@/utils/stringUtil"; type ObjectSettingsViewProps = { selectedCamera?: string; }; type Options = { [key: string]: boolean }; const emptyObject = Object.freeze({}); export default function ObjectSettingsView({ selectedCamera, }: ObjectSettingsViewProps) { const { data: config } = useSWR("config"); const DEBUG_OPTIONS = [ { param: "bbox", title: "Bounding boxes", description: "Show bounding boxes around detected objects", }, { param: "timestamp", title: "Timestamp", description: "Overlay a timestamp on the image", }, { param: "zones", title: "Zones", description: "Show an outline of any defined zones", }, { param: "mask", title: "Motion masks", description: "Show motion mask polygons", }, { param: "motion", title: "Motion boxes", description: "Show boxes around areas where motion is detected", }, { param: "regions", title: "Regions", description: "Show a box of the region of interest sent to the object detector", }, ]; const [options, setOptions, optionsLoaded] = usePersistence( `${selectedCamera}-feed`, emptyObject, ); const handleSetOption = useCallback( (id: string, value: boolean) => { const newOptions = { ...options, [id]: value }; setOptions(newOptions); }, [options, setOptions], ); const cameraConfig = useMemo(() => { if (config && selectedCamera) { return config.cameras[selectedCamera]; } }, [config, selectedCamera]); const { objects } = useCameraActivity(cameraConfig ?? ({} as CameraConfig)); const memoizedObjects = useDeepMemo(objects); const searchParams = useMemo(() => { if (!optionsLoaded) { return new URLSearchParams(); } const params = new URLSearchParams( Object.keys(options || {}).reduce((memo, key) => { //@ts-expect-error we know this is correct memo.push([key, options[key] === true ? "1" : "0"]); return memo; }, []), ); return params; }, [options, optionsLoaded]); useEffect(() => { document.title = "Object Settings - Frigate"; }, []); if (!cameraConfig) { return ; } return (
Debug

Frigate uses your detectors{" "} {config ? "(" + Object.keys(config?.detectors) .map((detector) => capitalizeFirstLetter(detector)) .join(",") + ")" : ""}{" "} to detect objects in your camera's video stream.

Debugging view shows a real-time view of detected objects and their statistics. The object list shows a time-delayed summary of detected objects.

Debugging Object List
{DEBUG_OPTIONS.map(({ param, title, description }) => (
{description}
{ handleSetOption(param, isChecked); }} />
))}
{ObjectList(memoizedObjects)}
{cameraConfig ? (
) : ( )}
); } function ObjectList(objects?: ObjectType[]) { const { data: config } = useSWR("config"); const colormap = useMemo(() => { if (!config) { return; } return config.model?.colormap; }, [config]); const getColorForObjectName = useCallback( (objectName: string) => { return colormap && colormap[objectName] ? `rgb(${colormap[objectName][2]}, ${colormap[objectName][1]}, ${colormap[objectName][0]})` : "rgb(128, 128, 128)"; }, [colormap], ); return (
{objects && objects.length > 0 ? ( objects.map((obj) => { return (
{getIconForLabel(obj.label, "size-5 text-white")}
{capitalizeFirstLetter(obj.label)}

Score

{obj.score ? (obj.score * 100).toFixed(1).toString() : "-"} %

Ratio

{obj.ratio ? obj.ratio.toFixed(2).toString() : "-"}

Area

{obj.area ? obj.area.toString() : "-"}
); }) ) : (
No objects
)}
); }