Support zone and mask reset

This commit is contained in:
Nicolas Mowen 2025-05-22 14:20:15 -06:00
parent b3ee79e672
commit 8cf418cf1e
6 changed files with 50 additions and 10 deletions

View File

@ -394,9 +394,8 @@ def config_set(request: Request, body: AppConfigSetBody):
if body.update_topic and body.update_topic.startswith("config/cameras/"):
_, _, camera, field = body.update_topic.split("/")
settings = config.model_dump(
mode="json", warnings="none", exclude_none=True
)["cameras"][camera][field]
settings = config.get_nested_object(body.update_topic)
request.app.config_publisher.publish_update(
CameraConfigUpdateTopic(CameraConfigUpdateEnum[field], camera),
settings,

View File

@ -1,5 +1,29 @@
from typing import Any
from pydantic import BaseModel, ConfigDict
class FrigateBaseModel(BaseModel):
model_config = ConfigDict(extra="forbid", protected_namespaces=())
def get_nested_object(self, path: str) -> Any:
parts = path.split("/")
obj = self
for part in parts:
if part == "config":
continue
if isinstance(obj, BaseModel):
try:
obj = getattr(obj, part)
except AttributeError:
return None
elif isinstance(obj, dict):
try:
obj = obj[part]
except KeyError:
return None
else:
return None
return obj

View File

@ -1,6 +1,8 @@
from abc import ABC, abstractmethod
from typing import Tuple
from numpy import ndarray
from frigate.config import MotionConfig
@ -18,13 +20,21 @@ class MotionDetector(ABC):
pass
@abstractmethod
def detect(self, frame):
def detect(self, frame: ndarray) -> list:
"""Detect motion and return motion boxes."""
pass
@abstractmethod
def is_calibrating(self):
"""Return if motion is recalibrating."""
pass
@abstractmethod
def update_mask(self) -> None:
"""Update the motion mask after a config change."""
pass
@abstractmethod
def stop(self):
"""Stop any ongoing work and processes."""
pass

View File

@ -35,12 +35,7 @@ class ImprovedMotionDetector(MotionDetector):
self.avg_frame = np.zeros(self.motion_frame_size, np.float32)
self.motion_frame_count = 0
self.frame_counter = 0
resized_mask = cv2.resize(
config.mask,
dsize=(self.motion_frame_size[1], self.motion_frame_size[0]),
interpolation=cv2.INTER_AREA,
)
self.mask = np.where(resized_mask == [0])
self.update_mask()
self.save_images = False
self.calibrating = True
self.blur_radius = blur_radius
@ -236,6 +231,14 @@ class ImprovedMotionDetector(MotionDetector):
return motion_boxes
def update_mask(self) -> None:
resized_mask = cv2.resize(
self.config.mask,
dsize=(self.motion_frame_size[1], self.motion_frame_size[0]),
interpolation=cv2.INTER_AREA,
)
self.mask = np.where(resized_mask == [0])
def stop(self) -> None:
"""stop the motion detector."""
pass

View File

@ -650,6 +650,9 @@ def process_frames(
prev_enabled = camera_enabled
camera_enabled = camera_config.enabled
if "motion" in updated_configs:
motion_detector.update_mask()
if (
not camera_enabled
and prev_enabled != camera_enabled

View File

@ -161,6 +161,7 @@ export default function MotionMaskEditPane({
axios
.put(`config/set?${queryString}`, {
requires_restart: 0,
update_topic: `config/cameras/${polygon.camera}/motion`,
})
.then((res) => {
if (res.status === 200) {