From 0b02fe02ea016c6efab4d379f2c6ba83a0c77ed9 Mon Sep 17 00:00:00 2001 From: Josh Hawkins <32435876+hawkeye217@users.noreply.github.com> Date: Fri, 31 Jan 2025 11:22:45 -0600 Subject: [PATCH] add ability to specify min and max area as percentages --- frigate/config/camera/objects.py | 10 +++--- frigate/config/config.py | 8 +++++ frigate/util/config.py | 30 ++++++++++++++++++ .../overlay/detail/ObjectLifecycle.tsx | 27 ++++++++++++---- web/src/views/settings/ObjectSettingsView.tsx | 31 ++++++++++++++++--- 5 files changed, 92 insertions(+), 14 deletions(-) diff --git a/frigate/config/camera/objects.py b/frigate/config/camera/objects.py index 22cd92f1c..ce24a09b0 100644 --- a/frigate/config/camera/objects.py +++ b/frigate/config/camera/objects.py @@ -11,11 +11,13 @@ DEFAULT_TRACKED_OBJECTS = ["person"] class FilterConfig(FrigateBaseModel): - min_area: int = Field( - default=0, title="Minimum area of bounding box for object to be counted." + min_area: Union[int, float] = Field( + default=0, + title="Minimum area of bounding box for object to be counted. Can be pixels (int) or percentage (float between 0.01 and 0.99).", ) - max_area: int = Field( - default=24000000, title="Maximum area of bounding box for object to be counted." + max_area: Union[int, float] = Field( + default=24000000, + title="Maximum area of bounding box for object to be counted. Can be pixels (int) or percentage (float between 0.01 and 0.99).", ) min_ratio: float = Field( default=0, diff --git a/frigate/config/config.py b/frigate/config/config.py index 43db89b4f..869b51aff 100644 --- a/frigate/config/config.py +++ b/frigate/config/config.py @@ -29,6 +29,7 @@ from frigate.util.builtin import ( ) from frigate.util.config import ( StreamInfoRetriever, + convert_area_to_pixels, find_config_file, get_relative_coordinates, migrate_frigate_config, @@ -143,6 +144,13 @@ class RuntimeFilterConfig(FilterConfig): if mask is not None: config["mask"] = create_mask(frame_shape, mask) + # Convert min_area and max_area to pixels if they're percentages + if "min_area" in config: + config["min_area"] = convert_area_to_pixels(config["min_area"], frame_shape) + + if "max_area" in config: + config["max_area"] = convert_area_to_pixels(config["max_area"], frame_shape) + super().__init__(**config) def dict(self, **kwargs): diff --git a/frigate/util/config.py b/frigate/util/config.py index d456c7557..a8664ea4e 100644 --- a/frigate/util/config.py +++ b/frigate/util/config.py @@ -347,6 +347,36 @@ def get_relative_coordinates( return mask +def convert_area_to_pixels( + area_value: Union[int, float], frame_shape: tuple[int, int] +) -> int: + """ + Convert area specification to pixels. + + Args: + area_value: Area value (pixels or percentage) + frame_shape: Tuple of (height, width) for the frame + + Returns: + Area in pixels + """ + # If already an integer, assume it's in pixels + if isinstance(area_value, int): + return area_value + + # Check if it's a percentage + if isinstance(area_value, float): + if 0.000001 <= area_value <= 0.99: + frame_area = frame_shape[0] * frame_shape[1] + return max(1, int(frame_area * area_value)) + else: + raise ValueError( + f"Percentage must be between 0.000001 and 0.99, got {area_value}" + ) + + raise TypeError(f"Unexpected type for area: {type(area_value)}") + + class StreamInfoRetriever: def __init__(self) -> None: self.stream_cache: dict[str, tuple[int, int]] = {} diff --git a/web/src/components/overlay/detail/ObjectLifecycle.tsx b/web/src/components/overlay/detail/ObjectLifecycle.tsx index 9512e4a7e..d61b5fa56 100644 --- a/web/src/components/overlay/detail/ObjectLifecycle.tsx +++ b/web/src/components/overlay/detail/ObjectLifecycle.tsx @@ -490,12 +490,27 @@ export default function ObjectLifecycle({ Area
{Array.isArray(item.data.box) && - item.data.box.length >= 4 - ? Math.round( - detectArea * - (item.data.box[2] * item.data.box[3]), - ) - : "N/A"} + item.data.box.length >= 4 ? ( + <> +@@ -351,7 +356,25 @@ function ObjectList(objects?: ObjectType[]) {
Area
- {obj.area ? obj.area.toString() : "-"} + {obj.area ? ( + <> +