Fix max_frames, improve stationary objects in masked areas (#6815)

* fix issue with max_frames

* dont consider stationary until the threshold

* require a stationary interval

* try to fix formatter issues
This commit is contained in:
Blake Blackshear 2023-06-16 07:32:43 -05:00 committed by GitHub
parent 3efa77f302
commit ca7853c087
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 30 additions and 21 deletions

View File

@ -73,7 +73,11 @@
"isort.args": ["--settings-path=./pyproject.toml"], "isort.args": ["--settings-path=./pyproject.toml"],
"[python]": { "[python]": {
"editor.defaultFormatter": "ms-python.black-formatter", "editor.defaultFormatter": "ms-python.black-formatter",
"editor.formatOnSave": true "editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.fixAll": true,
"source.organizeImports": true
}
}, },
"[json][jsonc]": { "[json][jsonc]": {
"editor.defaultFormatter": "esbenp.prettier-vscode" "editor.defaultFormatter": "esbenp.prettier-vscode"
@ -86,7 +90,7 @@
"editor.tabSize": 2 "editor.tabSize": 2
}, },
"cSpell.ignoreWords": ["rtmp"], "cSpell.ignoreWords": ["rtmp"],
"cSpell.words": ["preact"] "cSpell.words": ["preact", "astype", "hwaccel", "mqtt"]
} }
} }
} }

View File

@ -206,10 +206,10 @@ detect:
max_disappeared: 25 max_disappeared: 25
# Optional: Configuration for stationary object tracking # Optional: Configuration for stationary object tracking
stationary: stationary:
# Optional: Frequency for confirming stationary objects (default: shown below) # Optional: Frequency for confirming stationary objects (default: same as threshold)
# When set to 0, object detection will not confirm stationary objects until movement is detected. # When set to 1, object detection will run to confirm the object still exists on every frame.
# If set to 10, object detection will run to confirm the object still exists on every 10th frame. # If set to 10, object detection will run to confirm the object still exists on every 10th frame.
interval: 0 interval: 50
# Optional: Number of frames without a position change for an object to be considered stationary (default: 10x the frame rate or 10s) # Optional: Number of frames without a position change for an object to be considered stationary (default: 10x the frame rate or 10s)
threshold: 50 threshold: 50
# Optional: Define a maximum number of frames for tracking a stationary object (default: not set, track forever) # Optional: Define a maximum number of frames for tracking a stationary object (default: not set, track forever)

View File

@ -1,6 +1,6 @@
# Stationary Objects # Stationary Objects
An object is considered stationary when it is being tracked and has been in a very similar position for a certain number of frames. This number is defined in the configuration under `detect -> stationary -> threshold`, and is 10x the frame rate (or 10 seconds) by default. Once an object is considered stationary, it will remain stationary until motion occurs near the object at which point object detection will start running again. If the object changes location, it will be considered active. An object is considered stationary when it is being tracked and has been in a very similar position for a certain number of frames. This number is defined in the configuration under `detect -> stationary -> threshold`, and is 10x the frame rate (or 10 seconds) by default. Once an object is considered stationary, it will remain stationary until motion occurs within the object at which point object detection will start running again. If the object changes location, it will be considered active.
## Why does it matter if an object is stationary? ## Why does it matter if an object is stationary?
@ -13,11 +13,11 @@ The default config is:
```yaml ```yaml
detect: detect:
stationary: stationary:
interval: 0 interval: 50
threshold: 50 threshold: 50
``` ```
`interval` is defined as the frequency for running detection on stationary objects. This means that by default once an object is considered stationary, detection will not be run on it until motion is detected. With `interval > 0`, every nth frames detection will be run to make sure the object is still there. `interval` is defined as the frequency for running detection on stationary objects. This means that by default once an object is considered stationary, detection will not be run on it until motion is detected or until the interval (every 50th frame by default). With `interval >= 1`, every nth frames detection will be run to make sure the object is still there.
NOTE: There is no way to disable stationary object tracking with this value. NOTE: There is no way to disable stationary object tracking with this value.

View File

