add ability to specify min and max area as percentages

This commit is contained in:
Josh Hawkins 2025-01-31 11:22:45 -06:00
parent 7b65bcf13c
commit 0b02fe02ea
5 changed files with 92 additions and 14 deletions

View File

@ -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,

View File

@ -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):

View File

@ -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]] = {}

View File

@ -490,12 +490,27 @@ export default function ObjectLifecycle({
Area
</p>
{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 ? (
<>
<div className="flex flex-col text-xs">
px:{" "}
{Math.round(
detectArea *
(item.data.box[2] * item.data.box[3]),
)}
</div>
<div className="flex flex-col text-xs">
%:{" "}
{(
(detectArea *
(item.data.box[2] * item.data.box[3])) /
detectArea
).toFixed(4)}
</div>
</>
) : (
"N/A"
)}
</div>
</div>
</div>

View File

@ -260,7 +260,7 @@ export default function ObjectSettingsView({
</div>
</TabsContent>
<TabsContent value="objectlist">
{ObjectList(memoizedObjects)}
<ObjectList cameraConfig={cameraConfig} objects={memoizedObjects} />
</TabsContent>
</Tabs>
</div>
@ -284,7 +284,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 +331,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 +356,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>