mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-02-09 04:35:25 +03:00
remove motion and detection camera metrics
This commit is contained in:
parent
d17c8baf97
commit
493d726081
@ -129,35 +129,6 @@ class FrigateApp:
|
|||||||
# issue https://github.com/python/typeshed/issues/8799
|
# issue https://github.com/python/typeshed/issues/8799
|
||||||
# from mypy 0.981 onwards
|
# from mypy 0.981 onwards
|
||||||
"process_fps": mp.Value("d", 0.0), # type: ignore[typeddict-item]
|
"process_fps": mp.Value("d", 0.0), # type: ignore[typeddict-item]
|
||||||
# issue https://github.com/python/typeshed/issues/8799
|
|
||||||
# from mypy 0.981 onwards
|
|
||||||
"detection_enabled": mp.Value( # type: ignore[typeddict-item]
|
|
||||||
# issue https://github.com/python/typeshed/issues/8799
|
|
||||||
# from mypy 0.981 onwards
|
|
||||||
"i",
|
|
||||||
self.config.cameras[camera_name].detect.enabled,
|
|
||||||
),
|
|
||||||
"motion_enabled": mp.Value("i", True), # type: ignore[typeddict-item]
|
|
||||||
# issue https://github.com/python/typeshed/issues/8799
|
|
||||||
# from mypy 0.981 onwards
|
|
||||||
"improve_contrast_enabled": mp.Value( # type: ignore[typeddict-item]
|
|
||||||
# issue https://github.com/python/typeshed/issues/8799
|
|
||||||
# from mypy 0.981 onwards
|
|
||||||
"i",
|
|
||||||
self.config.cameras[camera_name].motion.improve_contrast,
|
|
||||||
),
|
|
||||||
"motion_threshold": mp.Value( # type: ignore[typeddict-item]
|
|
||||||
# issue https://github.com/python/typeshed/issues/8799
|
|
||||||
# from mypy 0.981 onwards
|
|
||||||
"i",
|
|
||||||
self.config.cameras[camera_name].motion.threshold,
|
|
||||||
),
|
|
||||||
"motion_contour_area": mp.Value( # type: ignore[typeddict-item]
|
|
||||||
# issue https://github.com/python/typeshed/issues/8799
|
|
||||||
# from mypy 0.981 onwards
|
|
||||||
"i",
|
|
||||||
self.config.cameras[camera_name].motion.contour_area,
|
|
||||||
),
|
|
||||||
"detection_fps": mp.Value("d", 0.0), # type: ignore[typeddict-item]
|
"detection_fps": mp.Value("d", 0.0), # type: ignore[typeddict-item]
|
||||||
# issue https://github.com/python/typeshed/issues/8799
|
# issue https://github.com/python/typeshed/issues/8799
|
||||||
# from mypy 0.981 onwards
|
# from mypy 0.981 onwards
|
||||||
@ -387,7 +358,6 @@ class FrigateApp:
|
|||||||
self.config,
|
self.config,
|
||||||
self.inter_config_updater,
|
self.inter_config_updater,
|
||||||
self.onvif_controller,
|
self.onvif_controller,
|
||||||
self.camera_metrics,
|
|
||||||
self.ptz_metrics,
|
self.ptz_metrics,
|
||||||
comms,
|
comms,
|
||||||
)
|
)
|
||||||
|
|||||||
@ -46,9 +46,7 @@ class ConfigSubscriber:
|
|||||||
def check_for_update(self) -> Optional[tuple[str, any]]:
|
def check_for_update(self) -> Optional[tuple[str, any]]:
|
||||||
"""Returns updated config or None if no update."""
|
"""Returns updated config or None if no update."""
|
||||||
try:
|
try:
|
||||||
topic = self.socket.recv_string(
|
topic = self.socket.recv_string(flags=zmq.NOBLOCK)
|
||||||
flags=zmq.NOBLOCK
|
|
||||||
)
|
|
||||||
return (topic, self.socket.recv_pyobj())
|
return (topic, self.socket.recv_pyobj())
|
||||||
except zmq.ZMQError:
|
except zmq.ZMQError:
|
||||||
return (None, None)
|
return (None, None)
|
||||||
|
|||||||
@ -9,7 +9,7 @@ from frigate.config import BirdseyeModeEnum, FrigateConfig
|
|||||||
from frigate.const import INSERT_MANY_RECORDINGS, INSERT_PREVIEW, REQUEST_REGION_GRID
|
from frigate.const import INSERT_MANY_RECORDINGS, INSERT_PREVIEW, REQUEST_REGION_GRID
|
||||||
from frigate.models import Previews, Recordings
|
from frigate.models import Previews, Recordings
|
||||||
from frigate.ptz.onvif import OnvifCommandEnum, OnvifController
|
from frigate.ptz.onvif import OnvifCommandEnum, OnvifController
|
||||||
from frigate.types import CameraMetricsTypes, PTZMetricsTypes
|
from frigate.types import PTZMetricsTypes
|
||||||
from frigate.util.object import get_camera_regions_grid
|
from frigate.util.object import get_camera_regions_grid
|
||||||
from frigate.util.services import restart_frigate
|
from frigate.util.services import restart_frigate
|
||||||
|
|
||||||
@ -43,14 +43,12 @@ class Dispatcher:
|
|||||||
config: FrigateConfig,
|
config: FrigateConfig,
|
||||||
config_updater: ConfigPublisher,
|
config_updater: ConfigPublisher,
|
||||||
onvif: OnvifController,
|
onvif: OnvifController,
|
||||||
camera_metrics: dict[str, CameraMetricsTypes],
|
|
||||||
ptz_metrics: dict[str, PTZMetricsTypes],
|
ptz_metrics: dict[str, PTZMetricsTypes],
|
||||||
communicators: list[Communicator],
|
communicators: list[Communicator],
|
||||||
) -> None:
|
) -> None:
|
||||||
self.config = config
|
self.config = config
|
||||||
self.config_updater = config_updater
|
self.config_updater = config_updater
|
||||||
self.onvif = onvif
|
self.onvif = onvif
|
||||||
self.camera_metrics = camera_metrics
|
|
||||||
self.ptz_metrics = ptz_metrics
|
self.ptz_metrics = ptz_metrics
|
||||||
self.comms = communicators
|
self.comms = communicators
|
||||||
|
|
||||||
@ -119,44 +117,51 @@ class Dispatcher:
|
|||||||
def _on_detect_command(self, camera_name: str, payload: str) -> None:
|
def _on_detect_command(self, camera_name: str, payload: str) -> None:
|
||||||
"""Callback for detect topic."""
|
"""Callback for detect topic."""
|
||||||
detect_settings = self.config.cameras[camera_name].detect
|
detect_settings = self.config.cameras[camera_name].detect
|
||||||
|
motion_settings = self.config.cameras[camera_name].motion
|
||||||
|
|
||||||
if payload == "ON":
|
if payload == "ON":
|
||||||
if not self.camera_metrics[camera_name]["detection_enabled"].value:
|
if not detect_settings.enabled:
|
||||||
logger.info(f"Turning on detection for {camera_name}")
|
logger.info(f"Turning on detection for {camera_name}")
|
||||||
self.camera_metrics[camera_name]["detection_enabled"].value = True
|
|
||||||
detect_settings.enabled = True
|
detect_settings.enabled = True
|
||||||
|
|
||||||
if not self.camera_metrics[camera_name]["motion_enabled"].value:
|
if not motion_settings.enabled:
|
||||||
logger.info(
|
logger.info(
|
||||||
f"Turning on motion for {camera_name} due to detection being enabled."
|
f"Turning on motion for {camera_name} due to detection being enabled."
|
||||||
)
|
)
|
||||||
self.camera_metrics[camera_name]["motion_enabled"].value = True
|
motion_settings.enabled = True
|
||||||
|
self.config_updater.publish(
|
||||||
|
f"config/motion/{camera_name}", motion_settings
|
||||||
|
)
|
||||||
self.publish(f"{camera_name}/motion/state", payload, retain=True)
|
self.publish(f"{camera_name}/motion/state", payload, retain=True)
|
||||||
elif payload == "OFF":
|
elif payload == "OFF":
|
||||||
if self.camera_metrics[camera_name]["detection_enabled"].value:
|
if detect_settings.enabled:
|
||||||
logger.info(f"Turning off detection for {camera_name}")
|
logger.info(f"Turning off detection for {camera_name}")
|
||||||
self.camera_metrics[camera_name]["detection_enabled"].value = False
|
|
||||||
detect_settings.enabled = False
|
detect_settings.enabled = False
|
||||||
|
|
||||||
|
self.config_updater.publish(f"config/detect/{camera_name}", detect_settings)
|
||||||
self.publish(f"{camera_name}/detect/state", payload, retain=True)
|
self.publish(f"{camera_name}/detect/state", payload, retain=True)
|
||||||
|
|
||||||
def _on_motion_command(self, camera_name: str, payload: str) -> None:
|
def _on_motion_command(self, camera_name: str, payload: str) -> None:
|
||||||
"""Callback for motion topic."""
|
"""Callback for motion topic."""
|
||||||
|
detect_settings = self.config.cameras[camera_name].detect
|
||||||
|
motion_settings = self.config.cameras[camera_name].motion
|
||||||
|
|
||||||
if payload == "ON":
|
if payload == "ON":
|
||||||
if not self.camera_metrics[camera_name]["motion_enabled"].value:
|
if not motion_settings.enabled:
|
||||||
logger.info(f"Turning on motion for {camera_name}")
|
logger.info(f"Turning on motion for {camera_name}")
|
||||||
self.camera_metrics[camera_name]["motion_enabled"].value = True
|
motion_settings.enabled = True
|
||||||
elif payload == "OFF":
|
elif payload == "OFF":
|
||||||
if self.camera_metrics[camera_name]["detection_enabled"].value:
|
if detect_settings.enabled:
|
||||||
logger.error(
|
logger.error(
|
||||||
"Turning off motion is not allowed when detection is enabled."
|
"Turning off motion is not allowed when detection is enabled."
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
if self.camera_metrics[camera_name]["motion_enabled"].value:
|
if motion_settings.enabled:
|
||||||
logger.info(f"Turning off motion for {camera_name}")
|
logger.info(f"Turning off motion for {camera_name}")
|
||||||
self.camera_metrics[camera_name]["motion_enabled"].value = False
|
motion_settings.enabled = False
|
||||||
|
|
||||||
|
self.config_updater.publish(f"config/motion/{camera_name}", motion_settings)
|
||||||
self.publish(f"{camera_name}/motion/state", payload, retain=True)
|
self.publish(f"{camera_name}/motion/state", payload, retain=True)
|
||||||
|
|
||||||
def _on_motion_improve_contrast_command(
|
def _on_motion_improve_contrast_command(
|
||||||
@ -166,20 +171,15 @@ class Dispatcher:
|
|||||||
motion_settings = self.config.cameras[camera_name].motion
|
motion_settings = self.config.cameras[camera_name].motion
|
||||||
|
|
||||||
if payload == "ON":
|
if payload == "ON":
|
||||||
if not self.camera_metrics[camera_name]["improve_contrast_enabled"].value:
|
if not motion_settings.improve_contrast:
|
||||||
logger.info(f"Turning on improve contrast for {camera_name}")
|
logger.info(f"Turning on improve contrast for {camera_name}")
|
||||||
self.camera_metrics[camera_name][
|
|
||||||
"improve_contrast_enabled"
|
|
||||||
].value = True
|
|
||||||
motion_settings.improve_contrast = True # type: ignore[union-attr]
|
motion_settings.improve_contrast = True # type: ignore[union-attr]
|
||||||
elif payload == "OFF":
|
elif payload == "OFF":
|
||||||
if self.camera_metrics[camera_name]["improve_contrast_enabled"].value:
|
if motion_settings.improve_contrast:
|
||||||
logger.info(f"Turning off improve contrast for {camera_name}")
|
logger.info(f"Turning off improve contrast for {camera_name}")
|
||||||
self.camera_metrics[camera_name][
|
|
||||||
"improve_contrast_enabled"
|
|
||||||
].value = False
|
|
||||||
motion_settings.improve_contrast = False # type: ignore[union-attr]
|
motion_settings.improve_contrast = False # type: ignore[union-attr]
|
||||||
|
|
||||||
|
self.config_updater.publish(f"config/motion/{camera_name}", motion_settings)
|
||||||
self.publish(f"{camera_name}/improve_contrast/state", payload, retain=True)
|
self.publish(f"{camera_name}/improve_contrast/state", payload, retain=True)
|
||||||
|
|
||||||
def _on_ptz_autotracker_command(self, camera_name: str, payload: str) -> None:
|
def _on_ptz_autotracker_command(self, camera_name: str, payload: str) -> None:
|
||||||
@ -218,8 +218,8 @@ class Dispatcher:
|
|||||||
|
|
||||||
motion_settings = self.config.cameras[camera_name].motion
|
motion_settings = self.config.cameras[camera_name].motion
|
||||||
logger.info(f"Setting motion contour area for {camera_name}: {payload}")
|
logger.info(f"Setting motion contour area for {camera_name}: {payload}")
|
||||||
self.camera_metrics[camera_name]["motion_contour_area"].value = payload
|
|
||||||
motion_settings.contour_area = payload # type: ignore[union-attr]
|
motion_settings.contour_area = payload # type: ignore[union-attr]
|
||||||
|
self.config_updater.publish(f"config/motion/{camera_name}", motion_settings)
|
||||||
self.publish(f"{camera_name}/motion_contour_area/state", payload, retain=True)
|
self.publish(f"{camera_name}/motion_contour_area/state", payload, retain=True)
|
||||||
|
|
||||||
def _on_motion_threshold_command(self, camera_name: str, payload: int) -> None:
|
def _on_motion_threshold_command(self, camera_name: str, payload: int) -> None:
|
||||||
@ -232,8 +232,8 @@ class Dispatcher:
|
|||||||
|
|
||||||
motion_settings = self.config.cameras[camera_name].motion
|
motion_settings = self.config.cameras[camera_name].motion
|
||||||
logger.info(f"Setting motion threshold for {camera_name}: {payload}")
|
logger.info(f"Setting motion threshold for {camera_name}: {payload}")
|
||||||
self.camera_metrics[camera_name]["motion_threshold"].value = payload
|
|
||||||
motion_settings.threshold = payload # type: ignore[union-attr]
|
motion_settings.threshold = payload # type: ignore[union-attr]
|
||||||
|
self.config_updater.publish(f"config/motion/{camera_name}", motion_settings)
|
||||||
self.publish(f"{camera_name}/motion_threshold/state", payload, retain=True)
|
self.publish(f"{camera_name}/motion_threshold/state", payload, retain=True)
|
||||||
|
|
||||||
def _on_audio_command(self, camera_name: str, payload: str) -> None:
|
def _on_audio_command(self, camera_name: str, payload: str) -> None:
|
||||||
@ -255,9 +255,7 @@ class Dispatcher:
|
|||||||
logger.info(f"Turning off audio detection for {camera_name}")
|
logger.info(f"Turning off audio detection for {camera_name}")
|
||||||
audio_settings.enabled = False
|
audio_settings.enabled = False
|
||||||
|
|
||||||
self.config_updater.publish(
|
self.config_updater.publish(f"config/audio/{camera_name}", audio_settings)
|
||||||
f"config/audio/{camera_name}", self.config.cameras[camera_name].audio
|
|
||||||
)
|
|
||||||
self.publish(f"{camera_name}/audio/state", payload, retain=True)
|
self.publish(f"{camera_name}/audio/state", payload, retain=True)
|
||||||
|
|
||||||
def _on_recordings_command(self, camera_name: str, payload: str) -> None:
|
def _on_recordings_command(self, camera_name: str, payload: str) -> None:
|
||||||
@ -279,9 +277,7 @@ class Dispatcher:
|
|||||||
logger.info(f"Turning off recordings for {camera_name}")
|
logger.info(f"Turning off recordings for {camera_name}")
|
||||||
record_settings.enabled = False
|
record_settings.enabled = False
|
||||||
|
|
||||||
self.config_updater.publish(
|
self.config_updater.publish(f"config/record/{camera_name}", record_settings)
|
||||||
f"config/record/{camera_name}", self.config.cameras[camera_name].record
|
|
||||||
)
|
|
||||||
self.publish(f"{camera_name}/recordings/state", payload, retain=True)
|
self.publish(f"{camera_name}/recordings/state", payload, retain=True)
|
||||||
|
|
||||||
def _on_snapshots_command(self, camera_name: str, payload: str) -> None:
|
def _on_snapshots_command(self, camera_name: str, payload: str) -> None:
|
||||||
@ -328,9 +324,7 @@ class Dispatcher:
|
|||||||
logger.info(f"Turning off birdseye for {camera_name}")
|
logger.info(f"Turning off birdseye for {camera_name}")
|
||||||
birdseye_settings.enabled = False
|
birdseye_settings.enabled = False
|
||||||
|
|
||||||
self.config_updater.publish(
|
self.config_updater.publish(f"config/birdseye/{camera_name}", birdseye_settings)
|
||||||
f"config/birdseye/{camera_name}", self.config.cameras[camera_name].birdseye
|
|
||||||
)
|
|
||||||
self.publish(f"{camera_name}/birdseye/state", payload, retain=True)
|
self.publish(f"{camera_name}/birdseye/state", payload, retain=True)
|
||||||
|
|
||||||
def _on_birdseye_mode_command(self, camera_name: str, payload: str) -> None:
|
def _on_birdseye_mode_command(self, camera_name: str, payload: str) -> None:
|
||||||
@ -340,18 +334,16 @@ class Dispatcher:
|
|||||||
logger.info(f"Invalid birdseye_mode command: {payload}")
|
logger.info(f"Invalid birdseye_mode command: {payload}")
|
||||||
return
|
return
|
||||||
|
|
||||||
birdseye_config = self.config.cameras[camera_name].birdseye
|
birdseye_settings = self.config.cameras[camera_name].birdseye
|
||||||
|
|
||||||
if not birdseye_config.enabled:
|
if not birdseye_settings.enabled:
|
||||||
logger.info(f"Birdseye mode not enabled for {camera_name}")
|
logger.info(f"Birdseye mode not enabled for {camera_name}")
|
||||||
return
|
return
|
||||||
|
|
||||||
birdseye_config.mode = BirdseyeModeEnum(payload.lower())
|
birdseye_settings.mode = BirdseyeModeEnum(payload.lower())
|
||||||
logger.info(
|
logger.info(
|
||||||
f"Setting birdseye mode for {camera_name} to {birdseye_config.mode}"
|
f"Setting birdseye mode for {camera_name} to {birdseye_settings.mode}"
|
||||||
)
|
)
|
||||||
|
|
||||||
self.config_updater.publish(
|
self.config_updater.publish(f"config/birdseye/{camera_name}", birdseye_settings)
|
||||||
f"config/birdseye/{camera_name}", self.config.cameras[camera_name].birdseye
|
|
||||||
)
|
|
||||||
self.publish(f"{camera_name}/birdseye_mode/state", payload, retain=True)
|
self.publish(f"{camera_name}/birdseye_mode/state", payload, retain=True)
|
||||||
|
|||||||
@ -32,7 +32,7 @@ class InterProcessCommunicator(Communicator):
|
|||||||
self.reader_thread.start()
|
self.reader_thread.start()
|
||||||
|
|
||||||
def read(self) -> None:
|
def read(self) -> None:
|
||||||
while not self.stop_event.wait(0.5):
|
while not self.stop_event.wait(0.1):
|
||||||
while True: # load all messages that are queued
|
while True: # load all messages that are queued
|
||||||
try:
|
try:
|
||||||
(topic, value) = self.socket.recv_pyobj(flags=zmq.NOBLOCK)
|
(topic, value) = self.socket.recv_pyobj(flags=zmq.NOBLOCK)
|
||||||
|
|||||||
@ -300,6 +300,7 @@ class RecordConfig(FrigateBaseModel):
|
|||||||
|
|
||||||
|
|
||||||
class MotionConfig(FrigateBaseModel):
|
class MotionConfig(FrigateBaseModel):
|
||||||
|
enabled: bool = Field(default=True, title="Enable motion on all cameras.")
|
||||||
threshold: int = Field(
|
threshold: int = Field(
|
||||||
default=30,
|
default=30,
|
||||||
title="Motion detection threshold (1-255).",
|
title="Motion detection threshold (1-255).",
|
||||||
@ -321,6 +322,9 @@ class MotionConfig(FrigateBaseModel):
|
|||||||
default=30,
|
default=30,
|
||||||
title="Delay for updating MQTT with no motion detected.",
|
title="Delay for updating MQTT with no motion detected.",
|
||||||
)
|
)
|
||||||
|
enabled_in_config: Optional[bool] = Field(
|
||||||
|
title="Keep track of original state of motion detection."
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class RuntimeMotionConfig(MotionConfig):
|
class RuntimeMotionConfig(MotionConfig):
|
||||||
@ -1041,6 +1045,14 @@ def verify_autotrack_zones(camera_config: CameraConfig) -> ValueError | None:
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def verify_motion_and_detect(camera_config: CameraConfig) -> ValueError | None:
|
||||||
|
"""Verify that required_zones are specified when autotracking is enabled."""
|
||||||
|
if camera_config.detect.enabled and not camera_config.motion.enabled:
|
||||||
|
raise ValueError(
|
||||||
|
f"Camera {camera_config.name} has motion detection disabled and object detection enabled but object detection requires motion detection ."
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class FrigateConfig(FrigateBaseModel):
|
class FrigateConfig(FrigateBaseModel):
|
||||||
mqtt: MqttConfig = Field(title="MQTT Configuration.")
|
mqtt: MqttConfig = Field(title="MQTT Configuration.")
|
||||||
database: DatabaseConfig = Field(
|
database: DatabaseConfig = Field(
|
||||||
@ -1202,8 +1214,8 @@ class FrigateConfig(FrigateBaseModel):
|
|||||||
**FRIGATE_ENV_VARS
|
**FRIGATE_ENV_VARS
|
||||||
)
|
)
|
||||||
# set config pre-value
|
# set config pre-value
|
||||||
camera_config.record.enabled_in_config = camera_config.record.enabled
|
|
||||||
camera_config.audio.enabled_in_config = camera_config.audio.enabled
|
camera_config.audio.enabled_in_config = camera_config.audio.enabled
|
||||||
|
camera_config.record.enabled_in_config = camera_config.record.enabled
|
||||||
camera_config.onvif.autotracking.enabled_in_config = (
|
camera_config.onvif.autotracking.enabled_in_config = (
|
||||||
camera_config.onvif.autotracking.enabled
|
camera_config.onvif.autotracking.enabled
|
||||||
)
|
)
|
||||||
@ -1250,6 +1262,7 @@ class FrigateConfig(FrigateBaseModel):
|
|||||||
raw_mask=camera_config.motion.mask,
|
raw_mask=camera_config.motion.mask,
|
||||||
**camera_config.motion.dict(exclude_unset=True),
|
**camera_config.motion.dict(exclude_unset=True),
|
||||||
)
|
)
|
||||||
|
camera_config.motion.enabled_in_config = camera_config.motion.enabled
|
||||||
|
|
||||||
# Set live view stream if none is set
|
# Set live view stream if none is set
|
||||||
if not camera_config.live.stream_name:
|
if not camera_config.live.stream_name:
|
||||||
@ -1261,6 +1274,7 @@ class FrigateConfig(FrigateBaseModel):
|
|||||||
verify_recording_segments_setup_with_reasonable_time(camera_config)
|
verify_recording_segments_setup_with_reasonable_time(camera_config)
|
||||||
verify_zone_objects_are_tracked(camera_config)
|
verify_zone_objects_are_tracked(camera_config)
|
||||||
verify_autotrack_zones(camera_config)
|
verify_autotrack_zones(camera_config)
|
||||||
|
verify_motion_and_detect(camera_config)
|
||||||
|
|
||||||
# generate the ffmpeg commands
|
# generate the ffmpeg commands
|
||||||
camera_config.create_ffmpeg_cmds()
|
camera_config.create_ffmpeg_cmds()
|
||||||
|
|||||||
@ -338,9 +338,10 @@ class AudioEventMaintainer(threading.Thread):
|
|||||||
|
|
||||||
while not self.stop_event.is_set():
|
while not self.stop_event.is_set():
|
||||||
# check if there is an updated config
|
# check if there is an updated config
|
||||||
updated_topic, updated_audio_config = (
|
(
|
||||||
self.config_subscriber.check_for_update()
|
updated_topic,
|
||||||
)
|
updated_audio_config,
|
||||||
|
) = self.config_subscriber.check_for_update()
|
||||||
|
|
||||||
if updated_topic:
|
if updated_topic:
|
||||||
self.config.audio = updated_audio_config
|
self.config.audio = updated_audio_config
|
||||||
|
|||||||
@ -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.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
|
||||||
|
|
||||||
@ -17,9 +18,6 @@ class ImprovedMotionDetector(MotionDetector):
|
|||||||
frame_shape,
|
frame_shape,
|
||||||
config: MotionConfig,
|
config: MotionConfig,
|
||||||
fps: int,
|
fps: int,
|
||||||
improve_contrast,
|
|
||||||
threshold,
|
|
||||||
contour_area,
|
|
||||||
name="improved",
|
name="improved",
|
||||||
blur_radius=1,
|
blur_radius=1,
|
||||||
interpolation=cv2.INTER_NEAREST,
|
interpolation=cv2.INTER_NEAREST,
|
||||||
@ -44,14 +42,12 @@ class ImprovedMotionDetector(MotionDetector):
|
|||||||
self.mask = np.where(resized_mask == [0])
|
self.mask = np.where(resized_mask == [0])
|
||||||
self.save_images = False
|
self.save_images = False
|
||||||
self.calibrating = True
|
self.calibrating = True
|
||||||
self.improve_contrast = improve_contrast
|
|
||||||
self.threshold = threshold
|
|
||||||
self.contour_area = contour_area
|
|
||||||
self.blur_radius = blur_radius
|
self.blur_radius = blur_radius
|
||||||
self.interpolation = interpolation
|
self.interpolation = interpolation
|
||||||
self.contrast_values = np.zeros((contrast_frame_history, 2), np.uint8)
|
self.contrast_values = np.zeros((contrast_frame_history, 2), np.uint8)
|
||||||
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}")
|
||||||
|
|
||||||
def is_calibrating(self):
|
def is_calibrating(self):
|
||||||
return self.calibrating
|
return self.calibrating
|
||||||
@ -59,6 +55,15 @@ class ImprovedMotionDetector(MotionDetector):
|
|||||||
def detect(self, frame):
|
def detect(self, frame):
|
||||||
motion_boxes = []
|
motion_boxes = []
|
||||||
|
|
||||||
|
# check for updated motion config
|
||||||
|
_, updated_motion_config = self.config_subscriber.check_for_update()
|
||||||
|
|
||||||
|
if updated_motion_config:
|
||||||
|
self.config = updated_motion_config
|
||||||
|
|
||||||
|
if not self.config.enabled:
|
||||||
|
return motion_boxes
|
||||||
|
|
||||||
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
|
||||||
@ -72,7 +77,7 @@ class ImprovedMotionDetector(MotionDetector):
|
|||||||
resized_saved = resized_frame.copy()
|
resized_saved = resized_frame.copy()
|
||||||
|
|
||||||
# Improve contrast
|
# Improve contrast
|
||||||
if self.improve_contrast.value:
|
if self.config.improve_contrast:
|
||||||
# TODO tracking moving average of min/max to avoid sudden contrast changes
|
# TODO tracking moving average of min/max to avoid sudden contrast changes
|
||||||
minval = np.percentile(resized_frame, 4).astype(np.uint8)
|
minval = np.percentile(resized_frame, 4).astype(np.uint8)
|
||||||
maxval = np.percentile(resized_frame, 96).astype(np.uint8)
|
maxval = np.percentile(resized_frame, 96).astype(np.uint8)
|
||||||
@ -110,7 +115,7 @@ class ImprovedMotionDetector(MotionDetector):
|
|||||||
|
|
||||||
# compute the threshold image for the current frame
|
# compute the threshold image for the current frame
|
||||||
thresh = cv2.threshold(
|
thresh = cv2.threshold(
|
||||||
frameDelta, self.threshold.value, 255, cv2.THRESH_BINARY
|
frameDelta, self.config.threshold, 255, cv2.THRESH_BINARY
|
||||||
)[1]
|
)[1]
|
||||||
|
|
||||||
# dilate the thresholded image to fill in holes, then find contours
|
# dilate the thresholded image to fill in holes, then find contours
|
||||||
@ -127,7 +132,7 @@ class ImprovedMotionDetector(MotionDetector):
|
|||||||
# if the contour is big enough, count it as motion
|
# if the contour is big enough, count it as motion
|
||||||
contour_area = cv2.contourArea(c)
|
contour_area = cv2.contourArea(c)
|
||||||
total_contour_area += contour_area
|
total_contour_area += contour_area
|
||||||
if contour_area > self.contour_area.value:
|
if contour_area > self.config.contour_area:
|
||||||
x, y, w, h = cv2.boundingRect(c)
|
x, y, w, h = cv2.boundingRect(c)
|
||||||
motion_boxes.append(
|
motion_boxes.append(
|
||||||
(
|
(
|
||||||
@ -170,9 +175,11 @@ class ImprovedMotionDetector(MotionDetector):
|
|||||||
]
|
]
|
||||||
cv2.imwrite(
|
cv2.imwrite(
|
||||||
f"debug/frames/{self.name}-{self.frame_counter}.jpg",
|
f"debug/frames/{self.name}-{self.frame_counter}.jpg",
|
||||||
|
(
|
||||||
cv2.hconcat(frames)
|
cv2.hconcat(frames)
|
||||||
if self.frame_shape[0] > self.frame_shape[1]
|
if self.frame_shape[0] > self.frame_shape[1]
|
||||||
else cv2.vconcat(frames),
|
else cv2.vconcat(frames)
|
||||||
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
if len(motion_boxes) > 0:
|
if len(motion_boxes) > 0:
|
||||||
|
|||||||
@ -433,10 +433,7 @@ class BirdsEyeFrameManager:
|
|||||||
|
|
||||||
# check if we need to reset the layout because there is a different number of cameras
|
# check if we need to reset the layout because there is a different number of cameras
|
||||||
if len(self.active_cameras) - len(active_cameras) == 0:
|
if len(self.active_cameras) - len(active_cameras) == 0:
|
||||||
if (
|
if len(self.active_cameras) == 1 and self.active_cameras != active_cameras:
|
||||||
len(self.active_cameras) == 1
|
|
||||||
and self.active_cameras[0] == active_cameras[0]
|
|
||||||
):
|
|
||||||
reset_layout = True
|
reset_layout = True
|
||||||
elif max_camera_refresh:
|
elif max_camera_refresh:
|
||||||
reset_layout = True
|
reset_layout = True
|
||||||
@ -758,9 +755,10 @@ class Birdseye:
|
|||||||
) -> None:
|
) -> None:
|
||||||
# check if there is an updated config
|
# check if there is an updated config
|
||||||
while True:
|
while True:
|
||||||
updated_topic, updated_birdseye_config = (
|
(
|
||||||
self.config_subscriber.check_for_update()
|
updated_topic,
|
||||||
)
|
updated_birdseye_config,
|
||||||
|
) = self.config_subscriber.check_for_update()
|
||||||
|
|
||||||
if not updated_topic:
|
if not updated_topic:
|
||||||
break
|
break
|
||||||
|
|||||||
@ -444,9 +444,10 @@ class RecordingMaintainer(threading.Thread):
|
|||||||
|
|
||||||
# check if there is an updated config
|
# check if there is an updated config
|
||||||
while True:
|
while True:
|
||||||
updated_topic, updated_record_config = (
|
(
|
||||||
self.config_subscriber.check_for_update()
|
updated_topic,
|
||||||
)
|
updated_record_config,
|
||||||
|
) = self.config_subscriber.check_for_update()
|
||||||
|
|
||||||
if not updated_topic:
|
if not updated_topic:
|
||||||
break
|
break
|
||||||
|
|||||||
@ -11,6 +11,7 @@ import time
|
|||||||
import cv2
|
import cv2
|
||||||
from setproctitle import setproctitle
|
from setproctitle import setproctitle
|
||||||
|
|
||||||
|
from frigate.comms.config_updater import ConfigSubscriber
|
||||||
from frigate.comms.inter_process import InterProcessRequestor
|
from frigate.comms.inter_process import InterProcessRequestor
|
||||||
from frigate.config import CameraConfig, DetectConfig, ModelConfig
|
from frigate.config import CameraConfig, DetectConfig, ModelConfig
|
||||||
from frigate.const import (
|
from frigate.const import (
|
||||||
@ -406,11 +407,6 @@ def track_camera(
|
|||||||
listen()
|
listen()
|
||||||
|
|
||||||
frame_queue = process_info["frame_queue"]
|
frame_queue = process_info["frame_queue"]
|
||||||
detection_enabled = process_info["detection_enabled"]
|
|
||||||
motion_enabled = process_info["motion_enabled"]
|
|
||||||
improve_contrast_enabled = process_info["improve_contrast_enabled"]
|
|
||||||
motion_threshold = process_info["motion_threshold"]
|
|
||||||
motion_contour_area = process_info["motion_contour_area"]
|
|
||||||
|
|
||||||
frame_shape = config.frame_shape
|
frame_shape = config.frame_shape
|
||||||
objects_to_track = config.objects.track
|
objects_to_track = config.objects.track
|
||||||
@ -420,9 +416,6 @@ def track_camera(
|
|||||||
frame_shape,
|
frame_shape,
|
||||||
config.motion,
|
config.motion,
|
||||||
config.detect.fps,
|
config.detect.fps,
|
||||||
improve_contrast_enabled,
|
|
||||||
motion_threshold,
|
|
||||||
motion_contour_area,
|
|
||||||
)
|
)
|
||||||
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
|
||||||
@ -450,8 +443,6 @@ def track_camera(
|
|||||||
process_info,
|
process_info,
|
||||||
objects_to_track,
|
objects_to_track,
|
||||||
object_filters,
|
object_filters,
|
||||||
detection_enabled,
|
|
||||||
motion_enabled,
|
|
||||||
stop_event,
|
stop_event,
|
||||||
ptz_metrics,
|
ptz_metrics,
|
||||||
region_grid,
|
region_grid,
|
||||||
@ -519,8 +510,6 @@ def process_frames(
|
|||||||
process_info: dict,
|
process_info: dict,
|
||||||
objects_to_track: list[str],
|
objects_to_track: list[str],
|
||||||
object_filters,
|
object_filters,
|
||||||
detection_enabled: mp.Value,
|
|
||||||
motion_enabled: mp.Value,
|
|
||||||
stop_event,
|
stop_event,
|
||||||
ptz_metrics: PTZMetricsTypes,
|
ptz_metrics: PTZMetricsTypes,
|
||||||
region_grid,
|
region_grid,
|
||||||
@ -530,6 +519,7 @@ def process_frames(
|
|||||||
detection_fps = process_info["detection_fps"]
|
detection_fps = process_info["detection_fps"]
|
||||||
current_frame_time = process_info["detection_frame"]
|
current_frame_time = process_info["detection_frame"]
|
||||||
next_region_update = get_tomorrow_at_time(2)
|
next_region_update = get_tomorrow_at_time(2)
|
||||||
|
config_subscriber = ConfigSubscriber(f"config/detect/{camera_name}")
|
||||||
|
|
||||||
fps_tracker = EventsPerSecond()
|
fps_tracker = EventsPerSecond()
|
||||||
fps_tracker.start()
|
fps_tracker.start()
|
||||||
@ -540,6 +530,12 @@ def process_frames(
|
|||||||
region_min_size = get_min_region_size(model_config)
|
region_min_size = get_min_region_size(model_config)
|
||||||
|
|
||||||
while not stop_event.is_set():
|
while not stop_event.is_set():
|
||||||
|
# check for updated detect config
|
||||||
|
_, updated_detect_config = config_subscriber.check_for_update()
|
||||||
|
|
||||||
|
if updated_detect_config:
|
||||||
|
detect_config = updated_detect_config
|
||||||
|
|
||||||
if (
|
if (
|
||||||
datetime.datetime.now().astimezone(datetime.timezone.utc)
|
datetime.datetime.now().astimezone(datetime.timezone.utc)
|
||||||
> next_region_update
|
> next_region_update
|
||||||
@ -570,13 +566,13 @@ def process_frames(
|
|||||||
continue
|
continue
|
||||||
|
|
||||||
# look for motion if enabled
|
# look for motion if enabled
|
||||||
motion_boxes = motion_detector.detect(frame) if motion_enabled.value else []
|
motion_boxes = motion_detector.detect(frame)
|
||||||
|
|
||||||
regions = []
|
regions = []
|
||||||
consolidated_detections = []
|
consolidated_detections = []
|
||||||
|
|
||||||
# if detection is disabled
|
# if detection is disabled
|
||||||
if not detection_enabled.value:
|
if not detect_config.enabled:
|
||||||
object_tracker.match_and_update(frame_time, [])
|
object_tracker.match_and_update(frame_time, [])
|
||||||
else:
|
else:
|
||||||
# get stationary object ids
|
# get stationary object ids
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user