diff --git a/frigate/app.py b/frigate/app.py index 8e8165345..8d5aba8c0 100644 --- a/frigate/app.py +++ b/frigate/app.py @@ -163,6 +163,7 @@ class FrigateApp: # issue https://github.com/python/typeshed/issues/8799 # from mypy 0.981 onwards "frame_queue": mp.Queue(maxsize=2), + "region_grid_queue": mp.Queue(maxsize=1), "capture_process": None, "process": None, "audio_rms": mp.Value("d", 0.0), # type: ignore[typeddict-item] @@ -477,6 +478,7 @@ class FrigateApp: self.detection_queue, self.detection_out_events[name], self.detected_frames_queue, + self.inter_process_queue, self.camera_metrics[name], self.ptz_metrics[name], self.region_grids[name], diff --git a/frigate/comms/dispatcher.py b/frigate/comms/dispatcher.py index e97095c8a..f3886a331 100644 --- a/frigate/comms/dispatcher.py +++ b/frigate/comms/dispatcher.py @@ -5,10 +5,11 @@ from abc import ABC, abstractmethod from typing import Any, Callable from frigate.config import FrigateConfig -from frigate.const import INSERT_MANY_RECORDINGS +from frigate.const import INSERT_MANY_RECORDINGS, REQUEST_REGION_GRID from frigate.models import Recordings from frigate.ptz.onvif import OnvifCommandEnum, OnvifController from frigate.types import CameraMetricsTypes, FeatureMetricsTypes, PTZMetricsTypes +from frigate.util.object import get_camera_regions_grid from frigate.util.services import restart_frigate logger = logging.getLogger(__name__) @@ -90,6 +91,11 @@ class Dispatcher: restart_frigate() elif topic == INSERT_MANY_RECORDINGS: Recordings.insert_many(payload).execute() + elif topic == REQUEST_REGION_GRID: + camera = payload + self.camera_metrics[camera]["region_grid_queue"].put( + get_camera_regions_grid(camera, self.config.cameras[camera].detect) + ) else: self.publish(topic, payload, retain=False) diff --git a/frigate/const.py b/frigate/const.py index c6912471b..56d0f4517 100644 --- a/frigate/const.py +++ b/frigate/const.py @@ -51,3 +51,4 @@ MAX_PLAYLIST_SECONDS = 7200 # support 2 hour segments for a single playlist to # Internal Comms Topics INSERT_MANY_RECORDINGS = "insert_many_recordings" +REQUEST_REGION_GRID = "request_region_grid" diff --git a/frigate/util/builtin.py b/frigate/util/builtin.py index dd2e3471f..2a9b7053a 100644 --- a/frigate/util/builtin.py +++ b/frigate/util/builtin.py @@ -14,6 +14,7 @@ import numpy as np import pytz import yaml from ruamel.yaml import YAML +from tzlocal import get_localzone from frigate.const import REGEX_HTTP_CAMERA_USER_PASS, REGEX_RTSP_CAMERA_USER_PASS @@ -265,5 +266,7 @@ def find_by_key(dictionary, target_key): def get_tomorrow_at_2() -> datetime.datetime: - tomorrow = datetime.datetime.now() + datetime.timedelta(days=1) - return tomorrow.replace(hour=2, minute=0, second=0) + tomorrow = datetime.datetime.now(get_localzone()) + datetime.timedelta(days=1) + return tomorrow.replace(hour=2, minute=0, second=0).astimezone( + datetime.timezone.utc + ) diff --git a/frigate/util/object.py b/frigate/util/object.py index 61f7d2108..02103c469 100644 --- a/frigate/util/object.py +++ b/frigate/util/object.py @@ -447,7 +447,11 @@ def get_consolidated_object_detections(detected_object_groups): return consolidated_detections -def get_startup_regions(frame_shape: tuple[int], region_min_size: int, region_grid: list[list[dict[str, any]]]) -> list[list[int]]: +def get_startup_regions( + frame_shape: tuple[int], + region_min_size: int, + region_grid: list[list[dict[str, any]]], +) -> list[list[int]]: """Get a list of regions to run on startup.""" # return 8 most popular regions for the camera all_cells = np.concatenate(region_grid).flat @@ -462,14 +466,16 @@ def get_startup_regions(frame_shape: tuple[int], region_min_size: int, region_gr x = frame_shape[1] / GRID_SIZE * (0.5 + cell["x"]) y = frame_shape[0] / GRID_SIZE * (0.5 + cell["y"]) size = cell["mean"] * frame_shape[1] - regions.append(calculate_region( - frame_shape, - x - size / 2, - y - size / 2, - x + size / 2, - y + size / 2, - region_min_size, - multiplier=1, - )) + regions.append( + calculate_region( + frame_shape, + x - size / 2, + y - size / 2, + x + size / 2, + y + size / 2, + region_min_size, + multiplier=1, + ) + ) return regions diff --git a/frigate/video.py b/frigate/video.py index 33ace1ad2..b961cc8a6 100755 --- a/frigate/video.py +++ b/frigate/video.py @@ -14,7 +14,12 @@ import numpy as np from setproctitle import setproctitle from frigate.config import CameraConfig, DetectConfig, ModelConfig -from frigate.const import ALL_ATTRIBUTE_LABELS, ATTRIBUTE_LABEL_MAP, CACHE_DIR +from frigate.const import ( + ALL_ATTRIBUTE_LABELS, + ATTRIBUTE_LABEL_MAP, + CACHE_DIR, + REQUEST_REGION_GRID, +) from frigate.log import LogPipe from frigate.motion import MotionDetector from frigate.motion.improved_motion import ImprovedMotionDetector @@ -380,6 +385,7 @@ def track_camera( detection_queue, result_connection, detected_objects_queue, + inter_process_queue, process_info, ptz_metrics, region_grid, @@ -397,6 +403,7 @@ def track_camera( listen() frame_queue = process_info["frame_queue"] + region_grid_queue = process_info["region_grid_queue"] detection_enabled = process_info["detection_enabled"] motion_enabled = process_info["motion_enabled"] improve_contrast_enabled = process_info["improve_contrast_enabled"] @@ -425,7 +432,9 @@ def track_camera( process_frames( name, + inter_process_queue, frame_queue, + region_grid_queue, frame_shape, model_config, config.detect, @@ -493,7 +502,9 @@ def detect( def process_frames( camera_name: str, + inter_process_queue: mp.Queue, frame_queue: mp.Queue, + region_grid_queue: mp.Queue, frame_shape, model_config: ModelConfig, detect_config: DetectConfig, @@ -525,8 +536,17 @@ def process_frames( region_min_size = get_min_region_size(model_config) while not stop_event.is_set(): - if datetime.datetime.now() > next_region_update: - # TODO signal update + if ( + datetime.datetime.now().astimezone(datetime.timezone.utc) + > next_region_update + ): + inter_process_queue.put((REQUEST_REGION_GRID, camera_name)) + + try: + region_grid = region_grid_queue.get(True, 10) + except queue.Empty: + logger.error(f"Unable to get updated region grid for {camera_name}") + next_region_update = get_tomorrow_at_2() try: @@ -627,7 +647,9 @@ def process_frames( # if starting up, get the next startup scan region if startup_scan: - for region in get_startup_regions(frame_shape, region_min_size, region_grid): + for region in get_startup_regions( + frame_shape, region_min_size, region_grid + ): regions.append(region) startup_scan = False