move ptz specific mp values to ptz_metrics dict

This commit is contained in:
Josh Hawkins 2023-07-10 16:15:12 -05:00
parent 2d939f0a74
commit 69434160ab
6 changed files with 74 additions and 68 deletions

View File

@ -48,7 +48,7 @@ from frigate.record.record import manage_recordings
from frigate.stats import StatsEmitter, stats_init from frigate.stats import StatsEmitter, stats_init
from frigate.storage import StorageMaintainer from frigate.storage import StorageMaintainer
from frigate.timeline import TimelineProcessor from frigate.timeline import TimelineProcessor
from frigate.types import CameraMetricsTypes, FeatureMetricsTypes from frigate.types import CameraMetricsTypes, FeatureMetricsTypes, PTZMetricsTypes
from frigate.version import VERSION from frigate.version import VERSION
from frigate.video import capture_camera, track_camera from frigate.video import capture_camera, track_camera
from frigate.watchdog import FrigateWatchdog from frigate.watchdog import FrigateWatchdog
@ -67,6 +67,7 @@ class FrigateApp:
self.plus_api = PlusApi() self.plus_api = PlusApi()
self.camera_metrics: dict[str, CameraMetricsTypes] = {} self.camera_metrics: dict[str, CameraMetricsTypes] = {}
self.feature_metrics: dict[str, FeatureMetricsTypes] = {} self.feature_metrics: dict[str, FeatureMetricsTypes] = {}
self.ptz_metrics: dict[str, PTZMetricsTypes] = {}
self.processes: dict[str, int] = {} self.processes: dict[str, int] = {}
def set_environment_vars(self) -> None: def set_environment_vars(self) -> None:
@ -135,19 +136,6 @@ class FrigateApp:
"i", "i",
self.config.cameras[camera_name].motion.improve_contrast, self.config.cameras[camera_name].motion.improve_contrast,
), ),
"ptz_autotracker_enabled": mp.Value( # type: ignore[typeddict-item]
# issue https://github.com/python/typeshed/issues/8799
# from mypy 0.981 onwards
"i",
self.config.cameras[camera_name].onvif.autotracking.enabled,
),
"ptz_stopped": mp.Event(),
"ptz_start_time": mp.Value("d", 0.0), # type: ignore[typeddict-item]
# issue https://github.com/python/typeshed/issues/8799
# from mypy 0.981 onwards
"ptz_stop_time": mp.Value("d", 0.0), # type: ignore[typeddict-item]
# issue https://github.com/python/typeshed/issues/8799
# from mypy 0.981 onwards
"motion_threshold": mp.Value( # type: ignore[typeddict-item] "motion_threshold": mp.Value( # type: ignore[typeddict-item]
# issue https://github.com/python/typeshed/issues/8799 # issue https://github.com/python/typeshed/issues/8799
# from mypy 0.981 onwards # from mypy 0.981 onwards
@ -176,7 +164,22 @@ class FrigateApp:
"capture_process": None, "capture_process": None,
"process": None, "process": None,
} }
self.camera_metrics[camera_name]["ptz_stopped"].set() self.ptz_metrics[camera_name] = {
"ptz_autotracker_enabled": mp.Value( # type: ignore[typeddict-item]
# issue https://github.com/python/typeshed/issues/8799
# from mypy 0.981 onwards
"i",
self.config.cameras[camera_name].onvif.autotracking.enabled,
),
"ptz_stopped": mp.Event(),
"ptz_start_time": mp.Value("d", 0.0), # type: ignore[typeddict-item]
# issue https://github.com/python/typeshed/issues/8799
# from mypy 0.981 onwards
"ptz_stop_time": mp.Value("d", 0.0), # type: ignore[typeddict-item]
# issue https://github.com/python/typeshed/issues/8799
# from mypy 0.981 onwards
}
self.ptz_metrics[camera_name]["ptz_stopped"].set()
self.feature_metrics[camera_name] = { self.feature_metrics[camera_name] = {
"audio_enabled": mp.Value( # type: ignore[typeddict-item] "audio_enabled": mp.Value( # type: ignore[typeddict-item]
# issue https://github.com/python/typeshed/issues/8799 # issue https://github.com/python/typeshed/issues/8799
@ -323,7 +326,7 @@ class FrigateApp:
) )
def init_onvif(self) -> None: def init_onvif(self) -> None:
self.onvif_controller = OnvifController(self.config, self.camera_metrics) self.onvif_controller = OnvifController(self.config, self.ptz_metrics)
def init_dispatcher(self) -> None: def init_dispatcher(self) -> None:
comms: list[Communicator] = [] comms: list[Communicator] = []
@ -337,6 +340,7 @@ class FrigateApp:
self.onvif_controller, self.onvif_controller,
self.camera_metrics, self.camera_metrics,
self.feature_metrics, self.feature_metrics,
self.ptz_metrics,
comms, comms,
) )
@ -381,7 +385,7 @@ class FrigateApp:
self.ptz_autotracker_thread = PtzAutoTrackerThread( self.ptz_autotracker_thread = PtzAutoTrackerThread(
self.config, self.config,
self.onvif_controller, self.onvif_controller,
self.camera_metrics, self.ptz_metrics,
self.stop_event, self.stop_event,
) )
self.ptz_autotracker_thread.start() self.ptz_autotracker_thread.start()
@ -432,6 +436,7 @@ class FrigateApp:
self.detection_out_events[name], self.detection_out_events[name],
self.detected_frames_queue, self.detected_frames_queue,
self.camera_metrics[name], self.camera_metrics[name],
self.ptz_metrics[name],
), ),
) )
camera_process.daemon = True camera_process.daemon = True

