Compare commits

...
3 Commits
Author SHA1 Message Date
DanielandGitHub 07f2a82c5a Merge 1c9396449e into bb5056a68a 2026-06-22 12:06:22 -04:00
mayerwinandGitHub bb5056a68a docs: correct face_recognition min_area default to 750 (#23535) 2026-06-22 06:38:52 -06:00
Daniel-dev22andClaude Opus 4.8 1c9396449e perf(track): add __slots__ to TrackedObjectAttribute
TrackedObjectAttribute is constructed per attribute (face, license plate,
logo, ...) per frame in process_frames. It holds exactly six fixed fields
and is never mutated beyond __init__, so __slots__ removes the per-instance
__dict__.

Measured in the release image: 352 B/instance (56 B object + 296 B __dict__)
-> ~104 B with __slots__, ~70% smaller, on a high-churn per-frame object.

Adds a test asserting no __dict__ and that undeclared attributes raise.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-20 09:57:01 -04:00
3 changed files with 19 additions and 2 deletions
+2 -2
View File
@@ -86,7 +86,7 @@ Navigate to <NavPath path="Settings > Enrichments > Face recognition" />.
- **Detection threshold**: Face detection confidence score required before recognition runs. This field only applies to the standalone face detection model; `min_score` should be used to filter for models that have face detection built in.
- Default: `0.7`
- **Minimum face area**: Minimum size (in pixels) a face must be before recognition runs. Depending on the resolution of your camera's `detect` stream, you can increase this value to ignore small or distant faces.
- Default: `500` pixels
- Default: `750` pixels
</TabItem>
<TabItem value="yaml">
@@ -95,7 +95,7 @@ Navigate to <NavPath path="Settings > Enrichments > Face recognition" />.
face_recognition:
enabled: true
detection_threshold: 0.7
min_area: 500
min_area: 750
```
</TabItem>
+15
View File
@@ -3,6 +3,21 @@ import unittest
from frigate.track.tracked_object import TrackedObjectAttribute
class TestAttributeSlots(unittest.TestCase):
def test_attribute_uses_slots(self) -> None:
attribute = TrackedObjectAttribute(
("amazon", 0.8, (847, 242, 883, 255), 468, 2.77, (702, 134, 1050, 482))
)
# __slots__ means no per-instance __dict__
self.assertFalse(hasattr(attribute, "__dict__"))
# all declared fields are still populated and readable
self.assertEqual(attribute.label, "amazon")
self.assertEqual(attribute.region, (702, 134, 1050, 482))
# setting an undeclared attribute must raise (catches accidental drift)
with self.assertRaises(AttributeError):
attribute.unexpected = 1
class TestAttribute(unittest.TestCase):
def test_overlapping_object_selection(self) -> None:
attribute = TrackedObjectAttribute(
+2
View File
@@ -574,6 +574,8 @@ def zone_filtered(obj: TrackedObject, object_config: dict[str, FilterConfig]) ->
class TrackedObjectAttribute:
__slots__ = ("label", "score", "box", "area", "ratio", "region")
def __init__(self, raw_data: tuple) -> None:
self.label = raw_data[0]
self.score = raw_data[1]