diff --git a/docs/docs/configuration/index.md b/docs/docs/configuration/index.md index d40d235b9..1644903a1 100644 --- a/docs/docs/configuration/index.md +++ b/docs/docs/configuration/index.md @@ -467,6 +467,8 @@ cameras: # Required: List of x,y coordinates to define the polygon of the zone. # NOTE: Presence in a zone is evaluated only based on the bottom center of the objects bounding box. coordinates: 545,1077,747,939,788,805 + # Optional: Number of consecutive frames required for object to be considered present in the zone. Allowed values are 1-10 (default: shown below) + inertia: 3 # Optional: List of objects that can trigger this zone (default: all tracked objects) objects: - person diff --git a/frigate/config.py b/frigate/config.py index 43a43be0d..58545e27c 100644 --- a/frigate/config.py +++ b/frigate/config.py @@ -330,6 +330,12 @@ class ZoneConfig(BaseModel): coordinates: Union[str, List[str]] = Field( title="Coordinates polygon for the defined zone." ) + inertia: int = Field( + default=3, + title="Number of consecutive frames required for object to be considered present in the zone.", + gt=0, + le=10, + ) objects: List[str] = Field( default_factory=list, title="List of objects that can trigger the zone.", diff --git a/frigate/object_processing.py b/frigate/object_processing.py index f9046d0ab..6455f6eba 100644 --- a/frigate/object_processing.py +++ b/frigate/object_processing.py @@ -73,6 +73,7 @@ class TrackedObject: self.colormap = colormap self.camera_config = camera_config self.frame_cache = frame_cache + self.zone_presence = {} self.current_zones = [] self.entered_zones = [] self.false_positive = True @@ -144,13 +145,24 @@ class TrackedObject: if len(zone.objects) > 0 and obj_data["label"] not in zone.objects: continue contour = zone.contour + zone_score = self.zone_presence.get(name, 0) # check if the object is in the zone if cv2.pointPolygonTest(contour, bottom_center, False) >= 0: - # if the object passed the filters once, dont apply again - if name in self.current_zones or not zone_filtered(self, zone.filters): - current_zones.append(name) - if name not in self.entered_zones: - self.entered_zones.append(name) + self.zone_presence[name] = zone_score + 1 + + # an object is only considered present in a zone if it has a zone inertia of 3+ + if zone_score >= zone.inertia: + # if the object passed the filters once, dont apply again + if name in self.current_zones or not zone_filtered( + self, zone.filters + ): + current_zones.append(name) + if name not in self.entered_zones: + self.entered_zones.append(name) + else: + # once an object has a zone inertia of 3+ it is not checked anymore + if 0 < zone_score < zone.inertia: + self.zone_presence[name] = zone_score - 1 if not self.false_positive: # if the zones changed, signal an update