View File

@ -6,7 +6,7 @@ from typing import Any, Callable
from frigate.config import FrigateConfig from frigate.config import FrigateConfig
from frigate.ptz.onvif import OnvifCommandEnum, OnvifController from frigate.ptz.onvif import OnvifCommandEnum, OnvifController
from frigate.types import CameraMetricsTypes, FeatureMetricsTypes from frigate.types import CameraMetricsTypes, FeatureMetricsTypes, PTZMetricsTypes
from frigate.util.services import restart_frigate from frigate.util.services import restart_frigate
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -40,12 +40,14 @@ class Dispatcher:
onvif: OnvifController, onvif: OnvifController,
camera_metrics: dict[str, CameraMetricsTypes], camera_metrics: dict[str, CameraMetricsTypes],
feature_metrics: dict[str, FeatureMetricsTypes], feature_metrics: dict[str, FeatureMetricsTypes],
ptz_metrics: dict[str, PTZMetricsTypes],
communicators: list[Communicator], communicators: list[Communicator],
) -> None: ) -> None:
self.config = config self.config = config
self.onvif = onvif self.onvif = onvif
self.camera_metrics = camera_metrics self.camera_metrics = camera_metrics
self.feature_metrics = feature_metrics self.feature_metrics = feature_metrics
self.ptz_metrics = ptz_metrics
self.comms = communicators self.comms = communicators
for comm in self.comms: for comm in self.comms:
@ -165,16 +167,14 @@ class Dispatcher:
ptz_autotracker_settings = self.config.cameras[camera_name].onvif.autotracking ptz_autotracker_settings = self.config.cameras[camera_name].onvif.autotracking
if payload == "ON": if payload == "ON":
if not self.camera_metrics[camera_name]["ptz_autotracker_enabled"].value: if not self.ptz_metrics[camera_name]["ptz_autotracker_enabled"].value:
logger.info(f"Turning on ptz autotracker for {camera_name}") logger.info(f"Turning on ptz autotracker for {camera_name}")
self.camera_metrics[camera_name]["ptz_autotracker_enabled"].value = True self.ptz_metrics[camera_name]["ptz_autotracker_enabled"].value = True
ptz_autotracker_settings.enabled = True ptz_autotracker_settings.enabled = True
elif payload == "OFF": elif payload == "OFF":
if self.camera_metrics[camera_name]["ptz_autotracker_enabled"].value: if self.ptz_metrics[camera_name]["ptz_autotracker_enabled"].value:
logger.info(f"Turning off ptz autotracker for {camera_name}") logger.info(f"Turning off ptz autotracker for {camera_name}")
self.camera_metrics[camera_name][ self.ptz_metrics[camera_name]["ptz_autotracker_enabled"].value = False
"ptz_autotracker_enabled"
].value = False
ptz_autotracker_settings.enabled = False ptz_autotracker_settings.enabled = False
self.publish(f"{camera_name}/ptz_autotracker/state", payload, retain=True) self.publish(f"{camera_name}/ptz_autotracker/state", payload, retain=True)

