Autotracking tweaks and docs update (#8345)

* refactor thresholds and reduce a duplicate call

* add camera to docs

* udpate docs
This commit is contained in:
Josh Hawkins
2023-10-26 17:21:58 -05:00
committed by GitHub
parent 5a46c36380
commit a399cb09fa
3 changed files with 71 additions and 31 deletions

View File

@@ -502,7 +502,7 @@ class PtzAutoTracker:
return np.dot(self.move_coefficients[camera], input_data)
def _calculate_tracked_object_metrics(self, camera):
def _calculate_tracked_object_metrics(self, camera, obj):
def remove_outliers(data):
Q1 = np.percentile(data, 25)
Q3 = np.percentile(data, 75)
@@ -541,6 +541,27 @@ class PtzAutoTracker:
"original_target_box"
] = self.tracked_object_metrics[camera]["target_box"]
(
self.tracked_object_metrics[camera]["valid_velocity"],
self.tracked_object_metrics[camera]["velocity"],
) = self._get_valid_velocity(camera, obj)
self.tracked_object_metrics[camera]["distance"] = self._get_distance_threshold(
camera, obj
)
centroid_distance = np.linalg.norm(
[
obj.obj_data["centroid"][0] - camera_config.detect.width / 2,
obj.obj_data["centroid"][1] - camera_config.detect.height / 2,
]
)
logger.debug(f"{camera}: Centroid distance: {centroid_distance}")
self.tracked_object_metrics[camera]["below_distance_threshold"] = (
centroid_distance < self.tracked_object_metrics[camera]["distance"]
)
def _process_move_queue(self, camera):
camera_config = self.config.cameras[camera]
camera_config.frame_shape[1]
@@ -668,12 +689,16 @@ class PtzAutoTracker:
velocities = obj.obj_data["estimate_velocity"]
logger.debug(f"{camera}: Velocities from norfair: {velocities}")
# if we are close enough to zero, return right away
if np.all(np.round(velocities) == 0):
return True, np.zeros((2, 2))
# Thresholds
x_mags_thresh = camera_width / camera_fps / 2
y_mags_thresh = camera_height / camera_fps / 2
dir_thresh = 0.96
delta_thresh = 10
var_thresh = 3
dir_thresh = 0.93
delta_thresh = 12
var_thresh = 5
# Check magnitude
x_mags = np.abs(velocities[:, 0])
@@ -690,11 +715,15 @@ class PtzAutoTracker:
high_variances = np.any(stdevs > var_thresh)
# Check direction difference
cosine_sim = np.dot(velocities[0], velocities[1]) / (
np.linalg.norm(velocities[0]) * np.linalg.norm(velocities[1])
)
dir_thresh = 0.6 if np.all(delta < delta_thresh / 2) else dir_thresh
invalid_dirs = cosine_sim < dir_thresh
velocities = np.round(velocities)
invalid_dirs = False
if not np.any(np.linalg.norm(velocities, axis=1)):
cosine_sim = np.dot(velocities[0], velocities[1]) / (
np.linalg.norm(velocities[0]) * np.linalg.norm(velocities[1])
)
dir_thresh = 0.6 if np.all(delta < delta_thresh / 2) else dir_thresh
print(f"cosine sim: {cosine_sim}")
invalid_dirs = cosine_sim < dir_thresh
# Combine
invalid = (
@@ -723,11 +752,12 @@ class PtzAutoTracker:
)
)
# invalid velocity
return np.zeros((2, 2))
return False, np.zeros((2, 2))
else:
return np.mean(velocities, axis=0)
logger.debug(f"{camera}: Valid velocity ")
return True, np.mean(velocities, axis=0)
def _below_distance_threshold(self, camera, obj):
def _get_distance_threshold(self, camera, obj):
# Returns true if Euclidean distance from object to center of frame is
# less than 10% of the of the larger dimension (width or height) of the frame,
# multiplied by a scaling factor for object size.
@@ -738,13 +768,6 @@ class PtzAutoTracker:
# TODO: there's probably a better way to approach this
camera_config = self.config.cameras[camera]
centroid_distance = np.linalg.norm(
[
obj.obj_data["centroid"][0] - camera_config.detect.width / 2,
obj.obj_data["centroid"][1] - camera_config.detect.height / 2,
]
)
obj_width = obj.obj_data["box"][2] - obj.obj_data["box"][0]
obj_height = obj.obj_data["box"][3] - obj.obj_data["box"][1]
@@ -758,14 +781,17 @@ class PtzAutoTracker:
# larger objects should lower the threshold, smaller objects should raise it
scaling_factor = 1 - np.log(max_obj / max_frame)
percentage = 0.1 if camera_config.onvif.autotracking.movement_weights else 0.03
percentage = (
0.08
if camera_config.onvif.autotracking.movement_weights
and self.tracked_object_metrics[camera]["valid_velocity"]
else 0.03
)
distance_threshold = percentage * max_frame * scaling_factor
logger.debug(
f"{camera}: Distance: {centroid_distance}, threshold: {distance_threshold}"
)
logger.debug(f"{camera}: Distance threshold: {distance_threshold}")
return centroid_distance < distance_threshold
return distance_threshold
def _should_zoom_in(self, camera, obj, box, debug_zooming=False):
# returns True if we should zoom in, False if we should zoom out, None to do nothing
@@ -774,7 +800,7 @@ class PtzAutoTracker:
camera_height = camera_config.frame_shape[0]
camera_fps = camera_config.detect.fps
average_velocity = self._get_valid_velocity(camera, obj)
average_velocity = self.tracked_object_metrics[camera]["velocity"]
bb_left, bb_top, bb_right, bb_bottom = box
@@ -799,7 +825,9 @@ class PtzAutoTracker:
)
# make sure object is centered in the frame
below_distance_threshold = self._below_distance_threshold(camera, obj)
below_distance_threshold = self.tracked_object_metrics[camera][
"below_distance_threshold"
]
below_dimension_threshold = (bb_right - bb_left) <= camera_width * (
self.zoom_factor[camera] + 0.1
@@ -925,7 +953,14 @@ class PtzAutoTracker:
): # use estimates if we have available coefficients
predicted_movement_time = self._predict_movement_time(camera, pan, tilt)
average_velocity = self._get_valid_velocity(camera, obj)
_, average_velocity = (
self._get_valid_velocity(camera, obj)
if "velocity" not in self.tracked_object_metrics[camera]
else (
self.tracked_object_metrics[camera]["valid_velocity"],
self.tracked_object_metrics[camera]["velocity"],
)
)
if np.any(average_velocity):
# this box could exceed the frame boundaries if velocity is high
@@ -992,7 +1027,7 @@ class PtzAutoTracker:
level = (
self.ptz_metrics[camera]["ptz_max_zoom"].value
- self.ptz_metrics[camera]["ptz_min_zoom"].value
) / 10
) / 20
if result:
zoom = min(1.0, current_zoom_level + level)
else:
@@ -1103,9 +1138,9 @@ class PtzAutoTracker:
)
):
self.tracked_object_history[camera].append(copy.deepcopy(obj.obj_data))
self._calculate_tracked_object_metrics(camera)
self._calculate_tracked_object_metrics(camera, obj)
if self._below_distance_threshold(camera, obj):
if self.tracked_object_metrics[camera]["below_distance_threshold"]:
logger.debug(
f"{camera}: Existing object (do NOT move ptz): {obj.obj_data['id']} {obj.obj_data['box']} {obj.obj_data['frame_time']}"
)
@@ -1148,7 +1183,7 @@ class PtzAutoTracker:
self.tracked_object_history[camera].append(
copy.deepcopy(obj.obj_data)
)
self._calculate_tracked_object_metrics(camera)
self._calculate_tracked_object_metrics(camera, obj)
self._autotrack_move_ptz(camera, obj)
return