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):
|
class PtzAutotrackConfig(FrigateBaseModel):
|
||||||
enabled: bool = Field(default=False, title="Enable PTZ object autotracking.")
|
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.")
|
track: List[str] = Field(default=DEFAULT_TRACKED_OBJECTS, title="Objects to track.")
|
||||||
required_zones: List[str] = Field(
|
required_zones: List[str] = Field(
|
||||||
default_factory=list,
|
default_factory=list,
|
||||||
|
|||||||
@ -11,7 +11,11 @@ from multiprocessing.synchronize import Event as MpEvent
|
|||||||
|
|
||||||
import cv2
|
import cv2
|
||||||
import numpy as np
|
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.config import CameraConfig, FrigateConfig
|
||||||
from frigate.ptz.onvif import OnvifController
|
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 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["ptz_reset"].is_set():
|
||||||
self.ptz_metrics["ptz_reset"].clear()
|
self.ptz_metrics["ptz_reset"].clear()
|
||||||
logger.debug("Motion estimator reset")
|
|
||||||
# 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.
|
||||||
self.norfair_motion_estimator = MotionEstimator(
|
if self.camera_config.onvif.autotracking.zooming:
|
||||||
transformations_getter=HomographyTransformationGetter(),
|
logger.debug("Motion estimator reset - homography")
|
||||||
min_distance=30,
|
self.norfair_motion_estimator = MotionEstimator(
|
||||||
max_points=900,
|
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
|
self.coord_transformations = None
|
||||||
|
|
||||||
if ptz_moving_at_frame_time(
|
if ptz_moving_at_frame_time(
|
||||||
@ -97,10 +110,11 @@ class PtzMotionEstimator:
|
|||||||
|
|
||||||
self.frame_manager.close(frame_id)
|
self.frame_manager.close(frame_id)
|
||||||
|
|
||||||
# doesn't work with homography
|
if not self.camera_config.onvif.autotracking.zooming:
|
||||||
# logger.debug(
|
# doesn't work with homography
|
||||||
# f"Motion estimator transformation: {self.coord_transformations.rel_to_abs((0,0))}"
|
logger.debug(
|
||||||
# )
|
f"Motion estimator transformation: {self.coord_transformations.rel_to_abs((0,0))}"
|
||||||
|
)
|
||||||
|
|
||||||
return self.coord_transformations
|
return self.coord_transformations
|
||||||
|
|
||||||
@ -265,26 +279,30 @@ class PtzAutoTracker:
|
|||||||
def _autotrack_zoom_ptz(self, camera, obj):
|
def _autotrack_zoom_ptz(self, camera, obj):
|
||||||
camera_config = self.config.cameras[camera]
|
camera_config = self.config.cameras[camera]
|
||||||
|
|
||||||
# frame width and height
|
if camera_config.onvif.autotracking.zooming:
|
||||||
camera_width = camera_config.frame_shape[1]
|
# frame width and height
|
||||||
camera_height = camera_config.frame_shape[0]
|
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:
|
# ensure zooming level is in range
|
||||||
if (
|
# if so, check if bounding box is 10% of an edge
|
||||||
bb_left > 0.1 * camera_width
|
# if so, try zooming in, otherwise try zooming out
|
||||||
and bb_right < 0.9 * camera_width
|
if -1 <= zoom_level < 1:
|
||||||
and bb_top > 0.1 * camera_height
|
if (
|
||||||
and bb_bottom < 0.9 * camera_height
|
bb_left > 0.1 * camera_width
|
||||||
):
|
and bb_right < 0.9 * camera_width
|
||||||
zoom = 0.1 # Zoom in
|
and bb_top > 0.1 * camera_height
|
||||||
else:
|
and bb_bottom < 0.9 * camera_height
|
||||||
zoom = -0.1 # Zoom out
|
):
|
||||||
|
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):
|
def autotrack_object(self, camera, obj):
|
||||||
camera_config = self.config.cameras[camera]
|
camera_config = self.config.cameras[camera]
|
||||||
|
|||||||
@ -33,6 +33,7 @@ class OnvifController:
|
|||||||
self, config: FrigateConfig, ptz_metrics: dict[str, PTZMetricsTypes]
|
self, config: FrigateConfig, ptz_metrics: dict[str, PTZMetricsTypes]
|
||||||
) -> None:
|
) -> None:
|
||||||
self.cams: dict[str, ONVIFCamera] = {}
|
self.cams: dict[str, ONVIFCamera] = {}
|
||||||
|
self.config = config
|
||||||
self.ptz_metrics = ptz_metrics
|
self.ptz_metrics = ptz_metrics
|
||||||
|
|
||||||
for cam_name, cam in config.cameras.items():
|
for cam_name, cam in config.cameras.items():
|
||||||
@ -93,16 +94,17 @@ class OnvifController:
|
|||||||
None,
|
None,
|
||||||
)
|
)
|
||||||
|
|
||||||
zoom_space_id = next(
|
if self.config.cameras[camera_name].onvif.autotracking.zooming:
|
||||||
(
|
zoom_space_id = next(
|
||||||
i
|
(
|
||||||
for i, space in enumerate(
|
i
|
||||||
ptz_config.Spaces.RelativeZoomTranslationSpace
|
for i, space in enumerate(
|
||||||
)
|
ptz_config.Spaces.RelativeZoomTranslationSpace
|
||||||
if "TranslationGenericSpace" in space["URI"]
|
)
|
||||||
),
|
if "TranslationGenericSpace" in space["URI"]
|
||||||
None,
|
),
|
||||||
)
|
None,
|
||||||
|
)
|
||||||
|
|
||||||
# setup continuous moving request
|
# setup continuous moving request
|
||||||
move_request = ptz.create_type("ContinuousMove")
|
move_request = ptz.create_type("ContinuousMove")
|
||||||
@ -121,12 +123,17 @@ class OnvifController:
|
|||||||
][fov_space_id]["URI"]
|
][fov_space_id]["URI"]
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if zoom_space_id is not None:
|
if self.config.cameras[camera_name].onvif.autotracking.zooming:
|
||||||
move_request.Translation.Zoom.space = ptz_config["Spaces"][
|
if zoom_space_id is not None:
|
||||||
"RelativeZoomTranslationSpace"
|
move_request.Translation.Zoom.space = ptz_config["Spaces"][
|
||||||
][0]["URI"]
|
"RelativeZoomTranslationSpace"
|
||||||
|
][0]["URI"]
|
||||||
except Exception:
|
except Exception:
|
||||||
# camera does not support relative zoom
|
# 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
|
pass
|
||||||
|
|
||||||
if move_request.Speed is None:
|
if move_request.Speed is None:
|
||||||
@ -351,7 +358,7 @@ class OnvifController:
|
|||||||
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"]
|
||||||
|
|
||||||
# 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 = numpy.interp(
|
||||||
zoom,
|
zoom,
|
||||||
[-1, 1],
|
[-1, 1],
|
||||||
@ -449,26 +456,32 @@ class OnvifController:
|
|||||||
].value = datetime.datetime.now().timestamp()
|
].value = datetime.datetime.now().timestamp()
|
||||||
self.ptz_metrics[camera_name]["ptz_stop_time"].value = 0
|
self.ptz_metrics[camera_name]["ptz_stop_time"].value = 0
|
||||||
|
|
||||||
logger.debug(f"PTZ zoom level: {status.Position.Zoom.x}")
|
if self.config.cameras[camera_name].onvif.autotracking.zooming:
|
||||||
self.ptz_metrics[camera_name]["ptz_zoom_level"].value = numpy.interp(
|
# interpolate the actual zoom level reported by the camera into the relative zoom range
|
||||||
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]["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"],
|
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}"
|
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 {
|
return {
|
||||||
"pan": status.Position.PanTilt.x,
|
"pan": status.Position.PanTilt.x,
|
||||||
"tilt": status.Position.PanTilt.y,
|
"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,
|
"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