View File

@ -15,7 +15,7 @@ from norfair.camera_motion import MotionEstimator, TranslationTransformationGett
from frigate.config import CameraConfig, FrigateConfig from frigate.config import CameraConfig, FrigateConfig
from frigate.ptz.onvif import OnvifController from frigate.ptz.onvif import OnvifController
from frigate.types import CameraMetricsTypes from frigate.types import PTZMetricsTypes
from frigate.util.image import SharedMemoryFrameManager, intersection_over_union from frigate.util.image import SharedMemoryFrameManager, intersection_over_union
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -97,12 +97,12 @@ class PtzAutoTrackerThread(threading.Thread):
self, self,
config: FrigateConfig, config: FrigateConfig,
onvif: OnvifController, onvif: OnvifController,
camera_metrics: dict[str, CameraMetricsTypes], ptz_metrics: dict[str, PTZMetricsTypes],
stop_event: MpEvent, stop_event: MpEvent,
) -> None: ) -> None:
threading.Thread.__init__(self) threading.Thread.__init__(self)
self.name = "ptz_autotracker" self.name = "ptz_autotracker"
self.ptz_autotracker = PtzAutoTracker(config, onvif, camera_metrics) self.ptz_autotracker = PtzAutoTracker(config, onvif, ptz_metrics)
self.stop_event = stop_event self.stop_event = stop_event
self.config = config self.config = config
@ -125,11 +125,11 @@ class PtzAutoTracker:
self, self,
config: FrigateConfig, config: FrigateConfig,
onvif: OnvifController, onvif: OnvifController,
camera_metrics: CameraMetricsTypes, ptz_metrics: PTZMetricsTypes,
) -> None: ) -> None:
self.config = config self.config = config
self.onvif = onvif self.onvif = onvif
self.camera_metrics = camera_metrics self.ptz_metrics = ptz_metrics
self.tracked_object: dict[str, object] = {} self.tracked_object: dict[str, object] = {}
self.tracked_object_previous: dict[str, object] = {} self.tracked_object_previous: dict[str, object] = {}
self.object_types = {} self.object_types = {}
@ -159,17 +159,13 @@ class PtzAutoTracker:
if not self.onvif._init_onvif(camera_name): if not self.onvif._init_onvif(camera_name):
logger.warning(f"Unable to initialize onvif for {camera_name}") logger.warning(f"Unable to initialize onvif for {camera_name}")
cam.onvif.autotracking.enabled = False cam.onvif.autotracking.enabled = False
self.camera_metrics[camera_name][ self.ptz_metrics[camera_name]["ptz_autotracker_enabled"].value = False
"ptz_autotracker_enabled"
].value = False
return return
if not self.onvif.cams[camera_name]["relative_fov_supported"]: if not self.onvif.cams[camera_name]["relative_fov_supported"]:
cam.onvif.autotracking.enabled = False cam.onvif.autotracking.enabled = False
self.camera_metrics[camera_name][ self.ptz_metrics[camera_name]["ptz_autotracker_enabled"].value = False
"ptz_autotracker_enabled"
].value = False
logger.warning( logger.warning(
f"Disabling autotracking for {camera_name}: FOV relative movement not supported" f"Disabling autotracking for {camera_name}: FOV relative movement not supported"
) )
@ -214,7 +210,7 @@ class PtzAutoTracker:
self.onvif._move_relative(camera, pan, tilt, 1) self.onvif._move_relative(camera, pan, tilt, 1)
# Wait until the camera finishes moving # Wait until the camera finishes moving
while not self.camera_metrics[camera]["ptz_stopped"].is_set(): while not self.ptz_metrics[camera]["ptz_stopped"].is_set():
# check if ptz is moving # check if ptz is moving
self.onvif.get_camera_status(camera) self.onvif.get_camera_status(camera)
time.sleep(1 / (self.config.cameras[camera].detect.fps / 2)) time.sleep(1 / (self.config.cameras[camera].detect.fps / 2))
@ -264,8 +260,8 @@ class PtzAutoTracker:
self.tracked_object[camera] = obj self.tracked_object[camera] = obj
self.tracked_object_previous[camera] = copy.deepcopy(obj) self.tracked_object_previous[camera] = copy.deepcopy(obj)
# only enqueue another move if the camera isn't moving # only enqueue another move if the camera isn't moving
if self.camera_metrics[camera]["ptz_stopped"].is_set(): if self.ptz_metrics[camera]["ptz_stopped"].is_set():
self.camera_metrics[camera]["ptz_stopped"].clear() self.ptz_metrics[camera]["ptz_stopped"].clear()
logger.debug("Autotrack: New object, moving ptz") logger.debug("Autotrack: New object, moving ptz")
self._autotrack_move_ptz(camera, obj) self._autotrack_move_ptz(camera, obj)
@ -312,7 +308,7 @@ class PtzAutoTracker:
f"Distance: {distance}, threshold: {distance_threshold}, iou: {iou}" f"Distance: {distance}, threshold: {distance_threshold}, iou: {iou}"
) )
if (distance < distance_threshold or iou > 0.5) and self.camera_metrics[ if (distance < distance_threshold or iou > 0.5) and self.ptz_metrics[
camera camera
]["ptz_stopped"].is_set(): ]["ptz_stopped"].is_set():
logger.debug( logger.debug(
@ -326,8 +322,8 @@ class PtzAutoTracker:
self.tracked_object_previous[camera] = copy.deepcopy(obj) self.tracked_object_previous[camera] = copy.deepcopy(obj)
# only enqueue another move if the camera isn't moving # only enqueue another move if the camera isn't moving
if self.camera_metrics[camera]["ptz_stopped"].is_set(): if self.ptz_metrics[camera]["ptz_stopped"].is_set():
self.camera_metrics[camera]["ptz_stopped"].clear() self.ptz_metrics[camera]["ptz_stopped"].clear()
logger.debug("Autotrack: Existing object, moving ptz") logger.debug("Autotrack: Existing object, moving ptz")
self._autotrack_move_ptz(camera, obj) self._autotrack_move_ptz(camera, obj)
@ -358,8 +354,8 @@ class PtzAutoTracker:
self.tracked_object[camera] = obj self.tracked_object[camera] = obj
self.tracked_object_previous[camera] = copy.deepcopy(obj) self.tracked_object_previous[camera] = copy.deepcopy(obj)
# only enqueue another move if the camera isn't moving # only enqueue another move if the camera isn't moving
if self.camera_metrics[camera]["ptz_stopped"].is_set(): if self.ptz_metrics[camera]["ptz_stopped"].is_set():
self.camera_metrics[camera]["ptz_stopped"].clear() self.ptz_metrics[camera]["ptz_stopped"].clear()
logger.debug("Autotrack: Reacquired object, moving ptz") logger.debug("Autotrack: Reacquired object, moving ptz")
self._autotrack_move_ptz(camera, obj) self._autotrack_move_ptz(camera, obj)
@ -384,7 +380,7 @@ class PtzAutoTracker:
if not self.autotracker_init[camera]: if not self.autotracker_init[camera]:
self._autotracker_setup(self.config.cameras[camera], camera) self._autotracker_setup(self.config.cameras[camera], camera)
# regularly update camera status # regularly update camera status
if not self.camera_metrics[camera]["ptz_stopped"].is_set(): if not self.ptz_metrics[camera]["ptz_stopped"].is_set():
self.onvif.get_camera_status(camera) self.onvif.get_camera_status(camera)
# return to preset if tracking is over # return to preset if tracking is over
@ -399,7 +395,7 @@ class PtzAutoTracker:
) )
and autotracker_config.return_preset and autotracker_config.return_preset
): ):
self.camera_metrics[camera]["ptz_stopped"].wait() self.ptz_metrics[camera]["ptz_stopped"].wait()
logger.debug( logger.debug(
f"Autotrack: Time is {time.time()}, returning to preset: {autotracker_config.return_preset}" f"Autotrack: Time is {time.time()}, returning to preset: {autotracker_config.return_preset}"
) )

