mirror of
https://github.com/blakeblackshear/frigate.git
synced 2025-02-25 18:55:25 -06:00
format
This commit is contained in:
parent
593f7d05d6
commit
fea64fa93a
@ -63,9 +63,7 @@ class CameraConfig(FrigateBaseModel):
|
||||
motion: Optional[MotionConfig] = Field(
|
||||
None, title="Motion detection configuration."
|
||||
)
|
||||
motion_paths: Optional[MotionPathConfig] = Field(
|
||||
None, title="Enable motion paths."
|
||||
)
|
||||
motion_paths: Optional[MotionPathConfig] = Field(None, title="Enable motion paths.")
|
||||
objects: ObjectConfig = Field(
|
||||
default_factory=ObjectConfig, title="Object configuration."
|
||||
)
|
||||
|
@ -26,10 +26,10 @@ class MotionPathConfig(FrigateBaseModel):
|
||||
def serialize_raw_mask(self, value: Any, info):
|
||||
return None
|
||||
|
||||
@validator('max_history')
|
||||
@validator("max_history")
|
||||
def max_history_range(cls, v):
|
||||
if v < 2:
|
||||
raise ValueError('max_history must be >= 2')
|
||||
raise ValueError("max_history must be >= 2")
|
||||
if v > 100:
|
||||
raise ValueError('max_history must be <= 100')
|
||||
raise ValueError("max_history must be <= 100")
|
||||
return v
|
||||
|
@ -3,6 +3,7 @@ import numpy as np
|
||||
from typing import Dict, List, Tuple
|
||||
from filterpy.kalman import KalmanFilter
|
||||
|
||||
|
||||
class PathVisualizer:
|
||||
def __init__(self, history_length: int = 30, prediction_length: int = 15):
|
||||
self.history_length = history_length
|
||||
@ -12,21 +13,22 @@ class PathVisualizer:
|
||||
|
||||
def _init_kalman(self, object_id: str, initial_pos: Tuple[int, int]):
|
||||
"""Initialize Kalman filter for new object with position and velocity state"""
|
||||
kf = KalmanFilter(dim_x=4, dim_z=2) # State: [x, y, vx, vy], Measurement: [x, y]
|
||||
kf = KalmanFilter(
|
||||
dim_x=4, dim_z=2
|
||||
) # State: [x, y, vx, vy], Measurement: [x, y]
|
||||
|
||||
# State transition matrix
|
||||
kf.F = np.array([
|
||||
kf.F = np.array(
|
||||
[
|
||||
[1, 0, 1, 0], # x = x + vx
|
||||
[0, 1, 0, 1], # y = y + vy
|
||||
[0, 0, 1, 0], # vx = vx
|
||||
[0, 0, 0, 1], # vy = vy
|
||||
])
|
||||
]
|
||||
)
|
||||
|
||||
# Measurement matrix
|
||||
kf.H = np.array([
|
||||
[1, 0, 0, 0],
|
||||
[0, 1, 0, 0]
|
||||
])
|
||||
kf.H = np.array([[1, 0, 0, 0], [0, 1, 0, 0]])
|
||||
|
||||
# Measurement noise
|
||||
kf.R = np.eye(2) * 5
|
||||
@ -60,9 +62,13 @@ class PathVisualizer:
|
||||
|
||||
# Trim history
|
||||
if len(self.position_history[object_id]) > self.history_length:
|
||||
self.position_history[object_id] = self.position_history[object_id][-self.history_length:]
|
||||
self.position_history[object_id] = self.position_history[object_id][
|
||||
-self.history_length :
|
||||
]
|
||||
|
||||
def predict_path(self, object_id: str, frame_shape: Tuple[int, int]) -> List[Tuple[int, int]]:
|
||||
def predict_path(
|
||||
self, object_id: str, frame_shape: Tuple[int, int]
|
||||
) -> List[Tuple[int, int]]:
|
||||
"""Predict future path using Kalman filter"""
|
||||
if object_id not in self.kalman_filters:
|
||||
return []
|
||||
@ -108,7 +114,7 @@ class PathVisualizer:
|
||||
color = (
|
||||
int(255 * (1 - alpha)), # Blue
|
||||
int(255 * alpha), # Green
|
||||
0 # Red
|
||||
0, # Red
|
||||
)
|
||||
|
||||
start_pos = positions[i - 1]
|
||||
|
@ -236,7 +236,8 @@ class CameraState:
|
||||
if draw_options.get("motion_paths"):
|
||||
# Update and draw paths for non-stationary objects
|
||||
active_objects = [
|
||||
obj_id for obj_id, obj in tracked_objects.items()
|
||||
obj_id
|
||||
for obj_id, obj in tracked_objects.items()
|
||||
if not obj["stationary"] and obj["frame_time"] == frame_time
|
||||
]
|
||||
|
||||
@ -245,7 +246,7 @@ class CameraState:
|
||||
obj = tracked_objects[obj_id]
|
||||
centroid = (
|
||||
int((obj["box"][0] + obj["box"][2]) / 2), # x center
|
||||
int((obj["box"][1] + obj["box"][3]) / 2) # y center
|
||||
int((obj["box"][1] + obj["box"][3]) / 2), # y center
|
||||
)
|
||||
self.path_visualizer.update_position(obj_id, centroid)
|
||||
|
||||
@ -445,7 +446,9 @@ class CameraState:
|
||||
|
||||
def update_paths(self, id: str, obj: TrackedObject):
|
||||
"""Store motion path data globally if movement exceeds motion threshold."""
|
||||
motion_paths_config = self.camera_config.motion_paths or self.config.motion_paths
|
||||
motion_paths_config = (
|
||||
self.camera_config.motion_paths or self.config.motion_paths
|
||||
)
|
||||
if motion_paths_config is None:
|
||||
return
|
||||
|
||||
@ -455,16 +458,15 @@ class CameraState:
|
||||
current_box = obj.obj_data["box"]
|
||||
current_centroid = (
|
||||
int((current_box[0] + current_box[2]) / 2),
|
||||
int((current_box[1] + current_box[3]) / 2)
|
||||
int((current_box[1] + current_box[3]) / 2),
|
||||
)
|
||||
|
||||
history = self.path_history[self.name][id]
|
||||
if history and len(history) > 0:
|
||||
prev_pos = history[-1]
|
||||
# Calculate motion delta
|
||||
delta = (
|
||||
abs(current_centroid[0] - prev_pos[0]) +
|
||||
abs(current_centroid[1] - prev_pos[1])
|
||||
delta = abs(current_centroid[0] - prev_pos[0]) + abs(
|
||||
current_centroid[1] - prev_pos[1]
|
||||
)
|
||||
if delta > motion_threshold:
|
||||
history.append(current_centroid)
|
||||
|
@ -395,7 +395,13 @@ class TrackedObject:
|
||||
return None
|
||||
|
||||
def get_jpg_bytes(
|
||||
self, timestamp=False, bounding_box=False, motion_paths=False, crop=False, height=None, quality=70
|
||||
self,
|
||||
timestamp=False,
|
||||
bounding_box=False,
|
||||
motion_paths=False,
|
||||
crop=False,
|
||||
height=None,
|
||||
quality=70,
|
||||
):
|
||||
if self.thumbnail_data is None:
|
||||
return None
|
||||
@ -462,7 +468,7 @@ class TrackedObject:
|
||||
color = (
|
||||
int(255 * (1 - alpha)), # Blue
|
||||
int(255 * alpha), # Green
|
||||
0 # Red
|
||||
0, # Red
|
||||
)
|
||||
cv2.line(best_frame, start_pos, end_pos, color, 2, cv2.LINE_AA)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user