Add MQTT topic for active autotracking (#8419)

* prevent estimate clipping when autotracking

* use unclipped estimate in distance function only

* remove autotracking velocity changes

* publish on init
This commit is contained in:
Josh Hawkins 2023-11-01 18:20:26 -05:00 committed by GitHub
parent 8b6b83bd62
commit 6eff08eb2d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 49 additions and 26 deletions

View File

@ -221,6 +221,10 @@ Topic to turn the PTZ autotracker for a camera on and off. Expected values are `
Topic with current state of the PTZ autotracker for a camera. Published values are `ON` and `OFF`.
### `frigate/<camera_name>/ptz_autotracker/active`
Topic to determine if PTZ autotracker is actively tracking an object. Published values are `ON` and `OFF`.
### `frigate/<camera_name>/birdseye/set`
Topic to turn Birdseye for a camera on and off. Expected values are `ON` and `OFF`. Birdseye mode

View File

@ -191,7 +191,8 @@ class FrigateApp:
"i",
self.config.cameras[camera_name].onvif.autotracking.enabled,
),
"ptz_stopped": mp.Event(),
"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
@ -212,7 +213,7 @@ class FrigateApp:
# issue https://github.com/python/typeshed/issues/8799
# from mypy 0.981 onwards
}
self.ptz_metrics[camera_name]["ptz_stopped"].set()
self.ptz_metrics[camera_name]["ptz_motor_stopped"].set()
self.feature_metrics[camera_name] = {
"audio_enabled": mp.Value( # type: ignore[typeddict-item]
# issue https://github.com/python/typeshed/issues/8799
@ -444,6 +445,7 @@ class FrigateApp:
self.config,
self.onvif_controller,
self.ptz_metrics,
self.dispatcher,
self.stop_event,
)
self.ptz_autotracker_thread.start()

View File

@ -18,6 +18,7 @@ from norfair.camera_motion import (
TranslationTransformationGetter,
)
from frigate.comms.dispatcher import Dispatcher
from frigate.config import CameraConfig, FrigateConfig, ZoomingModeEnum
from frigate.const import (
AUTOTRACKING_MAX_AREA_RATIO,
@ -144,11 +145,12 @@ class PtzAutoTrackerThread(threading.Thread):
config: FrigateConfig,
onvif: OnvifController,
ptz_metrics: dict[str, PTZMetricsTypes],
dispatcher: Dispatcher,
stop_event: MpEvent,
) -> None:
threading.Thread.__init__(self)
self.name = "ptz_autotracker"
self.ptz_autotracker = PtzAutoTracker(config, onvif, ptz_metrics)
self.ptz_autotracker = PtzAutoTracker(config, onvif, ptz_metrics, dispatcher)
self.stop_event = stop_event
self.config = config
@ -175,10 +177,12 @@ class PtzAutoTracker:
config: FrigateConfig,
onvif: OnvifController,
ptz_metrics: PTZMetricsTypes,
dispatcher: Dispatcher,
) -> None:
self.config = config
self.onvif = onvif
self.ptz_metrics = ptz_metrics
self.dispatcher = dispatcher
self.tracked_object: dict[str, object] = {}
self.tracked_object_history: dict[str, object] = {}
self.tracked_object_metrics: dict[str, object] = {}
@ -294,6 +298,8 @@ class PtzAutoTracker:
if camera_config.onvif.autotracking.calibrate_on_startup:
self._calibrate_camera(camera)
self.ptz_metrics[camera]["ptz_tracking_active"].clear()
self.dispatcher.publish(f"{camera}/ptz_autotracker/active", "OFF", retain=False)
self.autotracker_init[camera] = True
def _write_config(self, camera):
@ -338,7 +344,7 @@ class PtzAutoTracker:
1,
)
while not self.ptz_metrics[camera]["ptz_stopped"].is_set():
while not self.ptz_metrics[camera]["ptz_motor_stopped"].is_set():
self.onvif.get_camera_status(camera)
zoom_out_values.append(self.ptz_metrics[camera]["ptz_zoom_level"].value)
@ -349,7 +355,7 @@ class PtzAutoTracker:
1,
)
while not self.ptz_metrics[camera]["ptz_stopped"].is_set():
while not self.ptz_metrics[camera]["ptz_motor_stopped"].is_set():
self.onvif.get_camera_status(camera)
zoom_in_values.append(self.ptz_metrics[camera]["ptz_zoom_level"].value)
@ -367,7 +373,7 @@ class PtzAutoTracker:
1,
)
while not self.ptz_metrics[camera]["ptz_stopped"].is_set():
while not self.ptz_metrics[camera]["ptz_motor_stopped"].is_set():
self.onvif.get_camera_status(camera)
zoom_out_values.append(
@ -383,7 +389,7 @@ class PtzAutoTracker:
1,
)
while not self.ptz_metrics[camera]["ptz_stopped"].is_set():
while not self.ptz_metrics[camera]["ptz_motor_stopped"].is_set():
self.onvif.get_camera_status(camera)
zoom_in_values.append(
@ -406,10 +412,10 @@ class PtzAutoTracker:
self.config.cameras[camera].onvif.autotracking.return_preset.lower(),
)
self.ptz_metrics[camera]["ptz_reset"].set()
self.ptz_metrics[camera]["ptz_stopped"].clear()
self.ptz_metrics[camera]["ptz_motor_stopped"].clear()
# Wait until the camera finishes moving
while not self.ptz_metrics[camera]["ptz_stopped"].is_set():
while not self.ptz_metrics[camera]["ptz_motor_stopped"].is_set():
self.onvif.get_camera_status(camera)
for step in range(num_steps):
@ -420,7 +426,7 @@ class PtzAutoTracker:
self.onvif._move_relative(camera, pan, tilt, 0, 1)
# Wait until the camera finishes moving
while not self.ptz_metrics[camera]["ptz_stopped"].is_set():
while not self.ptz_metrics[camera]["ptz_motor_stopped"].is_set():
self.onvif.get_camera_status(camera)
stop_time = time.time()
@ -438,10 +444,10 @@ class PtzAutoTracker:
self.config.cameras[camera].onvif.autotracking.return_preset.lower(),
)
self.ptz_metrics[camera]["ptz_reset"].set()
self.ptz_metrics[camera]["ptz_stopped"].clear()
self.ptz_metrics[camera]["ptz_motor_stopped"].clear()
# Wait until the camera finishes moving
while not self.ptz_metrics[camera]["ptz_stopped"].is_set():
while not self.ptz_metrics[camera]["ptz_motor_stopped"].is_set():
self.onvif.get_camera_status(camera)
logger.info(
@ -606,7 +612,9 @@ class PtzAutoTracker:
self.onvif._move_relative(camera, pan, tilt, 0, 1)
# Wait until the camera finishes moving
while not self.ptz_metrics[camera]["ptz_stopped"].is_set():
while not self.ptz_metrics[camera][
"ptz_motor_stopped"
].is_set():
self.onvif.get_camera_status(camera)
if (
@ -616,7 +624,7 @@ class PtzAutoTracker:
self.onvif._zoom_absolute(camera, zoom, 1)
# Wait until the camera finishes moving
while not self.ptz_metrics[camera]["ptz_stopped"].is_set():
while not self.ptz_metrics[camera]["ptz_motor_stopped"].is_set():
self.onvif.get_camera_status(camera)
if self.config.cameras[camera].onvif.autotracking.movement_weights:
@ -1118,6 +1126,10 @@ class PtzAutoTracker:
logger.debug(
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.dispatcher.publish(
f"{camera}/ptz_autotracker/active", "ON", retain=False
)
self.tracked_object[camera] = obj
self.tracked_object_history[camera].append(copy.deepcopy(obj.obj_data))
@ -1220,7 +1232,7 @@ class PtzAutoTracker:
if not self.autotracker_init[camera]:
self._autotracker_setup(self.config.cameras[camera], camera)
# regularly update camera status
if not self.ptz_metrics[camera]["ptz_stopped"].is_set():
if not self.ptz_metrics[camera]["ptz_motor_stopped"].is_set():
self.onvif.get_camera_status(camera)
# return to preset if tracking is over
@ -1243,7 +1255,7 @@ class PtzAutoTracker:
while not self.move_queues[camera].empty():
self.move_queues[camera].get()
self.ptz_metrics[camera]["ptz_stopped"].wait()
self.ptz_metrics[camera]["ptz_motor_stopped"].wait()
logger.debug(
f"{camera}: Time is {self.ptz_metrics[camera]['ptz_frame_time'].value}, returning to preset: {autotracker_config.return_preset}"
)
@ -1253,7 +1265,11 @@ class PtzAutoTracker:
)
# update stored zoom level from preset
if not self.ptz_metrics[camera]["ptz_stopped"].is_set():
if not self.ptz_metrics[camera]["ptz_motor_stopped"].is_set():
self.onvif.get_camera_status(camera)
self.ptz_metrics[camera]["ptz_tracking_active"].clear()
self.dispatcher.publish(
f"{camera}/ptz_autotracker/active", "OFF", retain=False
)
self.ptz_metrics[camera]["ptz_reset"].set()

View File

@ -299,7 +299,7 @@ class OnvifController:
return
self.cams[camera_name]["active"] = True
self.ptz_metrics[camera_name]["ptz_stopped"].clear()
self.ptz_metrics[camera_name]["ptz_motor_stopped"].clear()
logger.debug(
f"{camera_name}: PTZ start time: {self.ptz_metrics[camera_name]['ptz_frame_time'].value}"
)
@ -366,7 +366,7 @@ class OnvifController:
return
self.cams[camera_name]["active"] = True
self.ptz_metrics[camera_name]["ptz_stopped"].clear()
self.ptz_metrics[camera_name]["ptz_motor_stopped"].clear()
self.ptz_metrics[camera_name]["ptz_start_time"].value = 0
self.ptz_metrics[camera_name]["ptz_stop_time"].value = 0
move_request = self.cams[camera_name]["move_request"]
@ -413,7 +413,7 @@ class OnvifController:
return
self.cams[camera_name]["active"] = True
self.ptz_metrics[camera_name]["ptz_stopped"].clear()
self.ptz_metrics[camera_name]["ptz_motor_stopped"].clear()
logger.debug(
f"{camera_name}: PTZ start time: {self.ptz_metrics[camera_name]['ptz_frame_time'].value}"
)
@ -543,8 +543,8 @@ class OnvifController:
zoom_status is None or zoom_status.lower() == "idle"
):
self.cams[camera_name]["active"] = False
if not self.ptz_metrics[camera_name]["ptz_stopped"].is_set():
self.ptz_metrics[camera_name]["ptz_stopped"].set()
if not self.ptz_metrics[camera_name]["ptz_motor_stopped"].is_set():
self.ptz_metrics[camera_name]["ptz_motor_stopped"].set()
logger.debug(
f"{camera_name}: PTZ stop time: {self.ptz_metrics[camera_name]['ptz_frame_time'].value}"
@ -555,8 +555,8 @@ class OnvifController:
]["ptz_frame_time"].value
else:
self.cams[camera_name]["active"] = True
if self.ptz_metrics[camera_name]["ptz_stopped"].is_set():
self.ptz_metrics[camera_name]["ptz_stopped"].clear()
if self.ptz_metrics[camera_name]["ptz_motor_stopped"].is_set():
self.ptz_metrics[camera_name]["ptz_motor_stopped"].clear()
logger.debug(
f"{camera_name}: PTZ start time: {self.ptz_metrics[camera_name]['ptz_frame_time'].value}"
@ -586,7 +586,7 @@ class OnvifController:
# some hikvision cams won't update MoveStatus, so warn if it hasn't changed
if (
not self.ptz_metrics[camera_name]["ptz_stopped"].is_set()
not self.ptz_metrics[camera_name]["ptz_motor_stopped"].is_set()
and not self.ptz_metrics[camera_name]["ptz_reset"].is_set()
and self.ptz_metrics[camera_name]["ptz_start_time"].value != 0
and self.ptz_metrics[camera_name]["ptz_frame_time"].value

View File

@ -31,7 +31,8 @@ class CameraMetricsTypes(TypedDict):
class PTZMetricsTypes(TypedDict):
ptz_autotracker_enabled: Synchronized
ptz_stopped: Event
ptz_tracking_active: Event
ptz_motor_stopped: Event
ptz_reset: Event
ptz_start_time: Synchronized
ptz_stop_time: Synchronized