From a5855ab4284d6093ade8726b043911f269226eed Mon Sep 17 00:00:00 2001 From: Alin Balutoiu Date: Sat, 11 Feb 2023 11:29:15 +0000 Subject: [PATCH] Add option to sort cameras inside Birdseye --- frigate/config.py | 6 ++++++ frigate/output.py | 31 ++++++++++++++++++++++++++++++- 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/frigate/config.py b/frigate/config.py index b83f3cbde..3fec86992 100644 --- a/frigate/config.py +++ b/frigate/config.py @@ -372,6 +372,9 @@ class BirdseyeModeEnum(str, Enum): class BirdseyeConfig(FrigateBaseModel): enabled: bool = Field(default=True, title="Enable birdseye view.") restream: bool = Field(default=False, title="Restream birdseye via RTSP.") + sort_cameras: bool = Field( + default=False, title="Sort cameras by position and name." + ) width: int = Field(default=1280, title="Birdseye width.") height: int = Field(default=720, title="Birdseye height.") quality: int = Field( @@ -388,6 +391,9 @@ class BirdseyeConfig(FrigateBaseModel): # uses BaseModel because some global attributes are not available at the camera level class BirdseyeCameraConfig(BaseModel): enabled: bool = Field(default=True, title="Enable birdseye view for camera.") + position: int = Field( + default=0, title="Position of the camera in the birdseye view." + ) mode: BirdseyeModeEnum = Field( default=BirdseyeModeEnum.objects, title="Tracking mode for camera." ) diff --git a/frigate/output.py b/frigate/output.py index b59d56a62..dc11bfbe7 100644 --- a/frigate/output.py +++ b/frigate/output.py @@ -4,6 +4,7 @@ import logging import math import multiprocessing as mp import os +import operator import queue import signal import subprocess as sp @@ -292,8 +293,21 @@ class BirdsEyeFrameManager: # calculate layout dimensions layout_dim = math.ceil(math.sqrt(len(active_cameras))) + # check if we need to reset the layout because sorting is enabled and there are new cameras to add + reset_layout = ( + True + if self.config.birdseye.sort_cameras + and len(active_cameras.difference(self.active_cameras)) > 0 + else False + ) + # reset the layout if it needs to be different - if layout_dim != self.layout_dim: + if layout_dim != self.layout_dim or reset_layout: + if reset_layout: + logger.debug( + f"Added new cameras and Birdseye sorting is enabled, resetting layout..." + ) + logger.debug(f"Changing layout size from {self.layout_dim} to {layout_dim}") self.layout_dim = layout_dim @@ -327,6 +341,21 @@ class BirdsEyeFrameManager: self.active_cameras = active_cameras + if self.config.birdseye.sort_cameras: + # this also converts added_cameras from a set to a list since we need + # to pop elements in order + added_cameras = sorted( + added_cameras, + # sort cameras by the position and by name if the position is the same + key=lambda added_camera: ( + self.config.cameras[added_camera].birdseye.position, + added_camera, + ), + # we're popping out elements from the end, so this needs to be reverse + # as we want the last element to be the first + reverse=True, + ) + # update each position in the layout for position, camera in enumerate(self.camera_layout, start=0): # if this camera was removed, replace it or clear it