mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-02-06 19:25:22 +03:00
make zooming configurable
This commit is contained in:
parent
2b52028d15
commit
6c310e11c6
@ -139,6 +139,7 @@ class MqttConfig(FrigateBaseModel):
|
||||
|
||||
class PtzAutotrackConfig(FrigateBaseModel):
|
||||
enabled: bool = Field(default=False, title="Enable PTZ object autotracking.")
|
||||
zooming: bool = Field(default=False, title="Enable zooming on autotracked object.")
|
||||
track: List[str] = Field(default=DEFAULT_TRACKED_OBJECTS, title="Objects to track.")
|
||||
required_zones: List[str] = Field(
|
||||
default_factory=list,
|
||||
|
||||
@ -11,7 +11,11 @@ from multiprocessing.synchronize import Event as MpEvent
|
||||
|
||||
import cv2
|
||||
import numpy as np
|
||||
from norfair.camera_motion import HomographyTransformationGetter, MotionEstimator
|
||||
from norfair.camera_motion import (
|
||||
HomographyTransformationGetter,
|
||||
MotionEstimator,
|
||||
TranslationTransformationGetter,
|
||||
)
|
||||
|
||||
from frigate.config import CameraConfig, FrigateConfig
|
||||
from frigate.ptz.onvif import OnvifController
|
||||
@ -54,13 +58,22 @@ class PtzMotionEstimator:
|
||||
# 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():
|
||||
self.ptz_metrics["ptz_reset"].clear()
|
||||
logger.debug("Motion estimator reset")
|
||||
# homography is nice (zooming) but slow, translation is pan/tilt only but fast.
|
||||
self.norfair_motion_estimator = MotionEstimator(
|
||||
transformations_getter=HomographyTransformationGetter(),
|
||||
min_distance=30,
|
||||
max_points=900,
|
||||
)
|
||||
if self.camera_config.onvif.autotracking.zooming:
|
||||
logger.debug("Motion estimator reset - homography")
|
||||
self.norfair_motion_estimator = MotionEstimator(
|
||||
transformations_getter=HomographyTransformationGetter(),
|
||||
min_distance=30,
|
||||
max_points=900,
|
||||
)
|
||||
else:
|
||||
logger.debug("Motion estimator reset - translation")
|
||||
self.norfair_motion_estimator = MotionEstimator(
|
||||
transformations_getter=TranslationTransformationGetter(),
|
||||
min_distance=30,
|
||||
max_points=900,
|
||||
)
|
||||
|
||||
self.coord_transformations = None
|
||||
|
||||
if ptz_moving_at_frame_time(
|
||||
@ -97,10 +110,11 @@ class PtzMotionEstimator:
|
||||
|
||||
self.frame_manager.close(frame_id)
|
||||
|
||||
# doesn't work with homography
|
||||
# logger.debug(
|
||||
# f"Motion estimator transformation: {self.coord_transformations.rel_to_abs((0,0))}"
|
||||
# )
|
||||
if not self.camera_config.onvif.autotracking.zooming:
|
||||
# doesn't work with homography
|
||||
logger.debug(
|
||||
f"Motion estimator transformation: {self.coord_transformations.rel_to_abs((0,0))}"
|
||||
)
|
||||
|
||||
return self.coord_transformations
|
||||
|
||||
@ -265,26 +279,30 @@ class PtzAutoTracker:
|
||||
def _autotrack_zoom_ptz(self, camera, obj):
|
||||
camera_config = self.config.cameras[camera]
|
||||
|
||||
# frame width and height
|
||||
camera_width = camera_config.frame_shape[1]
|
||||
camera_height = camera_config.frame_shape[0]
|
||||
if camera_config.onvif.autotracking.zooming:
|
||||
# frame width and height
|
||||
camera_width = camera_config.frame_shape[1]
|
||||
camera_height = camera_config.frame_shape[0]
|
||||
|
||||
bb_left, bb_top, bb_right, bb_bottom = obj.obj_data["box"]
|
||||
bb_left, bb_top, bb_right, bb_bottom = obj.obj_data["box"]
|
||||
|
||||
zoom_level = self.ptz_metrics[camera]["ptz_zoom_level"].value
|
||||
zoom_level = self.ptz_metrics[camera]["ptz_zoom_level"].value
|
||||
|
||||
if -1 <= zoom_level < 1:
|
||||
if (
|
||||
bb_left > 0.1 * camera_width
|
||||
and bb_right < 0.9 * camera_width
|
||||
and bb_top > 0.1 * camera_height
|
||||
and bb_bottom < 0.9 * camera_height
|
||||
):
|
||||
zoom = 0.1 # Zoom in
|
||||
else:
|
||||
zoom = -0.1 # Zoom out
|
||||
# ensure zooming level is in range
|
||||
# if so, check if bounding box is 10% of an edge
|
||||
# if so, try zooming in, otherwise try zooming out
|
||||
if -1 <= zoom_level < 1:
|
||||
if (
|
||||
bb_left > 0.1 * camera_width
|
||||
and bb_right < 0.9 * camera_width
|
||||
and bb_top > 0.1 * camera_height
|
||||
and bb_bottom < 0.9 * camera_height
|
||||
):
|
||||
zoom = 0.1 # Zoom in
|
||||
else:
|
||||
zoom = -0.1 # Zoom out
|
||||
|
||||
self._enqueue_move(camera, obj.obj_data["frame_time"], 0, 0, zoom)
|
||||
self._enqueue_move(camera, obj.obj_data["frame_time"], 0, 0, zoom)
|
||||
|
||||
def autotrack_object(self, camera, obj):
|
||||
camera_config = self.config.cameras[camera]
|
||||
|
||||
@ -33,6 +33,7 @@ class OnvifController:
|
||||
self, config: FrigateConfig, ptz_metrics: dict[str, PTZMetricsTypes]
|
||||
) -> None:
|
||||
self.cams: dict[str, ONVIFCamera] = {}
|
||||
self.config = config
|
||||
self.ptz_metrics = ptz_metrics
|
||||
|
||||
for cam_name, cam in config.cameras.items():
|
||||
@ -93,16 +94,17 @@ class OnvifController:
|
||||
None,
|
||||
)
|
||||
|
||||
zoom_space_id = next(
|
||||
(
|
||||
i
|
||||
for i, space in enumerate(
|
||||
ptz_config.Spaces.RelativeZoomTranslationSpace
|
||||
)
|
||||
if "TranslationGenericSpace" in space["URI"]
|
||||
),
|
||||
None,
|
||||
)
|
||||
if self.config.cameras[camera_name].onvif.autotracking.zooming:
|
||||
zoom_space_id = next(
|
||||
(
|
||||
i
|
||||
for i, space in enumerate(
|
||||
ptz_config.Spaces.RelativeZoomTranslationSpace
|
||||
)
|
||||
if "TranslationGenericSpace" in space["URI"]
|
||||
),
|
||||
None,
|
||||
)
|
||||
|
||||
# setup continuous moving request
|
||||
move_request = ptz.create_type("ContinuousMove")
|
||||
@ -121,12 +123,17 @@ class OnvifController:
|
||||
][fov_space_id]["URI"]
|
||||
|
||||
try:
|
||||
if zoom_space_id is not None:
|
||||
move_request.Translation.Zoom.space = ptz_config["Spaces"][
|
||||
"RelativeZoomTranslationSpace"
|
||||
][0]["URI"]
|
||||
if self.config.cameras[camera_name].onvif.autotracking.zooming:
|
||||
if zoom_space_id is not None:
|
||||
move_request.Translation.Zoom.space = ptz_config["Spaces"][
|
||||
"RelativeZoomTranslationSpace"
|
||||
][0]["URI"]
|
||||
except Exception:
|
||||
# camera does not support relative zoom
|
||||
self.config.cameras[camera_name].onvif.autotracking.zooming = False
|
||||
logger.warning(
|
||||
f"Disabling autotracking zooming for {camera_name}: Relative zoom not supported"
|
||||
)
|
||||
pass
|
||||
|
||||
if move_request.Speed is None:
|
||||
@ -351,7 +358,7 @@ class OnvifController:
|
||||
onvif: ONVIFCamera = self.cams[camera_name]["onvif"]
|
||||
move_request = self.cams[camera_name]["relative_move_request"]
|
||||
|
||||
# function takes in -1 to 1 for zoom, interpolate to the values of the camera.
|
||||
# function takes in -1 to 1 for zoom, interpolate to the relative values of the camera.
|
||||
zoom = numpy.interp(
|
||||
zoom,
|
||||
[-1, 1],
|
||||
@ -449,26 +456,32 @@ class OnvifController:
|
||||
].value = datetime.datetime.now().timestamp()
|
||||
self.ptz_metrics[camera_name]["ptz_stop_time"].value = 0
|
||||
|
||||
logger.debug(f"PTZ zoom level: {status.Position.Zoom.x}")
|
||||
self.ptz_metrics[camera_name]["ptz_zoom_level"].value = numpy.interp(
|
||||
status.Position.Zoom.x,
|
||||
[
|
||||
self.cams[camera_name]["zoom_limits"]["Range"]["XRange"]["Min"],
|
||||
self.cams[camera_name]["zoom_limits"]["Range"]["XRange"]["Max"],
|
||||
],
|
||||
[
|
||||
self.cams[camera_name]["relative_zoom_range"]["XRange"]["Min"],
|
||||
self.cams[camera_name]["relative_zoom_range"]["XRange"]["Max"],
|
||||
],
|
||||
)
|
||||
logger.debug(
|
||||
f"Relative zoom level: {self.ptz_metrics[camera_name]['ptz_zoom_level'].value}"
|
||||
)
|
||||
if self.config.cameras[camera_name].onvif.autotracking.zooming:
|
||||
# interpolate the actual zoom level reported by the camera into the relative zoom range
|
||||
self.ptz_metrics[camera_name]["ptz_zoom_level"].value = numpy.interp(
|
||||
status.Position.Zoom.x,
|
||||
[
|
||||
self.cams[camera_name]["zoom_limits"]["Range"]["XRange"]["Min"],
|
||||
self.cams[camera_name]["zoom_limits"]["Range"]["XRange"]["Max"],
|
||||
],
|
||||
[
|
||||
self.cams[camera_name]["relative_zoom_range"]["XRange"]["Min"],
|
||||
self.cams[camera_name]["relative_zoom_range"]["XRange"]["Max"],
|
||||
],
|
||||
)
|
||||
logger.debug(f"Actual zoom level: {status.Position.Zoom.x}")
|
||||
logger.debug(
|
||||
f"Relative zoom level: {self.ptz_metrics[camera_name]['ptz_zoom_level'].value}"
|
||||
)
|
||||
|
||||
return {
|
||||
"pan": status.Position.PanTilt.x,
|
||||
"tilt": status.Position.PanTilt.y,
|
||||
"zoom": status.Position.Zoom.x,
|
||||
"zoom": status.Position.Zoom.x
|
||||
if self.config.cameras[camera_name].onvif.autotracking.zooming
|
||||
else 0,
|
||||
"pantilt_moving": status.MoveStatus.PanTilt,
|
||||
"zoom_moving": status.MoveStatus.Zoom,
|
||||
"zoom_moving": status.MoveStatus.Zoom
|
||||
if self.config.cameras[camera_name].onvif.autotracking.zooming
|
||||
else "IDLE",
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user