View File

@ -9,7 +9,7 @@ import numpy
from onvif import ONVIFCamera, ONVIFError from onvif import ONVIFCamera, ONVIFError
from frigate.config import FrigateConfig from frigate.config import FrigateConfig
from frigate.types import CameraMetricsTypes from frigate.types import PTZMetricsTypes
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -30,10 +30,10 @@ class OnvifCommandEnum(str, Enum):
class OnvifController: class OnvifController:
def __init__( def __init__(
self, config: FrigateConfig, camera_metrics: dict[str, CameraMetricsTypes] self, config: FrigateConfig, ptz_metrics: dict[str, PTZMetricsTypes]
) -> None: ) -> None:
self.cams: dict[str, ONVIFCamera] = {} self.cams: dict[str, ONVIFCamera] = {}
self.camera_metrics = camera_metrics self.ptz_metrics = ptz_metrics
for cam_name, cam in config.cameras.items(): for cam_name, cam in config.cameras.items():
if not cam.enabled: if not cam.enabled:
@ -216,12 +216,12 @@ class OnvifController:
return return
self.cams[camera_name]["active"] = True self.cams[camera_name]["active"] = True
self.camera_metrics[camera_name]["ptz_stopped"].clear() self.ptz_metrics[camera_name]["ptz_stopped"].clear()
logger.debug(f"PTZ start time: {datetime.datetime.now().timestamp()}") logger.debug(f"PTZ start time: {datetime.datetime.now().timestamp()}")
self.camera_metrics[camera_name][ self.ptz_metrics[camera_name][
"ptz_start_time" "ptz_start_time"
].value = datetime.datetime.now().timestamp() ].value = datetime.datetime.now().timestamp()
self.camera_metrics[camera_name]["ptz_stop_time"].value = 0 self.ptz_metrics[camera_name]["ptz_stop_time"].value = 0
onvif: ONVIFCamera = self.cams[camera_name]["onvif"] onvif: ONVIFCamera = self.cams[camera_name]["onvif"]
move_request = self.cams[camera_name]["relative_move_request"] move_request = self.cams[camera_name]["relative_move_request"]
@ -266,7 +266,7 @@ class OnvifController:
return return
self.cams[camera_name]["active"] = True self.cams[camera_name]["active"] = True
self.camera_metrics[camera_name]["ptz_stopped"].clear() self.ptz_metrics[camera_name]["ptz_stopped"].clear()
move_request = self.cams[camera_name]["move_request"] move_request = self.cams[camera_name]["move_request"]
onvif: ONVIFCamera = self.cams[camera_name]["onvif"] onvif: ONVIFCamera = self.cams[camera_name]["onvif"]
preset_token = self.cams[camera_name]["presets"][preset] preset_token = self.cams[camera_name]["presets"][preset]
@ -276,7 +276,7 @@ class OnvifController:
"PresetToken": preset_token, "PresetToken": preset_token,
} }
) )
self.camera_metrics[camera_name]["ptz_stopped"].set() self.ptz_metrics[camera_name]["ptz_stopped"].set()
self.cams[camera_name]["active"] = False self.cams[camera_name]["active"] = False
def _zoom(self, camera_name: str, command: OnvifCommandEnum) -> None: def _zoom(self, camera_name: str, command: OnvifCommandEnum) -> None:
@ -350,25 +350,25 @@ class OnvifController:
if status.MoveStatus.PanTilt == "IDLE" and status.MoveStatus.Zoom == "IDLE": if status.MoveStatus.PanTilt == "IDLE" and status.MoveStatus.Zoom == "IDLE":
self.cams[camera_name]["active"] = False self.cams[camera_name]["active"] = False
if not self.camera_metrics[camera_name]["ptz_stopped"].is_set(): if not self.ptz_metrics[camera_name]["ptz_stopped"].is_set():
self.camera_metrics[camera_name]["ptz_stopped"].set() self.ptz_metrics[camera_name]["ptz_stopped"].set()
logger.debug(f"PTZ stop time: {datetime.datetime.now().timestamp()}") logger.debug(f"PTZ stop time: {datetime.datetime.now().timestamp()}")
self.camera_metrics[camera_name][ self.ptz_metrics[camera_name][
"ptz_stop_time" "ptz_stop_time"
].value = datetime.datetime.now().timestamp() ].value = datetime.datetime.now().timestamp()
else: else:
self.cams[camera_name]["active"] = True self.cams[camera_name]["active"] = True
if self.camera_metrics[camera_name]["ptz_stopped"].is_set(): if self.ptz_metrics[camera_name]["ptz_stopped"].is_set():
self.camera_metrics[camera_name]["ptz_stopped"].clear() self.ptz_metrics[camera_name]["ptz_stopped"].clear()
logger.debug(f"PTZ start time: {datetime.datetime.now().timestamp()}") logger.debug(f"PTZ start time: {datetime.datetime.now().timestamp()}")
self.camera_metrics[camera_name][ self.ptz_metrics[camera_name][
"ptz_start_time" "ptz_start_time"
].value = datetime.datetime.now().timestamp() ].value = datetime.datetime.now().timestamp()
self.camera_metrics[camera_name]["ptz_stop_time"].value = 0 self.ptz_metrics[camera_name]["ptz_stop_time"].value = 0
return { return {
"pan": status.Position.PanTilt.x, "pan": status.Position.PanTilt.x,

View File

@ -18,10 +18,6 @@ class CameraMetricsTypes(TypedDict):
frame_queue: Queue frame_queue: Queue
motion_enabled: Synchronized motion_enabled: Synchronized
improve_contrast_enabled: Synchronized improve_contrast_enabled: Synchronized
ptz_autotracker_enabled: Synchronized
ptz_stopped: Event
ptz_start_time: Synchronized
ptz_stop_time: Synchronized
motion_threshold: Synchronized motion_threshold: Synchronized
motion_contour_area: Synchronized motion_contour_area: Synchronized
process: Optional[Process] process: Optional[Process]
@ -30,6 +26,13 @@ class CameraMetricsTypes(TypedDict):
skipped_fps: Synchronized skipped_fps: Synchronized
class PTZMetricsTypes(TypedDict):
ptz_autotracker_enabled: Synchronized
ptz_stopped: Event
ptz_start_time: Synchronized
ptz_stop_time: Synchronized
class FeatureMetricsTypes(TypedDict): class FeatureMetricsTypes(TypedDict):
audio_enabled: Synchronized audio_enabled: Synchronized
record_enabled: Synchronized record_enabled: Synchronized

View File

@ -462,6 +462,7 @@ def track_camera(
result_connection, result_connection,
detected_objects_queue, detected_objects_queue,
process_info, process_info,
ptz_info,
): ):
stop_event = mp.Event() stop_event = mp.Event()
@ -479,13 +480,14 @@ def track_camera(
detection_enabled = process_info["detection_enabled"] detection_enabled = process_info["detection_enabled"]
motion_enabled = process_info["motion_enabled"] motion_enabled = process_info["motion_enabled"]
improve_contrast_enabled = process_info["improve_contrast_enabled"] improve_contrast_enabled = process_info["improve_contrast_enabled"]
ptz_autotracker_enabled = process_info["ptz_autotracker_enabled"]
ptz_start_time = process_info["ptz_start_time"]
ptz_stop_time = process_info["ptz_stop_time"]
ptz_stopped = process_info["ptz_stopped"]
motion_threshold = process_info["motion_threshold"] motion_threshold = process_info["motion_threshold"]
motion_contour_area = process_info["motion_contour_area"] motion_contour_area = process_info["motion_contour_area"]
ptz_autotracker_enabled = ptz_info["ptz_autotracker_enabled"]
ptz_start_time = ptz_info["ptz_start_time"]
ptz_stop_time = ptz_info["ptz_stop_time"]
ptz_stopped = ptz_info["ptz_stopped"]
frame_shape = config.frame_shape frame_shape = config.frame_shape
objects_to_track = config.objects.track objects_to_track = config.objects.track
object_filters = config.objects.filters object_filters = config.objects.filters