mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-02-05 18:55:23 +03:00
use mp event instead of value for ptz status
This commit is contained in:
parent
8e0d492ad8
commit
b267cfb520
@ -122,7 +122,7 @@ class FrigateApp:
|
||||
"i",
|
||||
self.config.cameras[camera_name].onvif.autotracking.enabled,
|
||||
),
|
||||
"ptz_moving": mp.Value("i", 0),
|
||||
"ptz_stopped": mp.Event(),
|
||||
"motion_threshold": mp.Value(
|
||||
"i", self.config.cameras[camera_name].motion.threshold
|
||||
),
|
||||
@ -137,6 +137,7 @@ class FrigateApp:
|
||||
"capture_process": None,
|
||||
"process": None,
|
||||
}
|
||||
self.camera_metrics[camera_name]["ptz_stopped"].set()
|
||||
self.record_metrics[camera_name] = {
|
||||
"record_enabled": mp.Value(
|
||||
"i", self.config.cameras[camera_name].record.enabled
|
||||
|
||||
@ -216,7 +216,7 @@ class OnvifController:
|
||||
return
|
||||
|
||||
self.cams[camera_name]["active"] = True
|
||||
self.camera_metrics[camera_name]["ptz_moving"].value = True
|
||||
self.camera_metrics[camera_name]["ptz_stopped"].clear()
|
||||
onvif: ONVIFCamera = self.cams[camera_name]["onvif"]
|
||||
move_request = self.cams[camera_name]["relative_move_request"]
|
||||
|
||||
@ -268,7 +268,7 @@ class OnvifController:
|
||||
return
|
||||
|
||||
self.cams[camera_name]["active"] = True
|
||||
self.camera_metrics[camera_name]["ptz_moving"].value = True
|
||||
self.camera_metrics[camera_name]["ptz_stopped"].clear()
|
||||
move_request = self.cams[camera_name]["move_request"]
|
||||
onvif: ONVIFCamera = self.cams[camera_name]["onvif"]
|
||||
preset_token = self.cams[camera_name]["presets"][preset]
|
||||
@ -278,7 +278,7 @@ class OnvifController:
|
||||
"PresetToken": preset_token,
|
||||
}
|
||||
)
|
||||
self.camera_metrics[camera_name]["ptz_moving"].value = False
|
||||
self.camera_metrics[camera_name]["ptz_stopped"].set()
|
||||
self.cams[camera_name]["active"] = False
|
||||
|
||||
def _zoom(self, camera_name: str, command: OnvifCommandEnum) -> None:
|
||||
@ -350,10 +350,12 @@ class OnvifController:
|
||||
status_request = self.cams[camera_name]["status_request"]
|
||||
status = onvif.get_service("ptz").GetStatus(status_request)
|
||||
|
||||
self.cams[camera_name]["active"] = status.MoveStatus.PanTilt != "IDLE"
|
||||
self.camera_metrics[camera_name]["ptz_moving"].value = (
|
||||
status.MoveStatus.PanTilt != "IDLE"
|
||||
)
|
||||
if status.MoveStatus.PanTilt == "IDLE" or status.MoveStatus.Zoom == "IDLE":
|
||||
self.cams[camera_name]["active"] = False
|
||||
self.camera_metrics[camera_name]["ptz_stopped"].set()
|
||||
else:
|
||||
self.cams[camera_name]["active"] = True
|
||||
self.camera_metrics[camera_name]["ptz_stopped"].clear()
|
||||
|
||||
return {
|
||||
"pan": status.Position.PanTilt.x,
|
||||
|
||||
@ -21,7 +21,7 @@ logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class PtzMotionEstimator:
|
||||
def __init__(self, config: CameraConfig, ptz_moving) -> None:
|
||||
def __init__(self, config: CameraConfig, ptz_stopped) -> None:
|
||||
self.frame_manager = SharedMemoryFrameManager()
|
||||
# homography is nice (zooming) but slow, translation is pan/tilt only but fast.
|
||||
self.norfair_motion_estimator = MotionEstimator(
|
||||
@ -31,11 +31,14 @@ class PtzMotionEstimator:
|
||||
)
|
||||
self.camera_config = config
|
||||
self.coord_transformations = None
|
||||
self.ptz_moving = ptz_moving
|
||||
self.ptz_stopped = ptz_stopped
|
||||
logger.debug(f"Motion estimator init for cam: {config.name}")
|
||||
|
||||
def motion_estimator(self, detections, frame_time, camera_name):
|
||||
if self.camera_config.onvif.autotracking.enabled and self.ptz_moving.value:
|
||||
if (
|
||||
self.camera_config.onvif.autotracking.enabled
|
||||
and not self.ptz_stopped.is_set()
|
||||
):
|
||||
# logger.debug(
|
||||
# f"Motion estimator running for {camera_name} - frame time: {frame_time}"
|
||||
# )
|
||||
@ -96,6 +99,11 @@ class PtzAutoTrackerThread(threading.Thread):
|
||||
if cam.onvif.autotracking.enabled:
|
||||
self.ptz_autotracker.camera_maintenance(camera_name)
|
||||
time.sleep(1)
|
||||
else:
|
||||
# disabled dynamically by mqtt
|
||||
if self.ptz_autotracker.tracked_object.get(camera_name):
|
||||
self.ptz_autotracker.tracked_object[camera_name] = None
|
||||
self.ptz_autotracker.tracked_object_previous[camera_name] = None
|
||||
time.sleep(0.1)
|
||||
logger.info("Exiting autotracker...")
|
||||
|
||||
@ -169,6 +177,13 @@ class PtzAutoTracker:
|
||||
tilt = 0
|
||||
|
||||
while not self.move_queues[camera].empty():
|
||||
queued_pan, queued_tilt = self.move_queues[camera].queue[0]
|
||||
|
||||
# If exceeding the movement range, keep it in the queue and move now
|
||||
if abs(pan + queued_pan) > 1.0 or abs(tilt + queued_tilt) > 1.0:
|
||||
logger.debug("Pan or tilt value exceeds 1.0")
|
||||
break
|
||||
|
||||
queued_pan, queued_tilt = self.move_queues[camera].get()
|
||||
logger.debug(
|
||||
f"queue pan: {queued_pan}, queue tilt: {queued_tilt}"
|
||||
@ -182,16 +197,15 @@ class PtzAutoTracker:
|
||||
|
||||
logger.debug(f"final pan: {pan}, final tilt: {tilt}")
|
||||
|
||||
self.onvif._move_relative(camera, pan, tilt, 0.1)
|
||||
self.onvif._move_relative(camera, pan, tilt, 1)
|
||||
|
||||
# Wait until the camera finishes moving
|
||||
while self.camera_metrics[camera]["ptz_moving"].value:
|
||||
pass
|
||||
self.camera_metrics[camera]["ptz_stopped"].wait()
|
||||
|
||||
except queue.Empty:
|
||||
pass
|
||||
time.sleep(0.1)
|
||||
|
||||
def enqueue_move(self, camera, pan, tilt):
|
||||
def _enqueue_move(self, camera, pan, tilt):
|
||||
move_data = (pan, tilt)
|
||||
logger.debug(f"enqueue pan: {pan}, enqueue tilt: {tilt}")
|
||||
self.move_queues[camera].put(move_data)
|
||||
@ -208,7 +222,7 @@ class PtzAutoTracker:
|
||||
tilt = 0.5 - (obj.obj_data["centroid"][1] / camera_height)
|
||||
|
||||
# ideas: check object velocity for camera speed?
|
||||
self.enqueue_move(camera, -pan, tilt)
|
||||
self._enqueue_move(camera, -pan, tilt)
|
||||
|
||||
def autotrack_object(self, camera, obj):
|
||||
camera_config = self.config.cameras[camera]
|
||||
@ -317,11 +331,10 @@ class PtzAutoTracker:
|
||||
# returns camera to preset after timeout when tracking is over
|
||||
autotracker_config = self.config.cameras[camera].onvif.autotracking
|
||||
|
||||
if autotracker_config.enabled:
|
||||
if not self.autotracker_init[camera]:
|
||||
self._autotracker_setup(self.config.cameras[camera], camera)
|
||||
# regularly update camera status
|
||||
if self.camera_metrics[camera]["ptz_moving"].value:
|
||||
if not self.camera_metrics[camera]["ptz_stopped"].is_set():
|
||||
self.onvif.get_camera_status(camera)
|
||||
|
||||
# return to preset if tracking is over
|
||||
@ -335,8 +348,8 @@ class PtzAutoTracker:
|
||||
> autotracker_config.timeout
|
||||
)
|
||||
and autotracker_config.return_preset
|
||||
and not self.camera_metrics[camera]["ptz_moving"].value
|
||||
):
|
||||
self.camera_metrics[camera]["ptz_stopped"].wait()
|
||||
logger.debug(
|
||||
f"Autotrack: Time is {time.time()}, returning to preset: {autotracker_config.return_preset}"
|
||||
)
|
||||
@ -345,7 +358,3 @@ class PtzAutoTracker:
|
||||
autotracker_config.return_preset.lower(),
|
||||
)
|
||||
self.tracked_object_previous[camera] = None
|
||||
|
||||
def disable_autotracking(self, camera):
|
||||
# need to call this if autotracking is disabled by mqtt??
|
||||
self.tracked_object[camera] = None
|
||||
|
||||
@ -55,7 +55,7 @@ def frigate_distance(detection: Detection, tracked_object) -> float:
|
||||
|
||||
|
||||
class NorfairTracker(ObjectTracker):
|
||||
def __init__(self, config: CameraConfig, ptz_autotracker_enabled, ptz_moving):
|
||||
def __init__(self, config: CameraConfig, ptz_autotracker_enabled, ptz_stopped):
|
||||
self.tracked_objects = {}
|
||||
self.disappeared = {}
|
||||
self.positions = {}
|
||||
@ -63,7 +63,7 @@ class NorfairTracker(ObjectTracker):
|
||||
self.camera_config = config
|
||||
self.detect_config = config.detect
|
||||
self.ptz_autotracker_enabled = ptz_autotracker_enabled.value
|
||||
self.ptz_moving = ptz_moving
|
||||
self.ptz_stopped = ptz_stopped
|
||||
self.camera_name = config.name
|
||||
self.track_id_map = {}
|
||||
# TODO: could also initialize a tracker per object class if there
|
||||
@ -75,7 +75,7 @@ class NorfairTracker(ObjectTracker):
|
||||
hit_counter_max=self.max_disappeared,
|
||||
)
|
||||
if self.ptz_autotracker_enabled:
|
||||
self.ptz_motion_estimator = PtzMotionEstimator(config, self.ptz_moving)
|
||||
self.ptz_motion_estimator = PtzMotionEstimator(config, self.ptz_stopped)
|
||||
|
||||
def register(self, track_id, obj):
|
||||
rand_id = "".join(random.choices(string.ascii_lowercase + string.digits, k=6))
|
||||
|
||||
@ -17,7 +17,7 @@ class CameraMetricsTypes(TypedDict):
|
||||
motion_enabled: Synchronized
|
||||
improve_contrast_enabled: Synchronized
|
||||
ptz_autotracker_enabled: Synchronized
|
||||
ptz_moving: Synchronized
|
||||
ptz_stopped: Synchronized
|
||||
motion_threshold: Synchronized
|
||||
motion_contour_area: Synchronized
|
||||
process: Optional[Process]
|
||||
|
||||
@ -458,7 +458,7 @@ def track_camera(
|
||||
motion_enabled = process_info["motion_enabled"]
|
||||
improve_contrast_enabled = process_info["improve_contrast_enabled"]
|
||||
ptz_autotracker_enabled = process_info["ptz_autotracker_enabled"]
|
||||
ptz_moving = process_info["ptz_moving"]
|
||||
ptz_stopped = process_info["ptz_stopped"]
|
||||
motion_threshold = process_info["motion_threshold"]
|
||||
motion_contour_area = process_info["motion_contour_area"]
|
||||
|
||||
@ -478,7 +478,7 @@ def track_camera(
|
||||
name, labelmap, detection_queue, result_connection, model_config, stop_event
|
||||
)
|
||||
|
||||
object_tracker = NorfairTracker(config, ptz_autotracker_enabled, ptz_moving)
|
||||
object_tracker = NorfairTracker(config, ptz_autotracker_enabled, ptz_stopped)
|
||||
|
||||
frame_manager = SharedMemoryFrameManager()
|
||||
|
||||
@ -499,7 +499,7 @@ def track_camera(
|
||||
detection_enabled,
|
||||
motion_enabled,
|
||||
stop_event,
|
||||
ptz_moving,
|
||||
ptz_stopped,
|
||||
)
|
||||
|
||||
logger.info(f"{name}: exiting subprocess")
|
||||
@ -724,7 +724,7 @@ def process_frames(
|
||||
detection_enabled: mp.Value,
|
||||
motion_enabled: mp.Value,
|
||||
stop_event,
|
||||
ptz_moving: mp.Value,
|
||||
ptz_stopped: mp.Event,
|
||||
exit_on_empty: bool = False,
|
||||
):
|
||||
# attribute labels are not tracked and are not assigned regions
|
||||
@ -769,7 +769,7 @@ def process_frames(
|
||||
# look for motion if enabled
|
||||
motion_boxes = (
|
||||
motion_detector.detect(frame)
|
||||
if motion_enabled.value and not ptz_moving.value
|
||||
if motion_enabled.value and ptz_stopped.is_set()
|
||||
else []
|
||||
)
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user