improve motion detection during autotracking

This commit is contained in:
Josh Hawkins 2025-01-25 16:55:45 -06:00
parent befb9fa490
commit 90868bdc77
4 changed files with 46 additions and 5 deletions

View File

@ -5,6 +5,7 @@ import imutils
import numpy as np import numpy as np
from scipy.ndimage import gaussian_filter from scipy.ndimage import gaussian_filter
from frigate.camera import PTZMetrics
from frigate.comms.config_updater import ConfigSubscriber from frigate.comms.config_updater import ConfigSubscriber
from frigate.config import MotionConfig from frigate.config import MotionConfig
from frigate.motion import MotionDetector from frigate.motion import MotionDetector
@ -18,6 +19,7 @@ class ImprovedMotionDetector(MotionDetector):
frame_shape, frame_shape,
config: MotionConfig, config: MotionConfig,
fps: int, fps: int,
ptz_metrics: PTZMetrics = None,
name="improved", name="improved",
blur_radius=1, blur_radius=1,
interpolation=cv2.INTER_NEAREST, interpolation=cv2.INTER_NEAREST,
@ -48,6 +50,8 @@ class ImprovedMotionDetector(MotionDetector):
self.contrast_values[:, 1:2] = 255 self.contrast_values[:, 1:2] = 255
self.contrast_values_index = 0 self.contrast_values_index = 0
self.config_subscriber = ConfigSubscriber(f"config/motion/{name}") self.config_subscriber = ConfigSubscriber(f"config/motion/{name}")
self.ptz_metrics = ptz_metrics
self.last_stop_time = None
def is_calibrating(self): def is_calibrating(self):
return self.calibrating return self.calibrating
@ -64,6 +68,21 @@ class ImprovedMotionDetector(MotionDetector):
if not self.config.enabled: if not self.config.enabled:
return motion_boxes return motion_boxes
# if ptz motor is moving from autotracking, quickly return
# a single box that is 80% of the frame
if (
self.ptz_metrics.autotracker_enabled.value
and not self.ptz_metrics.motor_stopped.is_set()
):
return [
(
int(self.frame_shape[1] * 0.1),
int(self.frame_shape[0] * 0.1),
int(self.frame_shape[1] * 0.9),
int(self.frame_shape[0] * 0.9),
)
]
gray = frame[0 : self.frame_shape[0], 0 : self.frame_shape[1]] gray = frame[0 : self.frame_shape[0], 0 : self.frame_shape[1]]
# resize frame # resize frame
@ -151,6 +170,25 @@ class ImprovedMotionDetector(MotionDetector):
self.motion_frame_size[0] * self.motion_frame_size[1] self.motion_frame_size[0] * self.motion_frame_size[1]
) )
# check if the motor has just stopped from autotracking
# if so, reassign the average to the current frame so we begin with a new baseline
if (
# ensure we only do this for cameras with autotracking enabled
self.ptz_metrics.autotracker_enabled.value
and self.ptz_metrics.motor_stopped.is_set()
and (
self.last_stop_time is None
or self.ptz_metrics.stop_time.value != self.last_stop_time
)
# value is 0 on startup or when motor is moving
and self.ptz_metrics.stop_time.value != 0
):
self.last_stop_time = self.ptz_metrics.stop_time.value
self.avg_frame = resized_frame.astype(np.float32)
motion_boxes = []
pct_motion = 0
# once the motion is less than 5% and the number of contours is < 4, assume its calibrated # once the motion is less than 5% and the number of contours is < 4, assume its calibrated
if pct_motion < 0.05 and len(motion_boxes) <= 4: if pct_motion < 0.05 and len(motion_boxes) <= 4:
self.calibrating = False self.calibrating = False

View File

@ -465,7 +465,6 @@ class OnvifController:
return return
self.cams[camera_name]["active"] = True self.cams[camera_name]["active"] = True
self.ptz_metrics[camera_name].motor_stopped.clear()
self.ptz_metrics[camera_name].start_time.value = 0 self.ptz_metrics[camera_name].start_time.value = 0
self.ptz_metrics[camera_name].stop_time.value = 0 self.ptz_metrics[camera_name].stop_time.value = 0
move_request = self.cams[camera_name]["move_request"] move_request = self.cams[camera_name]["move_request"]

View File

@ -94,7 +94,6 @@ def histogram_distance(matched_not_init_trackers, unmatched_trackers):
distance = 1 - cv2.compareHist( distance = 1 - cv2.compareHist(
snd_embedding, detection_fst.embedding, cv2.HISTCMP_CORREL snd_embedding, detection_fst.embedding, cv2.HISTCMP_CORREL
) )
print("ReID distance", distance)
if distance < 0.5: if distance < 0.5:
return distance return distance
return 1 return 1
@ -220,7 +219,6 @@ class NorfairTracker(ObjectTracker):
) )
is None is None
): ):
print("adding reid keys for ptz: ", obj_type)
reid_keys = [ reid_keys = [
"past_detections_length", "past_detections_length",
"reid_distance_function", "reid_distance_function",
@ -604,6 +602,8 @@ class NorfairTracker(ObjectTracker):
# Collect all tracked objects from each tracker # Collect all tracked objects from each tracker
all_tracked_objects = [] all_tracked_objects = []
# print a table to the console with norfair tracked object info
if False:
self.print_objects_as_table(self.trackers["person"]["ptz"].tracked_objects) self.print_objects_as_table(self.trackers["person"]["ptz"].tracked_objects)
# Get tracked objects from type-specific trackers # Get tracked objects from type-specific trackers

View File

@ -436,7 +436,11 @@ def track_camera(
object_filters = config.objects.filters object_filters = config.objects.filters
motion_detector = ImprovedMotionDetector( motion_detector = ImprovedMotionDetector(
frame_shape, config.motion, config.detect.fps, name=config.name frame_shape,
config.motion,
config.detect.fps,
name=config.name,
ptz_metrics=ptz_metrics,
) )
object_detector = RemoteObjectDetector( object_detector = RemoteObjectDetector(
name, labelmap, detection_queue, result_connection, model_config, stop_event name, labelmap, detection_queue, result_connection, model_config, stop_event