mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-02-15 15:45:27 +03:00
Make ptz_metrics into a class
This commit is contained in:
parent
618b9ef37b
commit
1e73147359
@ -17,7 +17,7 @@ from playhouse.sqliteq import SqliteQueueDatabase
|
|||||||
import frigate.util as util
|
import frigate.util as util
|
||||||
from frigate.api.auth import hash_password
|
from frigate.api.auth import hash_password
|
||||||
from frigate.api.fastapi_app import create_fastapi_app
|
from frigate.api.fastapi_app import create_fastapi_app
|
||||||
from frigate.camera import CameraMetrics
|
from frigate.camera import CameraMetrics, PTZMetrics
|
||||||
from frigate.comms.config_updater import ConfigPublisher
|
from frigate.comms.config_updater import ConfigPublisher
|
||||||
from frigate.comms.dispatcher import Communicator, Dispatcher
|
from frigate.comms.dispatcher import Communicator, Dispatcher
|
||||||
from frigate.comms.event_metadata_updater import (
|
from frigate.comms.event_metadata_updater import (
|
||||||
@ -67,7 +67,6 @@ from frigate.stats.emitter import StatsEmitter
|
|||||||
from frigate.stats.util import stats_init
|
from frigate.stats.util import 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 PTZMetricsTypes
|
|
||||||
from frigate.util.builtin import empty_and_close_queue
|
from frigate.util.builtin import empty_and_close_queue
|
||||||
from frigate.util.object import get_camera_regions_grid
|
from frigate.util.object import get_camera_regions_grid
|
||||||
from frigate.version import VERSION
|
from frigate.version import VERSION
|
||||||
@ -87,7 +86,7 @@ class FrigateApp:
|
|||||||
self.detection_shms: list[mp.shared_memory.SharedMemory] = []
|
self.detection_shms: list[mp.shared_memory.SharedMemory] = []
|
||||||
self.log_queue: Queue = mp.Queue()
|
self.log_queue: Queue = mp.Queue()
|
||||||
self.camera_metrics: dict[str, CameraMetrics] = {}
|
self.camera_metrics: dict[str, CameraMetrics] = {}
|
||||||
self.ptz_metrics: dict[str, PTZMetricsTypes] = {}
|
self.ptz_metrics: dict[str, PTZMetrics] = {}
|
||||||
self.processes: dict[str, int] = {}
|
self.processes: dict[str, int] = {}
|
||||||
self.region_grids: dict[str, list[list[dict[str, int]]]] = {}
|
self.region_grids: dict[str, list[list[dict[str, int]]]] = {}
|
||||||
self.config = config
|
self.config = config
|
||||||
@ -111,36 +110,11 @@ class FrigateApp:
|
|||||||
# create camera_metrics
|
# create camera_metrics
|
||||||
for camera_name in self.config.cameras.keys():
|
for camera_name in self.config.cameras.keys():
|
||||||
self.camera_metrics[camera_name] = CameraMetrics()
|
self.camera_metrics[camera_name] = CameraMetrics()
|
||||||
self.ptz_metrics[camera_name] = {
|
self.ptz_metrics[camera_name] = PTZMetrics(
|
||||||
"ptz_autotracker_enabled": mp.Value( # type: ignore[typeddict-item]
|
autotracker_enabled=self.config.cameras[
|
||||||
# issue https://github.com/python/typeshed/issues/8799
|
camera_name
|
||||||
# from mypy 0.981 onwards
|
].onvif.autotracking.enabled
|
||||||
"i",
|
)
|
||||||
self.config.cameras[camera_name].onvif.autotracking.enabled,
|
|
||||||
),
|
|
||||||
"ptz_tracking_active": mp.Event(),
|
|
||||||
"ptz_motor_stopped": mp.Event(),
|
|
||||||
"ptz_reset": 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
|
|
||||||
"ptz_frame_time": mp.Value("d", 0.0), # type: ignore[typeddict-item]
|
|
||||||
# issue https://github.com/python/typeshed/issues/8799
|
|
||||||
# from mypy 0.981 onwards
|
|
||||||
"ptz_zoom_level": mp.Value("d", 0.0), # type: ignore[typeddict-item]
|
|
||||||
# issue https://github.com/python/typeshed/issues/8799
|
|
||||||
# from mypy 0.981 onwards
|
|
||||||
"ptz_max_zoom": mp.Value("d", 0.0), # type: ignore[typeddict-item]
|
|
||||||
# issue https://github.com/python/typeshed/issues/8799
|
|
||||||
# from mypy 0.981 onwards
|
|
||||||
"ptz_min_zoom": 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_motor_stopped"].set()
|
|
||||||
|
|
||||||
def init_queues(self) -> None:
|
def init_queues(self) -> None:
|
||||||
# Queue for cameras to push tracked objects to
|
# Queue for cameras to push tracked objects to
|
||||||
|
|||||||
@ -36,3 +36,33 @@ class CameraMetrics:
|
|||||||
self.capture_process = None
|
self.capture_process = None
|
||||||
self.ffmpeg_pid = mp.Value("i", 0)
|
self.ffmpeg_pid = mp.Value("i", 0)
|
||||||
|
|
||||||
|
|
||||||
|
class PTZMetrics:
|
||||||
|
autotracker_enabled: Synchronized
|
||||||
|
|
||||||
|
start_time: Synchronized
|
||||||
|
stop_time: Synchronized
|
||||||
|
frame_time: Synchronized
|
||||||
|
zoom_level: Synchronized
|
||||||
|
max_zoom: Synchronized
|
||||||
|
min_zoom: Synchronized
|
||||||
|
|
||||||
|
tracking_active: Event
|
||||||
|
motor_stopped: Event
|
||||||
|
reset: Event
|
||||||
|
|
||||||
|
def __init__(self, *, autotracker_enabled: bool):
|
||||||
|
self.autotracker_enabled = mp.Value("i", autotracker_enabled)
|
||||||
|
|
||||||
|
self.start_time = mp.Value("d", 0)
|
||||||
|
self.stop_time = mp.Value("d", 0)
|
||||||
|
self.frame_time = mp.Value("d", 0)
|
||||||
|
self.zoom_level = mp.Value("d", 0)
|
||||||
|
self.max_zoom = mp.Value("d", 0)
|
||||||
|
self.min_zoom = mp.Value("d", 0)
|
||||||
|
|
||||||
|
self.tracking_active = mp.Event()
|
||||||
|
self.motor_stopped = mp.Event()
|
||||||
|
self.reset = mp.Event()
|
||||||
|
|
||||||
|
self.motor_stopped.set()
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import logging
|
|||||||
from abc import ABC, abstractmethod
|
from abc import ABC, abstractmethod
|
||||||
from typing import Any, Callable, Optional
|
from typing import Any, Callable, Optional
|
||||||
|
|
||||||
|
from frigate.camera import PTZMetrics
|
||||||
from frigate.comms.config_updater import ConfigPublisher
|
from frigate.comms.config_updater import ConfigPublisher
|
||||||
from frigate.config import BirdseyeModeEnum, FrigateConfig
|
from frigate.config import BirdseyeModeEnum, FrigateConfig
|
||||||
from frigate.const import (
|
from frigate.const import (
|
||||||
@ -19,7 +20,6 @@ from frigate.const import (
|
|||||||
)
|
)
|
||||||
from frigate.models import Event, Previews, Recordings, ReviewSegment
|
from frigate.models import Event, Previews, Recordings, ReviewSegment
|
||||||
from frigate.ptz.onvif import OnvifCommandEnum, OnvifController
|
from frigate.ptz.onvif import OnvifCommandEnum, OnvifController
|
||||||
from frigate.types import PTZMetricsTypes
|
|
||||||
from frigate.util.object import get_camera_regions_grid
|
from frigate.util.object import get_camera_regions_grid
|
||||||
from frigate.util.services import restart_frigate
|
from frigate.util.services import restart_frigate
|
||||||
|
|
||||||
@ -53,7 +53,7 @@ class Dispatcher:
|
|||||||
config: FrigateConfig,
|
config: FrigateConfig,
|
||||||
config_updater: ConfigPublisher,
|
config_updater: ConfigPublisher,
|
||||||
onvif: OnvifController,
|
onvif: OnvifController,
|
||||||
ptz_metrics: dict[str, PTZMetricsTypes],
|
ptz_metrics: dict[str, PTZMetrics],
|
||||||
communicators: list[Communicator],
|
communicators: list[Communicator],
|
||||||
) -> None:
|
) -> None:
|
||||||
self.config = config
|
self.config = config
|
||||||
@ -251,16 +251,16 @@ class Dispatcher:
|
|||||||
"Autotracking must be enabled in the config to be turned on via MQTT."
|
"Autotracking must be enabled in the config to be turned on via MQTT."
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
if not self.ptz_metrics[camera_name]["ptz_autotracker_enabled"].value:
|
if not self.ptz_metrics[camera_name].autotracker_enabled.value:
|
||||||
logger.info(f"Turning on ptz autotracker for {camera_name}")
|
logger.info(f"Turning on ptz autotracker for {camera_name}")
|
||||||
self.ptz_metrics[camera_name]["ptz_autotracker_enabled"].value = True
|
self.ptz_metrics[camera_name].autotracker_enabled.value = True
|
||||||
self.ptz_metrics[camera_name]["ptz_start_time"].value = 0
|
self.ptz_metrics[camera_name].start_time.value = 0
|
||||||
ptz_autotracker_settings.enabled = True
|
ptz_autotracker_settings.enabled = True
|
||||||
elif payload == "OFF":
|
elif payload == "OFF":
|
||||||
if self.ptz_metrics[camera_name]["ptz_autotracker_enabled"].value:
|
if self.ptz_metrics[camera_name].autotracker_enabled.value:
|
||||||
logger.info(f"Turning off ptz autotracker for {camera_name}")
|
logger.info(f"Turning off ptz autotracker for {camera_name}")
|
||||||
self.ptz_metrics[camera_name]["ptz_autotracker_enabled"].value = False
|
self.ptz_metrics[camera_name].autotracker_enabled.value = False
|
||||||
self.ptz_metrics[camera_name]["ptz_start_time"].value = 0
|
self.ptz_metrics[camera_name].start_time.value = 0
|
||||||
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)
|
||||||
|
|||||||
@ -18,6 +18,7 @@ from norfair.camera_motion import (
|
|||||||
TranslationTransformationGetter,
|
TranslationTransformationGetter,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
from frigate.camera import PTZMetrics
|
||||||
from frigate.comms.dispatcher import Dispatcher
|
from frigate.comms.dispatcher import Dispatcher
|
||||||
from frigate.config import CameraConfig, FrigateConfig, ZoomingModeEnum
|
from frigate.config import CameraConfig, FrigateConfig, ZoomingModeEnum
|
||||||
from frigate.const import (
|
from frigate.const import (
|
||||||
@ -31,7 +32,6 @@ from frigate.const import (
|
|||||||
CONFIG_DIR,
|
CONFIG_DIR,
|
||||||
)
|
)
|
||||||
from frigate.ptz.onvif import OnvifController
|
from frigate.ptz.onvif import OnvifController
|
||||||
from frigate.types import PTZMetricsTypes
|
|
||||||
from frigate.util.builtin import update_yaml_file
|
from frigate.util.builtin import update_yaml_file
|
||||||
from frigate.util.image import SharedMemoryFrameManager, intersection_over_union
|
from frigate.util.image import SharedMemoryFrameManager, intersection_over_union
|
||||||
|
|
||||||
@ -50,23 +50,23 @@ def ptz_moving_at_frame_time(frame_time, ptz_start_time, ptz_stop_time):
|
|||||||
|
|
||||||
class PtzMotionEstimator:
|
class PtzMotionEstimator:
|
||||||
def __init__(
|
def __init__(
|
||||||
self, config: CameraConfig, ptz_metrics: dict[str, PTZMetricsTypes]
|
self, config: CameraConfig, ptz_metrics: dict[str, PTZMetrics]
|
||||||
) -> None:
|
) -> None:
|
||||||
self.frame_manager = SharedMemoryFrameManager()
|
self.frame_manager = SharedMemoryFrameManager()
|
||||||
self.norfair_motion_estimator = None
|
self.norfair_motion_estimator = None
|
||||||
self.camera_config = config
|
self.camera_config = config
|
||||||
self.coord_transformations = None
|
self.coord_transformations = None
|
||||||
self.ptz_metrics = ptz_metrics
|
self.ptz_metrics = ptz_metrics
|
||||||
self.ptz_start_time = self.ptz_metrics["ptz_start_time"]
|
self.ptz_start_time = self.ptz_metrics.start_time
|
||||||
self.ptz_stop_time = self.ptz_metrics["ptz_stop_time"]
|
self.ptz_stop_time = self.ptz_metrics.stop_time
|
||||||
|
|
||||||
self.ptz_metrics["ptz_reset"].set()
|
self.ptz_metrics.reset.set()
|
||||||
logger.debug(f"{config.name}: Motion estimator init")
|
logger.debug(f"{config.name}: Motion estimator init")
|
||||||
|
|
||||||
def motion_estimator(self, detections, frame_time, camera):
|
def motion_estimator(self, detections, frame_time, camera):
|
||||||
# If we've just started up or returned to our preset, reset motion estimator for new tracking session
|
# If we've just started up or returned to our preset, reset motion estimator for new tracking session
|
||||||
if self.ptz_metrics["ptz_reset"].is_set():
|
if self.ptz_metrics.reset.is_set():
|
||||||
self.ptz_metrics["ptz_reset"].clear()
|
self.ptz_metrics.reset.clear()
|
||||||
|
|
||||||
# homography is nice (zooming) but slow, translation is pan/tilt only but fast.
|
# homography is nice (zooming) but slow, translation is pan/tilt only but fast.
|
||||||
if (
|
if (
|
||||||
@ -148,7 +148,7 @@ class PtzAutoTrackerThread(threading.Thread):
|
|||||||
self,
|
self,
|
||||||
config: FrigateConfig,
|
config: FrigateConfig,
|
||||||
onvif: OnvifController,
|
onvif: OnvifController,
|
||||||
ptz_metrics: dict[str, PTZMetricsTypes],
|
ptz_metrics: dict[str, PTZMetrics],
|
||||||
dispatcher: Dispatcher,
|
dispatcher: Dispatcher,
|
||||||
stop_event: MpEvent,
|
stop_event: MpEvent,
|
||||||
) -> None:
|
) -> None:
|
||||||
@ -182,7 +182,7 @@ class PtzAutoTracker:
|
|||||||
self,
|
self,
|
||||||
config: FrigateConfig,
|
config: FrigateConfig,
|
||||||
onvif: OnvifController,
|
onvif: OnvifController,
|
||||||
ptz_metrics: PTZMetricsTypes,
|
ptz_metrics: PTZMetrics,
|
||||||
dispatcher: Dispatcher,
|
dispatcher: Dispatcher,
|
||||||
stop_event: MpEvent,
|
stop_event: MpEvent,
|
||||||
) -> None:
|
) -> None:
|
||||||
@ -248,7 +248,7 @@ class PtzAutoTracker:
|
|||||||
f"Disabling autotracking for {camera}: onvif connection failed"
|
f"Disabling autotracking for {camera}: onvif connection failed"
|
||||||
)
|
)
|
||||||
camera_config.onvif.autotracking.enabled = False
|
camera_config.onvif.autotracking.enabled = False
|
||||||
self.ptz_metrics[camera]["ptz_autotracker_enabled"].value = False
|
self.ptz_metrics[camera].autotracker_enabled.value = False
|
||||||
return
|
return
|
||||||
|
|
||||||
if not self.onvif.cams[camera]["init"]:
|
if not self.onvif.cams[camera]["init"]:
|
||||||
@ -257,7 +257,7 @@ class PtzAutoTracker:
|
|||||||
f"Disabling autotracking for {camera}: Unable to initialize onvif"
|
f"Disabling autotracking for {camera}: Unable to initialize onvif"
|
||||||
)
|
)
|
||||||
camera_config.onvif.autotracking.enabled = False
|
camera_config.onvif.autotracking.enabled = False
|
||||||
self.ptz_metrics[camera]["ptz_autotracker_enabled"].value = False
|
self.ptz_metrics[camera].autotracker_enabled.value = False
|
||||||
return
|
return
|
||||||
|
|
||||||
if "pt-r-fov" not in self.onvif.cams[camera]["features"]:
|
if "pt-r-fov" not in self.onvif.cams[camera]["features"]:
|
||||||
@ -265,7 +265,7 @@ class PtzAutoTracker:
|
|||||||
f"Disabling autotracking for {camera}: FOV relative movement not supported"
|
f"Disabling autotracking for {camera}: FOV relative movement not supported"
|
||||||
)
|
)
|
||||||
camera_config.onvif.autotracking.enabled = False
|
camera_config.onvif.autotracking.enabled = False
|
||||||
self.ptz_metrics[camera]["ptz_autotracker_enabled"].value = False
|
self.ptz_metrics[camera].autotracker_enabled.value = False
|
||||||
return
|
return
|
||||||
|
|
||||||
move_status_supported = self.onvif.get_service_capabilities(camera)
|
move_status_supported = self.onvif.get_service_capabilities(camera)
|
||||||
@ -275,7 +275,7 @@ class PtzAutoTracker:
|
|||||||
f"Disabling autotracking for {camera}: ONVIF MoveStatus not supported"
|
f"Disabling autotracking for {camera}: ONVIF MoveStatus not supported"
|
||||||
)
|
)
|
||||||
camera_config.onvif.autotracking.enabled = False
|
camera_config.onvif.autotracking.enabled = False
|
||||||
self.ptz_metrics[camera]["ptz_autotracker_enabled"].value = False
|
self.ptz_metrics[camera].autotracker_enabled.value = False
|
||||||
return
|
return
|
||||||
|
|
||||||
if self.onvif.cams[camera]["init"]:
|
if self.onvif.cams[camera]["init"]:
|
||||||
@ -295,12 +295,16 @@ class PtzAutoTracker:
|
|||||||
float(val)
|
float(val)
|
||||||
for val in camera_config.onvif.autotracking.movement_weights
|
for val in camera_config.onvif.autotracking.movement_weights
|
||||||
]
|
]
|
||||||
self.ptz_metrics[camera][
|
self.ptz_metrics[
|
||||||
"ptz_min_zoom"
|
camera
|
||||||
].value = camera_config.onvif.autotracking.movement_weights[0]
|
].min_zoom.value = (
|
||||||
self.ptz_metrics[camera][
|
camera_config.onvif.autotracking.movement_weights[0]
|
||||||
"ptz_max_zoom"
|
)
|
||||||
].value = camera_config.onvif.autotracking.movement_weights[1]
|
self.ptz_metrics[
|
||||||
|
camera
|
||||||
|
].max_zoom.value = (
|
||||||
|
camera_config.onvif.autotracking.movement_weights[1]
|
||||||
|
)
|
||||||
self.intercept[camera] = (
|
self.intercept[camera] = (
|
||||||
camera_config.onvif.autotracking.movement_weights[2]
|
camera_config.onvif.autotracking.movement_weights[2]
|
||||||
)
|
)
|
||||||
@ -309,7 +313,7 @@ class PtzAutoTracker:
|
|||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
camera_config.onvif.autotracking.enabled = False
|
camera_config.onvif.autotracking.enabled = False
|
||||||
self.ptz_metrics[camera]["ptz_autotracker_enabled"].value = False
|
self.ptz_metrics[camera].autotracker_enabled.value = False
|
||||||
logger.warning(
|
logger.warning(
|
||||||
f"Autotracker recalibration is required for {camera}. Disabling autotracking."
|
f"Autotracker recalibration is required for {camera}. Disabling autotracking."
|
||||||
)
|
)
|
||||||
@ -317,7 +321,7 @@ class PtzAutoTracker:
|
|||||||
if camera_config.onvif.autotracking.calibrate_on_startup:
|
if camera_config.onvif.autotracking.calibrate_on_startup:
|
||||||
self._calibrate_camera(camera)
|
self._calibrate_camera(camera)
|
||||||
|
|
||||||
self.ptz_metrics[camera]["ptz_tracking_active"].clear()
|
self.ptz_metrics[camera].tracking_active.clear()
|
||||||
self.dispatcher.publish(f"{camera}/ptz_autotracker/active", "OFF", retain=False)
|
self.dispatcher.publish(f"{camera}/ptz_autotracker/active", "OFF", retain=False)
|
||||||
self.autotracker_init[camera] = True
|
self.autotracker_init[camera] = True
|
||||||
|
|
||||||
@ -363,10 +367,10 @@ class PtzAutoTracker:
|
|||||||
1,
|
1,
|
||||||
)
|
)
|
||||||
|
|
||||||
while not self.ptz_metrics[camera]["ptz_motor_stopped"].is_set():
|
while not self.ptz_metrics[camera].motor_stopped.is_set():
|
||||||
self.onvif.get_camera_status(camera)
|
self.onvif.get_camera_status(camera)
|
||||||
|
|
||||||
zoom_out_values.append(self.ptz_metrics[camera]["ptz_zoom_level"].value)
|
zoom_out_values.append(self.ptz_metrics[camera].zoom_level.value)
|
||||||
|
|
||||||
self.onvif._zoom_absolute(
|
self.onvif._zoom_absolute(
|
||||||
camera,
|
camera,
|
||||||
@ -374,10 +378,10 @@ class PtzAutoTracker:
|
|||||||
1,
|
1,
|
||||||
)
|
)
|
||||||
|
|
||||||
while not self.ptz_metrics[camera]["ptz_motor_stopped"].is_set():
|
while not self.ptz_metrics[camera].motor_stopped.is_set():
|
||||||
self.onvif.get_camera_status(camera)
|
self.onvif.get_camera_status(camera)
|
||||||
|
|
||||||
zoom_in_values.append(self.ptz_metrics[camera]["ptz_zoom_level"].value)
|
zoom_in_values.append(self.ptz_metrics[camera].zoom_level.value)
|
||||||
|
|
||||||
if (
|
if (
|
||||||
self.config.cameras[camera].onvif.autotracking.zooming
|
self.config.cameras[camera].onvif.autotracking.zooming
|
||||||
@ -392,12 +396,10 @@ class PtzAutoTracker:
|
|||||||
1,
|
1,
|
||||||
)
|
)
|
||||||
|
|
||||||
while not self.ptz_metrics[camera]["ptz_motor_stopped"].is_set():
|
while not self.ptz_metrics[camera].motor_stopped.is_set():
|
||||||
self.onvif.get_camera_status(camera)
|
self.onvif.get_camera_status(camera)
|
||||||
|
|
||||||
zoom_out_values.append(
|
zoom_out_values.append(self.ptz_metrics[camera].zoom_level.value)
|
||||||
self.ptz_metrics[camera]["ptz_zoom_level"].value
|
|
||||||
)
|
|
||||||
|
|
||||||
# relative move to 0.01
|
# relative move to 0.01
|
||||||
self.onvif._move_relative(
|
self.onvif._move_relative(
|
||||||
@ -408,33 +410,31 @@ class PtzAutoTracker:
|
|||||||
1,
|
1,
|
||||||
)
|
)
|
||||||
|
|
||||||
while not self.ptz_metrics[camera]["ptz_motor_stopped"].is_set():
|
while not self.ptz_metrics[camera].motor_stopped.is_set():
|
||||||
self.onvif.get_camera_status(camera)
|
self.onvif.get_camera_status(camera)
|
||||||
|
|
||||||
zoom_in_values.append(
|
zoom_in_values.append(self.ptz_metrics[camera].zoom_level.value)
|
||||||
self.ptz_metrics[camera]["ptz_zoom_level"].value
|
|
||||||
)
|
|
||||||
|
|
||||||
self.ptz_metrics[camera]["ptz_max_zoom"].value = max(zoom_in_values)
|
self.ptz_metrics[camera].max_zoom.value = max(zoom_in_values)
|
||||||
self.ptz_metrics[camera]["ptz_min_zoom"].value = min(zoom_out_values)
|
self.ptz_metrics[camera].min_zoom.value = min(zoom_out_values)
|
||||||
|
|
||||||
logger.debug(
|
logger.debug(
|
||||||
f'{camera}: Calibration values: max zoom: {self.ptz_metrics[camera]["ptz_max_zoom"].value}, min zoom: {self.ptz_metrics[camera]["ptz_min_zoom"].value}'
|
f"{camera}: Calibration values: max zoom: {self.ptz_metrics[camera].max_zoom.value}, min zoom: {self.ptz_metrics[camera].min_zoom.value}"
|
||||||
)
|
)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
self.ptz_metrics[camera]["ptz_max_zoom"].value = 1
|
self.ptz_metrics[camera].max_zoom.value = 1
|
||||||
self.ptz_metrics[camera]["ptz_min_zoom"].value = 0
|
self.ptz_metrics[camera].min_zoom.value = 0
|
||||||
|
|
||||||
self.onvif._move_to_preset(
|
self.onvif._move_to_preset(
|
||||||
camera,
|
camera,
|
||||||
self.config.cameras[camera].onvif.autotracking.return_preset.lower(),
|
self.config.cameras[camera].onvif.autotracking.return_preset.lower(),
|
||||||
)
|
)
|
||||||
self.ptz_metrics[camera]["ptz_reset"].set()
|
self.ptz_metrics[camera].reset.set()
|
||||||
self.ptz_metrics[camera]["ptz_motor_stopped"].clear()
|
self.ptz_metrics[camera].motor_stopped.clear()
|
||||||
|
|
||||||
# Wait until the camera finishes moving
|
# Wait until the camera finishes moving
|
||||||
while not self.ptz_metrics[camera]["ptz_motor_stopped"].is_set():
|
while not self.ptz_metrics[camera].motor_stopped.is_set():
|
||||||
self.onvif.get_camera_status(camera)
|
self.onvif.get_camera_status(camera)
|
||||||
|
|
||||||
for step in range(num_steps):
|
for step in range(num_steps):
|
||||||
@ -445,7 +445,7 @@ class PtzAutoTracker:
|
|||||||
self.onvif._move_relative(camera, pan, tilt, 0, 1)
|
self.onvif._move_relative(camera, pan, tilt, 0, 1)
|
||||||
|
|
||||||
# Wait until the camera finishes moving
|
# Wait until the camera finishes moving
|
||||||
while not self.ptz_metrics[camera]["ptz_motor_stopped"].is_set():
|
while not self.ptz_metrics[camera].motor_stopped.is_set():
|
||||||
self.onvif.get_camera_status(camera)
|
self.onvif.get_camera_status(camera)
|
||||||
stop_time = time.time()
|
stop_time = time.time()
|
||||||
|
|
||||||
@ -462,11 +462,11 @@ class PtzAutoTracker:
|
|||||||
camera,
|
camera,
|
||||||
self.config.cameras[camera].onvif.autotracking.return_preset.lower(),
|
self.config.cameras[camera].onvif.autotracking.return_preset.lower(),
|
||||||
)
|
)
|
||||||
self.ptz_metrics[camera]["ptz_reset"].set()
|
self.ptz_metrics[camera].reset.set()
|
||||||
self.ptz_metrics[camera]["ptz_motor_stopped"].clear()
|
self.ptz_metrics[camera].motor_stopped.clear()
|
||||||
|
|
||||||
# Wait until the camera finishes moving
|
# Wait until the camera finishes moving
|
||||||
while not self.ptz_metrics[camera]["ptz_motor_stopped"].is_set():
|
while not self.ptz_metrics[camera].motor_stopped.is_set():
|
||||||
self.onvif.get_camera_status(camera)
|
self.onvif.get_camera_status(camera)
|
||||||
|
|
||||||
logger.info(
|
logger.info(
|
||||||
@ -512,8 +512,8 @@ class PtzAutoTracker:
|
|||||||
self.config.cameras[camera].onvif.autotracking.movement_weights = ", ".join(
|
self.config.cameras[camera].onvif.autotracking.movement_weights = ", ".join(
|
||||||
str(v)
|
str(v)
|
||||||
for v in [
|
for v in [
|
||||||
self.ptz_metrics[camera]["ptz_min_zoom"].value,
|
self.ptz_metrics[camera].min_zoom.value,
|
||||||
self.ptz_metrics[camera]["ptz_max_zoom"].value,
|
self.ptz_metrics[camera].max_zoom.value,
|
||||||
self.intercept[camera],
|
self.intercept[camera],
|
||||||
*self.move_coefficients[camera],
|
*self.move_coefficients[camera],
|
||||||
]
|
]
|
||||||
@ -649,8 +649,8 @@ class PtzAutoTracker:
|
|||||||
# if we're receiving move requests during a PTZ move, ignore them
|
# if we're receiving move requests during a PTZ move, ignore them
|
||||||
if ptz_moving_at_frame_time(
|
if ptz_moving_at_frame_time(
|
||||||
frame_time,
|
frame_time,
|
||||||
self.ptz_metrics[camera]["ptz_start_time"].value,
|
self.ptz_metrics[camera].start_time.value,
|
||||||
self.ptz_metrics[camera]["ptz_stop_time"].value,
|
self.ptz_metrics[camera].stop_time.value,
|
||||||
):
|
):
|
||||||
# instead of dequeueing this might be a good place to preemptively move based
|
# instead of dequeueing this might be a good place to preemptively move based
|
||||||
# on an estimate - for fast moving objects, etc.
|
# on an estimate - for fast moving objects, etc.
|
||||||
@ -671,19 +671,17 @@ class PtzAutoTracker:
|
|||||||
self.onvif._move_relative(camera, pan, tilt, 0, 1)
|
self.onvif._move_relative(camera, pan, tilt, 0, 1)
|
||||||
|
|
||||||
# Wait until the camera finishes moving
|
# Wait until the camera finishes moving
|
||||||
while not self.ptz_metrics[camera][
|
while not self.ptz_metrics[camera].motor_stopped.is_set():
|
||||||
"ptz_motor_stopped"
|
|
||||||
].is_set():
|
|
||||||
self.onvif.get_camera_status(camera)
|
self.onvif.get_camera_status(camera)
|
||||||
|
|
||||||
if (
|
if (
|
||||||
zoom > 0
|
zoom > 0
|
||||||
and self.ptz_metrics[camera]["ptz_zoom_level"].value != zoom
|
and self.ptz_metrics[camera].zoom_level.value != zoom
|
||||||
):
|
):
|
||||||
self.onvif._zoom_absolute(camera, zoom, 1)
|
self.onvif._zoom_absolute(camera, zoom, 1)
|
||||||
|
|
||||||
# Wait until the camera finishes moving
|
# Wait until the camera finishes moving
|
||||||
while not self.ptz_metrics[camera]["ptz_motor_stopped"].is_set():
|
while not self.ptz_metrics[camera].motor_stopped.is_set():
|
||||||
self.onvif.get_camera_status(camera)
|
self.onvif.get_camera_status(camera)
|
||||||
|
|
||||||
if self.config.cameras[camera].onvif.autotracking.movement_weights:
|
if self.config.cameras[camera].onvif.autotracking.movement_weights:
|
||||||
@ -691,7 +689,7 @@ class PtzAutoTracker:
|
|||||||
f"{camera}: Predicted movement time: {self._predict_movement_time(camera, pan, tilt)}"
|
f"{camera}: Predicted movement time: {self._predict_movement_time(camera, pan, tilt)}"
|
||||||
)
|
)
|
||||||
logger.debug(
|
logger.debug(
|
||||||
f'{camera}: Actual movement time: {self.ptz_metrics[camera]["ptz_stop_time"].value-self.ptz_metrics[camera]["ptz_start_time"].value}'
|
f"{camera}: Actual movement time: {self.ptz_metrics[camera].stop_time.value-self.ptz_metrics[camera].start_time.value}"
|
||||||
)
|
)
|
||||||
|
|
||||||
# save metrics for better estimate calculations
|
# save metrics for better estimate calculations
|
||||||
@ -709,12 +707,12 @@ class PtzAutoTracker:
|
|||||||
{
|
{
|
||||||
"pan": pan,
|
"pan": pan,
|
||||||
"tilt": tilt,
|
"tilt": tilt,
|
||||||
"start_timestamp": self.ptz_metrics[camera][
|
"start_timestamp": self.ptz_metrics[
|
||||||
"ptz_start_time"
|
camera
|
||||||
].value,
|
].start_time.value,
|
||||||
"end_timestamp": self.ptz_metrics[camera][
|
"end_timestamp": self.ptz_metrics[
|
||||||
"ptz_stop_time"
|
camera
|
||||||
].value,
|
].stop_time.value,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -734,8 +732,8 @@ class PtzAutoTracker:
|
|||||||
return clipped, diff
|
return clipped, diff
|
||||||
|
|
||||||
if (
|
if (
|
||||||
frame_time > self.ptz_metrics[camera]["ptz_start_time"].value
|
frame_time > self.ptz_metrics[camera].start_time.value
|
||||||
and frame_time > self.ptz_metrics[camera]["ptz_stop_time"].value
|
and frame_time > self.ptz_metrics[camera].stop_time.value
|
||||||
and not self.move_queue_locks[camera].locked()
|
and not self.move_queue_locks[camera].locked()
|
||||||
):
|
):
|
||||||
# we can split up any large moves caused by velocity estimated movements if necessary
|
# we can split up any large moves caused by velocity estimated movements if necessary
|
||||||
@ -954,12 +952,12 @@ class PtzAutoTracker:
|
|||||||
)
|
)
|
||||||
|
|
||||||
at_max_zoom = (
|
at_max_zoom = (
|
||||||
self.ptz_metrics[camera]["ptz_zoom_level"].value
|
self.ptz_metrics[camera].zoom_level.value
|
||||||
== self.ptz_metrics[camera]["ptz_max_zoom"].value
|
== self.ptz_metrics[camera].max_zoom.value
|
||||||
)
|
)
|
||||||
at_min_zoom = (
|
at_min_zoom = (
|
||||||
self.ptz_metrics[camera]["ptz_zoom_level"].value
|
self.ptz_metrics[camera].zoom_level.value
|
||||||
== self.ptz_metrics[camera]["ptz_min_zoom"].value
|
== self.ptz_metrics[camera].min_zoom.value
|
||||||
)
|
)
|
||||||
|
|
||||||
# debug zooming
|
# debug zooming
|
||||||
@ -1100,7 +1098,7 @@ class PtzAutoTracker:
|
|||||||
|
|
||||||
zoom = 0
|
zoom = 0
|
||||||
result = None
|
result = None
|
||||||
current_zoom_level = self.ptz_metrics[camera]["ptz_zoom_level"].value
|
current_zoom_level = self.ptz_metrics[camera].zoom_level.value
|
||||||
target_box = max(
|
target_box = max(
|
||||||
obj.obj_data["box"][2] - obj.obj_data["box"][0],
|
obj.obj_data["box"][2] - obj.obj_data["box"][0],
|
||||||
obj.obj_data["box"][3] - obj.obj_data["box"][1],
|
obj.obj_data["box"][3] - obj.obj_data["box"][1],
|
||||||
@ -1123,8 +1121,8 @@ class PtzAutoTracker:
|
|||||||
) is not None:
|
) is not None:
|
||||||
# divide zoom in 10 increments and always zoom out more than in
|
# divide zoom in 10 increments and always zoom out more than in
|
||||||
level = (
|
level = (
|
||||||
self.ptz_metrics[camera]["ptz_max_zoom"].value
|
self.ptz_metrics[camera].max_zoom.value
|
||||||
- self.ptz_metrics[camera]["ptz_min_zoom"].value
|
- self.ptz_metrics[camera].min_zoom.value
|
||||||
) / 20
|
) / 20
|
||||||
if result:
|
if result:
|
||||||
zoom = min(1.0, current_zoom_level + level)
|
zoom = min(1.0, current_zoom_level + level)
|
||||||
@ -1219,7 +1217,7 @@ class PtzAutoTracker:
|
|||||||
logger.debug(
|
logger.debug(
|
||||||
f"{camera}: New object: {obj.obj_data['id']} {obj.obj_data['box']} {obj.obj_data['frame_time']}"
|
f"{camera}: New object: {obj.obj_data['id']} {obj.obj_data['box']} {obj.obj_data['frame_time']}"
|
||||||
)
|
)
|
||||||
self.ptz_metrics[camera]["ptz_tracking_active"].set()
|
self.ptz_metrics[camera].tracking_active.set()
|
||||||
self.dispatcher.publish(
|
self.dispatcher.publish(
|
||||||
f"{camera}/ptz_autotracker/active", "ON", retain=False
|
f"{camera}/ptz_autotracker/active", "ON", retain=False
|
||||||
)
|
)
|
||||||
@ -1243,8 +1241,8 @@ class PtzAutoTracker:
|
|||||||
|
|
||||||
if not ptz_moving_at_frame_time(
|
if not ptz_moving_at_frame_time(
|
||||||
obj.obj_data["frame_time"],
|
obj.obj_data["frame_time"],
|
||||||
self.ptz_metrics[camera]["ptz_start_time"].value,
|
self.ptz_metrics[camera].start_time.value,
|
||||||
self.ptz_metrics[camera]["ptz_stop_time"].value,
|
self.ptz_metrics[camera].stop_time.value,
|
||||||
):
|
):
|
||||||
if self.tracked_object_metrics[camera]["below_distance_threshold"]:
|
if self.tracked_object_metrics[camera]["below_distance_threshold"]:
|
||||||
logger.debug(
|
logger.debug(
|
||||||
@ -1325,7 +1323,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.ptz_metrics[camera]["ptz_motor_stopped"].is_set():
|
if not self.ptz_metrics[camera].motor_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
|
||||||
@ -1334,7 +1332,7 @@ class PtzAutoTracker:
|
|||||||
and self.tracked_object_history[camera]
|
and self.tracked_object_history[camera]
|
||||||
and (
|
and (
|
||||||
# might want to use a different timestamp here?
|
# might want to use a different timestamp here?
|
||||||
self.ptz_metrics[camera]["ptz_frame_time"].value
|
self.ptz_metrics[camera].frame_time.value
|
||||||
- self.tracked_object_history[camera][-1]["frame_time"]
|
- self.tracked_object_history[camera][-1]["frame_time"]
|
||||||
>= autotracker_config.timeout
|
>= autotracker_config.timeout
|
||||||
)
|
)
|
||||||
@ -1348,9 +1346,9 @@ class PtzAutoTracker:
|
|||||||
while not self.move_queues[camera].empty():
|
while not self.move_queues[camera].empty():
|
||||||
self.move_queues[camera].get()
|
self.move_queues[camera].get()
|
||||||
|
|
||||||
self.ptz_metrics[camera]["ptz_motor_stopped"].wait()
|
self.ptz_metrics[camera].motor_stopped.wait()
|
||||||
logger.debug(
|
logger.debug(
|
||||||
f"{camera}: Time is {self.ptz_metrics[camera]['ptz_frame_time'].value}, returning to preset: {autotracker_config.return_preset}"
|
f"{camera}: Time is {self.ptz_metrics[camera].frame_time.value}, returning to preset: {autotracker_config.return_preset}"
|
||||||
)
|
)
|
||||||
self.onvif._move_to_preset(
|
self.onvif._move_to_preset(
|
||||||
camera,
|
camera,
|
||||||
@ -1358,11 +1356,11 @@ class PtzAutoTracker:
|
|||||||
)
|
)
|
||||||
|
|
||||||
# update stored zoom level from preset
|
# update stored zoom level from preset
|
||||||
if not self.ptz_metrics[camera]["ptz_motor_stopped"].is_set():
|
if not self.ptz_metrics[camera].motor_stopped.is_set():
|
||||||
self.onvif.get_camera_status(camera)
|
self.onvif.get_camera_status(camera)
|
||||||
|
|
||||||
self.ptz_metrics[camera]["ptz_tracking_active"].clear()
|
self.ptz_metrics[camera].tracking_active.clear()
|
||||||
self.dispatcher.publish(
|
self.dispatcher.publish(
|
||||||
f"{camera}/ptz_autotracker/active", "OFF", retain=False
|
f"{camera}/ptz_autotracker/active", "OFF", retain=False
|
||||||
)
|
)
|
||||||
self.ptz_metrics[camera]["ptz_reset"].set()
|
self.ptz_metrics[camera].reset.set()
|
||||||
|
|||||||
@ -10,8 +10,8 @@ from onvif import ONVIFCamera, ONVIFError
|
|||||||
from zeep.exceptions import Fault, TransportError
|
from zeep.exceptions import Fault, TransportError
|
||||||
from zeep.transports import Transport
|
from zeep.transports import Transport
|
||||||
|
|
||||||
|
from frigate.camera import PTZMetrics
|
||||||
from frigate.config import FrigateConfig, ZoomingModeEnum
|
from frigate.config import FrigateConfig, ZoomingModeEnum
|
||||||
from frigate.types import PTZMetricsTypes
|
|
||||||
from frigate.util.builtin import find_by_key
|
from frigate.util.builtin import find_by_key
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
@ -33,8 +33,10 @@ class OnvifCommandEnum(str, Enum):
|
|||||||
|
|
||||||
|
|
||||||
class OnvifController:
|
class OnvifController:
|
||||||
|
ptz_metrics: dict[str, PTZMetrics]
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self, config: FrigateConfig, ptz_metrics: dict[str, PTZMetricsTypes]
|
self, config: FrigateConfig, ptz_metrics: dict[str, PTZMetrics]
|
||||||
) -> None:
|
) -> None:
|
||||||
self.cams: dict[str, ONVIFCamera] = {}
|
self.cams: dict[str, ONVIFCamera] = {}
|
||||||
self.config = config
|
self.config = config
|
||||||
@ -389,14 +391,14 @@ class OnvifController:
|
|||||||
return
|
return
|
||||||
|
|
||||||
self.cams[camera_name]["active"] = True
|
self.cams[camera_name]["active"] = True
|
||||||
self.ptz_metrics[camera_name]["ptz_motor_stopped"].clear()
|
self.ptz_metrics[camera_name].motor_stopped.clear()
|
||||||
logger.debug(
|
logger.debug(
|
||||||
f"{camera_name}: PTZ start time: {self.ptz_metrics[camera_name]['ptz_frame_time'].value}"
|
f"{camera_name}: PTZ start time: {self.ptz_metrics[camera_name].frame_time.value}"
|
||||||
)
|
)
|
||||||
self.ptz_metrics[camera_name]["ptz_start_time"].value = self.ptz_metrics[
|
self.ptz_metrics[camera_name].start_time.value = self.ptz_metrics[
|
||||||
camera_name
|
camera_name
|
||||||
]["ptz_frame_time"].value
|
].frame_time.value
|
||||||
self.ptz_metrics[camera_name]["ptz_stop_time"].value = 0
|
self.ptz_metrics[camera_name].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"]
|
||||||
|
|
||||||
@ -464,9 +466,9 @@ class OnvifController:
|
|||||||
return
|
return
|
||||||
|
|
||||||
self.cams[camera_name]["active"] = True
|
self.cams[camera_name]["active"] = True
|
||||||
self.ptz_metrics[camera_name]["ptz_motor_stopped"].clear()
|
self.ptz_metrics[camera_name].motor_stopped.clear()
|
||||||
self.ptz_metrics[camera_name]["ptz_start_time"].value = 0
|
self.ptz_metrics[camera_name].start_time.value = 0
|
||||||
self.ptz_metrics[camera_name]["ptz_stop_time"].value = 0
|
self.ptz_metrics[camera_name].stop_time.value = 0
|
||||||
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]
|
||||||
@ -515,14 +517,14 @@ class OnvifController:
|
|||||||
return
|
return
|
||||||
|
|
||||||
self.cams[camera_name]["active"] = True
|
self.cams[camera_name]["active"] = True
|
||||||
self.ptz_metrics[camera_name]["ptz_motor_stopped"].clear()
|
self.ptz_metrics[camera_name].motor_stopped.clear()
|
||||||
logger.debug(
|
logger.debug(
|
||||||
f"{camera_name}: PTZ start time: {self.ptz_metrics[camera_name]['ptz_frame_time'].value}"
|
f"{camera_name}: PTZ start time: {self.ptz_metrics[camera_name].frame_time.value}"
|
||||||
)
|
)
|
||||||
self.ptz_metrics[camera_name]["ptz_start_time"].value = self.ptz_metrics[
|
self.ptz_metrics[camera_name].start_time.value = self.ptz_metrics[
|
||||||
camera_name
|
camera_name
|
||||||
]["ptz_frame_time"].value
|
].frame_time.value
|
||||||
self.ptz_metrics[camera_name]["ptz_stop_time"].value = 0
|
self.ptz_metrics[camera_name].stop_time.value = 0
|
||||||
onvif: ONVIFCamera = self.cams[camera_name]["onvif"]
|
onvif: ONVIFCamera = self.cams[camera_name]["onvif"]
|
||||||
move_request = self.cams[camera_name]["absolute_move_request"]
|
move_request = self.cams[camera_name]["absolute_move_request"]
|
||||||
|
|
||||||
@ -653,36 +655,36 @@ class OnvifController:
|
|||||||
|
|
||||||
if pan_tilt_status == "IDLE" and (zoom_status is None or zoom_status == "IDLE"):
|
if pan_tilt_status == "IDLE" and (zoom_status is None or zoom_status == "IDLE"):
|
||||||
self.cams[camera_name]["active"] = False
|
self.cams[camera_name]["active"] = False
|
||||||
if not self.ptz_metrics[camera_name]["ptz_motor_stopped"].is_set():
|
if not self.ptz_metrics[camera_name].motor_stopped.is_set():
|
||||||
self.ptz_metrics[camera_name]["ptz_motor_stopped"].set()
|
self.ptz_metrics[camera_name].motor_stopped.set()
|
||||||
|
|
||||||
logger.debug(
|
logger.debug(
|
||||||
f"{camera_name}: PTZ stop time: {self.ptz_metrics[camera_name]['ptz_frame_time'].value}"
|
f"{camera_name}: PTZ stop time: {self.ptz_metrics[camera_name].frame_time.value}"
|
||||||
)
|
)
|
||||||
|
|
||||||
self.ptz_metrics[camera_name]["ptz_stop_time"].value = self.ptz_metrics[
|
self.ptz_metrics[camera_name].stop_time.value = self.ptz_metrics[
|
||||||
camera_name
|
camera_name
|
||||||
]["ptz_frame_time"].value
|
].frame_time.value
|
||||||
else:
|
else:
|
||||||
self.cams[camera_name]["active"] = True
|
self.cams[camera_name]["active"] = True
|
||||||
if self.ptz_metrics[camera_name]["ptz_motor_stopped"].is_set():
|
if self.ptz_metrics[camera_name].motor_stopped.is_set():
|
||||||
self.ptz_metrics[camera_name]["ptz_motor_stopped"].clear()
|
self.ptz_metrics[camera_name].motor_stopped.clear()
|
||||||
|
|
||||||
logger.debug(
|
logger.debug(
|
||||||
f"{camera_name}: PTZ start time: {self.ptz_metrics[camera_name]['ptz_frame_time'].value}"
|
f"{camera_name}: PTZ start time: {self.ptz_metrics[camera_name].frame_time.value}"
|
||||||
)
|
)
|
||||||
|
|
||||||
self.ptz_metrics[camera_name][
|
self.ptz_metrics[camera_name].start_time.value = self.ptz_metrics[
|
||||||
"ptz_start_time"
|
camera_name
|
||||||
].value = self.ptz_metrics[camera_name]["ptz_frame_time"].value
|
].frame_time.value
|
||||||
self.ptz_metrics[camera_name]["ptz_stop_time"].value = 0
|
self.ptz_metrics[camera_name].stop_time.value = 0
|
||||||
|
|
||||||
if (
|
if (
|
||||||
self.config.cameras[camera_name].onvif.autotracking.zooming
|
self.config.cameras[camera_name].onvif.autotracking.zooming
|
||||||
!= ZoomingModeEnum.disabled
|
!= ZoomingModeEnum.disabled
|
||||||
):
|
):
|
||||||
# store absolute zoom level as 0 to 1 interpolated from the values of the camera
|
# store absolute zoom level as 0 to 1 interpolated from the values of the camera
|
||||||
self.ptz_metrics[camera_name]["ptz_zoom_level"].value = numpy.interp(
|
self.ptz_metrics[camera_name].zoom_level.value = numpy.interp(
|
||||||
round(status.Position.Zoom.x, 2),
|
round(status.Position.Zoom.x, 2),
|
||||||
[0, 1],
|
[0, 1],
|
||||||
[
|
[
|
||||||
@ -691,23 +693,23 @@ class OnvifController:
|
|||||||
],
|
],
|
||||||
)
|
)
|
||||||
logger.debug(
|
logger.debug(
|
||||||
f'{camera_name}: Camera zoom level: {self.ptz_metrics[camera_name]["ptz_zoom_level"].value}'
|
f"{camera_name}: Camera zoom level: {self.ptz_metrics[camera_name].zoom_level.value}"
|
||||||
)
|
)
|
||||||
|
|
||||||
# some hikvision cams won't update MoveStatus, so warn if it hasn't changed
|
# some hikvision cams won't update MoveStatus, so warn if it hasn't changed
|
||||||
if (
|
if (
|
||||||
not self.ptz_metrics[camera_name]["ptz_motor_stopped"].is_set()
|
not self.ptz_metrics[camera_name].motor_stopped.is_set()
|
||||||
and not self.ptz_metrics[camera_name]["ptz_reset"].is_set()
|
and not self.ptz_metrics[camera_name].reset.is_set()
|
||||||
and self.ptz_metrics[camera_name]["ptz_start_time"].value != 0
|
and self.ptz_metrics[camera_name].start_time.value != 0
|
||||||
and self.ptz_metrics[camera_name]["ptz_frame_time"].value
|
and self.ptz_metrics[camera_name].frame_time.value
|
||||||
> (self.ptz_metrics[camera_name]["ptz_start_time"].value + 10)
|
> (self.ptz_metrics[camera_name].start_time.value + 10)
|
||||||
and self.ptz_metrics[camera_name]["ptz_stop_time"].value == 0
|
and self.ptz_metrics[camera_name].stop_time.value == 0
|
||||||
):
|
):
|
||||||
logger.debug(
|
logger.debug(
|
||||||
f'Start time: {self.ptz_metrics[camera_name]["ptz_start_time"].value}, Stop time: {self.ptz_metrics[camera_name]["ptz_stop_time"].value}, Frame time: {self.ptz_metrics[camera_name]["ptz_frame_time"].value}'
|
f"Start time: {self.ptz_metrics[camera_name].start_time.value}, Stop time: {self.ptz_metrics[camera_name].stop_time.value}, Frame time: {self.ptz_metrics[camera_name].frame_time.value}"
|
||||||
)
|
)
|
||||||
# set the stop time so we don't come back into this again and spam the logs
|
# set the stop time so we don't come back into this again and spam the logs
|
||||||
self.ptz_metrics[camera_name]["ptz_stop_time"].value = self.ptz_metrics[
|
self.ptz_metrics[camera_name].stop_time.value = self.ptz_metrics[
|
||||||
camera_name
|
camera_name
|
||||||
]["ptz_frame_time"].value
|
].frame_time.value
|
||||||
logger.warning(f"Camera {camera_name} is still in ONVIF 'MOVING' status.")
|
logger.warning(f"Camera {camera_name} is still in ONVIF 'MOVING' status.")
|
||||||
|
|||||||
@ -12,10 +12,10 @@ from norfair import (
|
|||||||
)
|
)
|
||||||
from norfair.drawing.drawer import Drawer
|
from norfair.drawing.drawer import Drawer
|
||||||
|
|
||||||
|
from frigate.camera import PTZMetrics
|
||||||
from frigate.config import CameraConfig
|
from frigate.config import CameraConfig
|
||||||
from frigate.ptz.autotrack import PtzMotionEstimator
|
from frigate.ptz.autotrack import PtzMotionEstimator
|
||||||
from frigate.track import ObjectTracker
|
from frigate.track import ObjectTracker
|
||||||
from frigate.types import PTZMetricsTypes
|
|
||||||
from frigate.util.image import intersection_over_union
|
from frigate.util.image import intersection_over_union
|
||||||
from frigate.util.object import average_boxes, median_of_boxes
|
from frigate.util.object import average_boxes, median_of_boxes
|
||||||
|
|
||||||
@ -75,7 +75,7 @@ class NorfairTracker(ObjectTracker):
|
|||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
config: CameraConfig,
|
config: CameraConfig,
|
||||||
ptz_metrics: PTZMetricsTypes,
|
ptz_metrics: PTZMetrics,
|
||||||
):
|
):
|
||||||
self.tracked_objects = {}
|
self.tracked_objects = {}
|
||||||
self.untracked_object_boxes: list[list[int]] = []
|
self.untracked_object_boxes: list[list[int]] = []
|
||||||
@ -85,7 +85,7 @@ class NorfairTracker(ObjectTracker):
|
|||||||
self.camera_config = config
|
self.camera_config = config
|
||||||
self.detect_config = config.detect
|
self.detect_config = config.detect
|
||||||
self.ptz_metrics = ptz_metrics
|
self.ptz_metrics = ptz_metrics
|
||||||
self.ptz_autotracker_enabled = ptz_metrics["ptz_autotracker_enabled"]
|
self.ptz_autotracker_enabled = ptz_metrics.autotracker_enabled
|
||||||
self.ptz_motion_estimator = {}
|
self.ptz_motion_estimator = {}
|
||||||
self.camera_name = config.name
|
self.camera_name = config.name
|
||||||
self.track_id_map = {}
|
self.track_id_map = {}
|
||||||
|
|||||||
@ -1,24 +1,9 @@
|
|||||||
from multiprocessing.sharedctypes import Synchronized
|
|
||||||
from multiprocessing.synchronize import Event
|
|
||||||
from typing import TypedDict
|
from typing import TypedDict
|
||||||
|
|
||||||
from frigate.camera import CameraMetrics
|
from frigate.camera import CameraMetrics
|
||||||
from frigate.object_detection import ObjectDetectProcess
|
from frigate.object_detection import ObjectDetectProcess
|
||||||
|
|
||||||
|
|
||||||
class PTZMetricsTypes(TypedDict):
|
|
||||||
ptz_autotracker_enabled: Synchronized
|
|
||||||
ptz_tracking_active: Event
|
|
||||||
ptz_motor_stopped: Event
|
|
||||||
ptz_reset: Event
|
|
||||||
ptz_start_time: Synchronized
|
|
||||||
ptz_stop_time: Synchronized
|
|
||||||
ptz_frame_time: Synchronized
|
|
||||||
ptz_zoom_level: Synchronized
|
|
||||||
ptz_max_zoom: Synchronized
|
|
||||||
ptz_min_zoom: Synchronized
|
|
||||||
|
|
||||||
|
|
||||||
class StatsTrackingTypes(TypedDict):
|
class StatsTrackingTypes(TypedDict):
|
||||||
camera_metrics: dict[str, CameraMetrics]
|
camera_metrics: dict[str, CameraMetrics]
|
||||||
detectors: dict[str, ObjectDetectProcess]
|
detectors: dict[str, ObjectDetectProcess]
|
||||||
|
|||||||
@ -11,7 +11,7 @@ import time
|
|||||||
import cv2
|
import cv2
|
||||||
from setproctitle import setproctitle
|
from setproctitle import setproctitle
|
||||||
|
|
||||||
from frigate.camera import CameraMetrics
|
from frigate.camera import CameraMetrics, PTZMetrics
|
||||||
from frigate.comms.config_updater import ConfigSubscriber
|
from frigate.comms.config_updater import ConfigSubscriber
|
||||||
from frigate.comms.inter_process import InterProcessRequestor
|
from frigate.comms.inter_process import InterProcessRequestor
|
||||||
from frigate.config import CameraConfig, DetectConfig, ModelConfig
|
from frigate.config import CameraConfig, DetectConfig, ModelConfig
|
||||||
@ -29,7 +29,6 @@ from frigate.object_detection import RemoteObjectDetector
|
|||||||
from frigate.ptz.autotrack import ptz_moving_at_frame_time
|
from frigate.ptz.autotrack import ptz_moving_at_frame_time
|
||||||
from frigate.track import ObjectTracker
|
from frigate.track import ObjectTracker
|
||||||
from frigate.track.norfair_tracker import NorfairTracker
|
from frigate.track.norfair_tracker import NorfairTracker
|
||||||
from frigate.types import PTZMetricsTypes
|
|
||||||
from frigate.util.builtin import EventsPerSecond, get_tomorrow_at_time
|
from frigate.util.builtin import EventsPerSecond, get_tomorrow_at_time
|
||||||
from frigate.util.image import (
|
from frigate.util.image import (
|
||||||
FrameManager,
|
FrameManager,
|
||||||
@ -424,7 +423,7 @@ def track_camera(
|
|||||||
result_connection,
|
result_connection,
|
||||||
detected_objects_queue,
|
detected_objects_queue,
|
||||||
camera_metrics: CameraMetrics,
|
camera_metrics: CameraMetrics,
|
||||||
ptz_metrics,
|
ptz_metrics: PTZMetrics,
|
||||||
region_grid,
|
region_grid,
|
||||||
):
|
):
|
||||||
stop_event = mp.Event()
|
stop_event = mp.Event()
|
||||||
@ -548,7 +547,7 @@ def process_frames(
|
|||||||
objects_to_track: list[str],
|
objects_to_track: list[str],
|
||||||
object_filters,
|
object_filters,
|
||||||
stop_event,
|
stop_event,
|
||||||
ptz_metrics: PTZMetricsTypes,
|
ptz_metrics: PTZMetrics,
|
||||||
region_grid,
|
region_grid,
|
||||||
exit_on_empty: bool = False,
|
exit_on_empty: bool = False,
|
||||||
):
|
):
|
||||||
@ -589,7 +588,7 @@ def process_frames(
|
|||||||
continue
|
continue
|
||||||
|
|
||||||
camera_metrics.detection_frame.value = frame_time
|
camera_metrics.detection_frame.value = frame_time
|
||||||
ptz_metrics["ptz_frame_time"].value = frame_time
|
ptz_metrics.frame_time.value = frame_time
|
||||||
|
|
||||||
frame = frame_manager.get(
|
frame = frame_manager.get(
|
||||||
f"{camera_name}{frame_time}", (frame_shape[0] * 3 // 2, frame_shape[1])
|
f"{camera_name}{frame_time}", (frame_shape[0] * 3 // 2, frame_shape[1])
|
||||||
@ -659,8 +658,8 @@ def process_frames(
|
|||||||
# ptz_moving_at_frame_time() always returns False for non-autotracking cameras
|
# ptz_moving_at_frame_time() always returns False for non-autotracking cameras
|
||||||
if not motion_detector.is_calibrating() and not ptz_moving_at_frame_time(
|
if not motion_detector.is_calibrating() and not ptz_moving_at_frame_time(
|
||||||
frame_time,
|
frame_time,
|
||||||
ptz_metrics["ptz_start_time"].value,
|
ptz_metrics.start_time.value,
|
||||||
ptz_metrics["ptz_stop_time"].value,
|
ptz_metrics.stop_time.value,
|
||||||
):
|
):
|
||||||
# find motion boxes that are not inside tracked object regions
|
# find motion boxes that are not inside tracked object regions
|
||||||
standalone_motion_boxes = [
|
standalone_motion_boxes = [
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user