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",
|
"i",
|
||||||
self.config.cameras[camera_name].onvif.autotracking.enabled,
|
self.config.cameras[camera_name].onvif.autotracking.enabled,
|
||||||
),
|
),
|
||||||
"ptz_moving": mp.Value("i", 0),
|
"ptz_stopped": mp.Event(),
|
||||||
"motion_threshold": mp.Value(
|
"motion_threshold": mp.Value(
|
||||||
"i", self.config.cameras[camera_name].motion.threshold
|
"i", self.config.cameras[camera_name].motion.threshold
|
||||||
),
|
),
|
||||||
@ -137,6 +137,7 @@ class FrigateApp:
|
|||||||
"capture_process": None,
|
"capture_process": None,
|
||||||
"process": None,
|
"process": None,
|
||||||
}
|
}
|
||||||
|
self.camera_metrics[camera_name]["ptz_stopped"].set()
|
||||||
self.record_metrics[camera_name] = {
|
self.record_metrics[camera_name] = {
|
||||||
"record_enabled": mp.Value(
|
"record_enabled": mp.Value(
|
||||||
"i", self.config.cameras[camera_name].record.enabled
|
"i", self.config.cameras[camera_name].record.enabled
|
||||||
|
|||||||
@ -216,7 +216,7 @@ class OnvifController:
|
|||||||
return
|
return
|
||||||
|
|
||||||
self.cams[camera_name]["active"] = True
|
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"]
|
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"]
|
||||||
|
|
||||||
@ -268,7 +268,7 @@ class OnvifController:
|
|||||||
return
|
return
|
||||||
|
|
||||||
self.cams[camera_name]["active"] = True
|
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"]
|
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]
|
||||||
@ -278,7 +278,7 @@ class OnvifController:
|
|||||||
"PresetToken": preset_token,
|
"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
|
self.cams[camera_name]["active"] = False
|
||||||
|
|
||||||
def _zoom(self, camera_name: str, command: OnvifCommandEnum) -> None:
|
def _zoom(self, camera_name: str, command: OnvifCommandEnum) -> None:
|
||||||
@ -350,10 +350,12 @@ class OnvifController:
|
|||||||
status_request = self.cams[camera_name]["status_request"]
|
status_request = self.cams[camera_name]["status_request"]
|
||||||
status = onvif.get_service("ptz").GetStatus(status_request)
|
status = onvif.get_service("ptz").GetStatus(status_request)
|
||||||
|
|
||||||
self.cams[camera_name]["active"] = status.MoveStatus.PanTilt != "IDLE"
|
if status.MoveStatus.PanTilt == "IDLE" or status.MoveStatus.Zoom == "IDLE":
|
||||||
self.camera_metrics[camera_name]["ptz_moving"].value = (
|
self.cams[camera_name]["active"] = False
|
||||||
status.MoveStatus.PanTilt != "IDLE"
|
self.camera_metrics[camera_name]["ptz_stopped"].set()
|
||||||
)
|
else:
|
||||||
|
self.cams[camera_name]["active"] = True
|
||||||
|
self.camera_metrics[camera_name]["ptz_stopped"].clear()
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"pan": status.Position.PanTilt.x,
|
"pan": status.Position.PanTilt.x,
|
||||||
|
|||||||
@ -21,7 +21,7 @@ logger = logging.getLogger(__name__)
|
|||||||
|
|
||||||
|
|
||||||
class PtzMotionEstimator:
|
class PtzMotionEstimator:
|
||||||
def __init__(self, config: CameraConfig, ptz_moving) -> None:
|
def __init__(self, config: CameraConfig, ptz_stopped) -> None:
|
||||||
self.frame_manager = SharedMemoryFrameManager()
|
self.frame_manager = SharedMemoryFrameManager()
|
||||||
# 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(
|
self.norfair_motion_estimator = MotionEstimator(
|
||||||
@ -31,11 +31,14 @@ class PtzMotionEstimator:
|
|||||||
)
|
)
|
||||||
self.camera_config = config
|
self.camera_config = config
|
||||||
self.coord_transformations = None
|
self.coord_transformations = None
|
||||||
self.ptz_moving = ptz_moving
|
self.ptz_stopped = ptz_stopped
|
||||||
logger.debug(f"Motion estimator init for cam: {config.name}")
|
logger.debug(f"Motion estimator init for cam: {config.name}")
|
||||||
|
|
||||||
def motion_estimator(self, detections, frame_time, camera_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(
|
# logger.debug(
|
||||||
# f"Motion estimator running for {camera_name} - frame time: {frame_time}"
|
# f"Motion estimator running for {camera_name} - frame time: {frame_time}"
|
||||||
# )
|
# )
|
||||||
@ -96,6 +99,11 @@ class PtzAutoTrackerThread(threading.Thread):
|
|||||||
if cam.onvif.autotracking.enabled:
|
if cam.onvif.autotracking.enabled:
|
||||||
self.ptz_autotracker.camera_maintenance(camera_name)
|
self.ptz_autotracker.camera_maintenance(camera_name)
|
||||||
time.sleep(1)
|
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)
|
time.sleep(0.1)
|
||||||
logger.info("Exiting autotracker...")
|
logger.info("Exiting autotracker...")
|
||||||
|
|
||||||
@ -169,6 +177,13 @@ class PtzAutoTracker:
|
|||||||
tilt = 0
|
tilt = 0
|
||||||
|
|
||||||
while not self.move_queues[camera].empty():
|
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()
|
queued_pan, queued_tilt = self.move_queues[camera].get()
|
||||||
logger.debug(
|
logger.debug(
|
||||||
f"queue pan: {queued_pan}, queue tilt: {queued_tilt}"
|
f"queue pan: {queued_pan}, queue tilt: {queued_tilt}"
|
||||||
@ -182,16 +197,15 @@ class PtzAutoTracker:
|
|||||||
|
|
||||||
logger.debug(f"final pan: {pan}, final tilt: {tilt}")
|
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
|
# Wait until the camera finishes moving
|
||||||
while self.camera_metrics[camera]["ptz_moving"].value:
|
self.camera_metrics[camera]["ptz_stopped"].wait()
|
||||||
pass
|
|
||||||
|
|
||||||
except queue.Empty:
|
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)
|
move_data = (pan, tilt)
|
||||||
logger.debug(f"enqueue pan: {pan}, enqueue tilt: {tilt}")
|
logger.debug(f"enqueue pan: {pan}, enqueue tilt: {tilt}")
|
||||||
self.move_queues[camera].put(move_data)
|
self.move_queues[camera].put(move_data)
|
||||||
@ -208,7 +222,7 @@ class PtzAutoTracker:
|
|||||||
tilt = 0.5 - (obj.obj_data["centroid"][1] / camera_height)
|
tilt = 0.5 - (obj.obj_data["centroid"][1] / camera_height)
|
||||||
|
|
||||||
# ideas: check object velocity for camera speed?
|
# 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):
|
def autotrack_object(self, camera, obj):
|
||||||
camera_config = self.config.cameras[camera]
|
camera_config = self.config.cameras[camera]
|
||||||
@ -317,11 +331,10 @@ class PtzAutoTracker:
|
|||||||
# returns camera to preset after timeout when tracking is over
|
# returns camera to preset after timeout when tracking is over
|
||||||
autotracker_config = self.config.cameras[camera].onvif.autotracking
|
autotracker_config = self.config.cameras[camera].onvif.autotracking
|
||||||
|
|
||||||
if autotracker_config.enabled:
|
|
||||||
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 self.camera_metrics[camera]["ptz_moving"].value:
|
if not self.camera_metrics[camera]["ptz_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
|
||||||
@ -335,8 +348,8 @@ class PtzAutoTracker:
|
|||||||
> autotracker_config.timeout
|
> autotracker_config.timeout
|
||||||
)
|
)
|
||||||
and autotracker_config.return_preset
|
and autotracker_config.return_preset
|
||||||
and not self.camera_metrics[camera]["ptz_moving"].value
|
|
||||||
):
|
):
|
||||||
|
self.camera_metrics[camera]["ptz_stopped"].wait()
|
||||||
logger.debug(
|
logger.debug(
|
||||||
f"Autotrack: Time is {time.time()}, returning to preset: {autotracker_config.return_preset}"
|
f"Autotrack: Time is {time.time()}, returning to preset: {autotracker_config.return_preset}"
|
||||||
)
|
)
|
||||||
@ -345,7 +358,3 @@ class PtzAutoTracker:
|
|||||||
autotracker_config.return_preset.lower(),
|
autotracker_config.return_preset.lower(),
|
||||||
)
|
)
|
||||||
self.tracked_object_previous[camera] = None
|
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):
|
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.tracked_objects = {}
|
||||||
self.disappeared = {}
|
self.disappeared = {}
|
||||||
self.positions = {}
|
self.positions = {}
|
||||||
@ -63,7 +63,7 @@ class NorfairTracker(ObjectTracker):
|
|||||||
self.camera_config = config
|
self.camera_config = config
|
||||||
self.detect_config = config.detect
|
self.detect_config = config.detect
|
||||||
self.ptz_autotracker_enabled = ptz_autotracker_enabled.value
|
self.ptz_autotracker_enabled = ptz_autotracker_enabled.value
|
||||||
self.ptz_moving = ptz_moving
|
self.ptz_stopped = ptz_stopped
|
||||||
self.camera_name = config.name
|
self.camera_name = config.name
|
||||||
self.track_id_map = {}
|
self.track_id_map = {}
|
||||||
# TODO: could also initialize a tracker per object class if there
|
# TODO: could also initialize a tracker per object class if there
|
||||||
@ -75,7 +75,7 @@ class NorfairTracker(ObjectTracker):
|
|||||||
hit_counter_max=self.max_disappeared,
|
hit_counter_max=self.max_disappeared,
|
||||||
)
|
)
|
||||||
if self.ptz_autotracker_enabled:
|
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):
|
def register(self, track_id, obj):
|
||||||
rand_id = "".join(random.choices(string.ascii_lowercase + string.digits, k=6))
|
rand_id = "".join(random.choices(string.ascii_lowercase + string.digits, k=6))
|
||||||
|
|||||||
@ -17,7 +17,7 @@ class CameraMetricsTypes(TypedDict):
|
|||||||
motion_enabled: Synchronized
|
motion_enabled: Synchronized
|
||||||
improve_contrast_enabled: Synchronized
|
improve_contrast_enabled: Synchronized
|
||||||
ptz_autotracker_enabled: Synchronized
|
ptz_autotracker_enabled: Synchronized
|
||||||
ptz_moving: Synchronized
|
ptz_stopped: Synchronized
|
||||||
motion_threshold: Synchronized
|
motion_threshold: Synchronized
|
||||||
motion_contour_area: Synchronized
|
motion_contour_area: Synchronized
|
||||||
process: Optional[Process]
|
process: Optional[Process]
|
||||||
|
|||||||
@ -458,7 +458,7 @@ def track_camera(
|
|||||||
motion_enabled = process_info["motion_enabled"]
|
motion_enabled = process_info["motion_enabled"]
|
||||||
improve_contrast_enabled = process_info["improve_contrast_enabled"]
|
improve_contrast_enabled = process_info["improve_contrast_enabled"]
|
||||||
ptz_autotracker_enabled = process_info["ptz_autotracker_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_threshold = process_info["motion_threshold"]
|
||||||
motion_contour_area = process_info["motion_contour_area"]
|
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
|
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()
|
frame_manager = SharedMemoryFrameManager()
|
||||||
|
|
||||||
@ -499,7 +499,7 @@ def track_camera(
|
|||||||
detection_enabled,
|
detection_enabled,
|
||||||
motion_enabled,
|
motion_enabled,
|
||||||
stop_event,
|
stop_event,
|
||||||
ptz_moving,
|
ptz_stopped,
|
||||||
)
|
)
|
||||||
|
|
||||||
logger.info(f"{name}: exiting subprocess")
|
logger.info(f"{name}: exiting subprocess")
|
||||||
@ -724,7 +724,7 @@ def process_frames(
|
|||||||
detection_enabled: mp.Value,
|
detection_enabled: mp.Value,
|
||||||
motion_enabled: mp.Value,
|
motion_enabled: mp.Value,
|
||||||
stop_event,
|
stop_event,
|
||||||
ptz_moving: mp.Value,
|
ptz_stopped: mp.Event,
|
||||||
exit_on_empty: bool = False,
|
exit_on_empty: bool = False,
|
||||||
):
|
):
|
||||||
# attribute labels are not tracked and are not assigned regions
|
# attribute labels are not tracked and are not assigned regions
|
||||||
@ -769,7 +769,7 @@ def process_frames(
|
|||||||
# look for motion if enabled
|
# look for motion if enabled
|
||||||
motion_boxes = (
|
motion_boxes = (
|
||||||
motion_detector.detect(frame)
|
motion_detector.detect(frame)
|
||||||
if motion_enabled.value and not ptz_moving.value
|
if motion_enabled.value and ptz_stopped.is_set()
|
||||||
else []
|
else []
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user