@ -13,8 +13,6 @@ from pydantic.fields import PrivateAttr
from frigate.const import CACHE_DIR, DEFAULT_DB_PATH, REGEX_CAMERA_NAME, YAML_EXT from frigate.const import CACHE_DIR, DEFAULT_DB_PATH, REGEX_CAMERA_NAME, YAML_EXT
from frigate.detectors import DetectorConfig, ModelConfig from frigate.detectors import DetectorConfig, ModelConfig
from frigate.detectors.detector_config import InputTensorEnum # noqa: F401
from frigate.detectors.detector_config import PixelFormatEnum # noqa: F401
from frigate.detectors.detector_config import BaseDetectorConfig from frigate.detectors.detector_config import BaseDetectorConfig
from frigate.ffmpeg_presets import ( from frigate.ffmpeg_presets import (
parse_preset_hardware_acceleration_decode, parse_preset_hardware_acceleration_decode,
@ -251,9 +249,8 @@ class StationaryMaxFramesConfig(FrigateBaseModel):
class StationaryConfig(FrigateBaseModel): class StationaryConfig(FrigateBaseModel):
interval: Optional[int] = Field( interval: Optional[int] = Field(
default=0,
title="Frame interval for checking stationary objects.", title="Frame interval for checking stationary objects.",
ge=0, gt=0,
) )
threshold: Optional[int] = Field( threshold: Optional[int] = Field(
title="Number of frames without a position change for an object to be considered stationary", title="Number of frames without a position change for an object to be considered stationary",
@ -963,6 +960,9 @@ class FrigateConfig(FrigateBaseModel):
stationary_threshold = camera_config.detect.fps * 10 stationary_threshold = camera_config.detect.fps * 10
if camera_config.detect.stationary.threshold is None: if camera_config.detect.stationary.threshold is None:
camera_config.detect.stationary.threshold = stationary_threshold camera_config.detect.stationary.threshold = stationary_threshold
# default to the stationary_threshold if not defined
if camera_config.detect.stationary.interval is None:
camera_config.detect.stationary.interval = stationary_threshold
# FFMPEG input substitution # FFMPEG input substitution
for input in camera_config.ffmpeg.inputs: for input in camera_config.ffmpeg.inputs:

View File

@ -10,8 +10,8 @@ from abc import ABC, abstractmethod
import numpy as np import numpy as np
from setproctitle import setproctitle from setproctitle import setproctitle
from frigate.config import InputTensorEnum
from frigate.detectors import create_detector from frigate.detectors import create_detector
from frigate.detectors.detector_config import InputTensorEnum
from frigate.util import EventsPerSecond, SharedMemoryFrameManager, listen, load_labels from frigate.util import EventsPerSecond, SharedMemoryFrameManager, listen, load_labels
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)

View File

@ -6,8 +6,9 @@ from pydantic import parse_obj_as
import frigate.detectors as detectors import frigate.detectors as detectors
import frigate.object_detection import frigate.object_detection
from frigate.config import DetectorConfig, InputTensorEnum, ModelConfig from frigate.config import DetectorConfig, ModelConfig
from frigate.detectors import DetectorTypeEnum from frigate.detectors import DetectorTypeEnum
from frigate.detectors.detector_config import InputTensorEnum
class TestLocalObjectDetector(unittest.TestCase): class TestLocalObjectDetector(unittest.TestCase):

View File

@ -91,9 +91,13 @@ class NorfairTracker(ObjectTracker):
"ymax": self.detect_config.height, "ymax": self.detect_config.height,
} }
def deregister(self, id): def deregister(self, id, track_id):
del self.tracked_objects[id] del self.tracked_objects[id]
del self.disappeared[id] del self.disappeared[id]
self.tracker.tracked_objects = [
o for o in self.tracker.tracked_objects if o.global_id != track_id
]
del self.track_id_map[track_id]
# tracks the current position of the object based on the last N bounding boxes # tracks the current position of the object based on the last N bounding boxes
# returns False if the object has moved outside its previous position # returns False if the object has moved outside its previous position
@ -167,7 +171,7 @@ class NorfairTracker(ObjectTracker):
if self.update_position(id, obj["box"]): if self.update_position(id, obj["box"]):
self.tracked_objects[id]["motionless_count"] += 1 self.tracked_objects[id]["motionless_count"] += 1
if self.is_expired(id): if self.is_expired(id):
self.deregister(id) self.deregister(id, track_id)
return return
else: else:
# register the first position change and then only increment if # register the first position change and then only increment if
@ -261,8 +265,7 @@ class NorfairTracker(ObjectTracker):
# clear expired tracks # clear expired tracks
expired_ids = [k for k in self.track_id_map.keys() if k not in active_ids] expired_ids = [k for k in self.track_id_map.keys() if k not in active_ids]
for e_id in expired_ids: for e_id in expired_ids:
self.deregister(self.track_id_map[e_id]) self.deregister(self.track_id_map[e_id], e_id)
del self.track_id_map[e_id]
def debug_draw(self, frame, frame_time): def debug_draw(self, frame, frame_time):
active_detections = [ active_detections = [

View File

@ -14,8 +14,9 @@ import cv2
import numpy as np import numpy as np
from setproctitle import setproctitle from setproctitle import setproctitle
from frigate.config import CameraConfig, DetectConfig, PixelFormatEnum from frigate.config import CameraConfig, DetectConfig
from frigate.const import CACHE_DIR from frigate.const import CACHE_DIR
from frigate.detectors.detector_config import PixelFormatEnum
from frigate.log import LogPipe from frigate.log import LogPipe
from frigate.motion import MotionDetector from frigate.motion import MotionDetector
from frigate.motion.improved_motion import ImprovedMotionDetector from frigate.motion.improved_motion import ImprovedMotionDetector
@ -769,8 +770,8 @@ def process_frames(
stationary_object_ids = [ stationary_object_ids = [
obj["id"] obj["id"]
for obj in object_tracker.tracked_objects.values() for obj in object_tracker.tracked_objects.values()
# if there hasn't been motion for 10 frames # if it has exceeded the stationary threshold
if obj["motionless_count"] >= 10 if obj["motionless_count"] >= detect_config.stationary.threshold
# and it isn't due for a periodic check # and it isn't due for a periodic check
and ( and (
detect_config.stationary.interval == 0 detect_config.stationary.interval == 0