diff --git a/docs/docs/configuration/detectors.md b/docs/docs/configuration/detectors.md index 53315b609..45ffffa8e 100644 --- a/docs/docs/configuration/detectors.md +++ b/docs/docs/configuration/detectors.md @@ -29,6 +29,7 @@ detectors: When using CPU detectors, you can add one CPU detector per camera. Adding more detectors than the number of cameras should not improve performance. ## Edge-TPU Detector + The EdgeTPU detector type runs a TensorFlow Lite model utilizing the Google Coral delegate for hardware acceleration. To configure an EdgeTPU detector, set the `"type"` attribute to `"edgetpu"`. The EdgeTPU device can specified using the `"device"` attribute according to the [Documentation for the TensorFlow Lite Python API](https://coral.ai/docs/edgetpu/multiple-edgetpu/#using-the-tensorflow-lite-python-api). If not set, the delegate will use the first device it finds. @@ -93,6 +94,7 @@ detectors: ``` ## OpenVINO Detector + The OpenVINO detector type runs an OpenVINO IR model on Intel CPU, GPU and VPU hardware. To configure an OpenVINO detector, set the `"type"` attribute to `"openvino"`. The OpenVINO device plugin is specified using the `"device"` attribute according to naming conventions in the [Device Documentation](https://docs.openvino.ai/latest/openvino_docs_OV_UG_Working_with_devices.html). Other supported devices could be `AUTO`, `CPU`, `GPU`, `MYRIAD`, etc. If not specified, the default OpenVINO device will be selected by the `AUTO` plugin. @@ -145,3 +147,38 @@ device_cgroup_rules: volumes: - /dev/bus/usb:/dev/bus/usb ``` + +## Custom Detectors + +Custom python detector modules can be added at `/opt/frigate/frigate/detectors/plugins` in the container. +See the below for an example implementation. + +```python +from frigate.detectors.detection_api import DetectionApi +from frigate.detectors.detector_config import BaseDetectorConfig +from typing import Literal +from pydantic import Extra, Field + +DETECTOR_KEY = "" + +# A pydantic model inheriting from `BaseDetectorConfig` +# Must implement the `type` attribute as below +# Can add any number of fields to be passed from +# configuration to the constructor of your detector. +class CustomDetectorConfig(BaseDetectorConfig): + type: Literal[DETECTOR_KEY] + custom_field: str = Field(default="value", title="Custom field description") + + +# The custom detector class must inherit from `DetectionApi` +# and must implement the `type_key`, `__init__`, +# and `detect_raw` methods as below +class CustomDetector(DetectionApi): + type_key = DETECTOR_KEY + + def __init__(self, detector_config: CustomDetectorConfig): + ... + + def detect_raw(self, tensor_input): + return +``` \ No newline at end of file diff --git a/docs/docs/configuration/index.md b/docs/docs/configuration/index.md index a0ede7448..e03a9484c 100644 --- a/docs/docs/configuration/index.md +++ b/docs/docs/configuration/index.md @@ -76,7 +76,7 @@ detectors: # Required: name of the detector detector_name: # Required: type of the detector - # Frigate provided types include 'cpu', 'edgetpu', and 'openvino' + # Frigate provided types include 'cpu', 'edgetpu', and 'openvino' (default: shown below) # Additional detector types can also be plugged in. # Detectors may require additional configuration. # Refer to the Detectors configuration page for more information. diff --git a/frigate/app.py b/frigate/app.py index 0e21359fe..5ffa3d77d 100644 --- a/frigate/app.py +++ b/frigate/app.py @@ -186,7 +186,7 @@ class FrigateApp: self.detection_out_events[name] = mp.Event() try: - size = max( + largest_frame = max( [ det.model.height * det.model.width * 3 for (name, det) in self.config.detectors.items() @@ -195,7 +195,7 @@ class FrigateApp: shm_in = mp.shared_memory.SharedMemory( name=name, create=True, - size=size, + size=largest_frame, ) except FileExistsError: shm_in = mp.shared_memory.SharedMemory(name=name) diff --git a/frigate/config.py b/frigate/config.py index 927cc3c5d..787722239 100644 --- a/frigate/config.py +++ b/frigate/config.py @@ -834,7 +834,7 @@ class FrigateConfig(FrigateBaseModel): default_factory=ModelConfig, title="Detection model configuration." ) detectors: Dict[str, DetectorConfig] = Field( - default=parse_obj_as(Dict[str, DetectorConfig], DEFAULT_DETECTORS), + default=DEFAULT_DETECTORS, title="Detector hardware configuration.", ) logger: LoggerConfig = Field( diff --git a/frigate/detectors/plugins/cpu_tfl.py b/frigate/detectors/plugins/cpu_tfl.py index 28235639a..9e24cb1f4 100644 --- a/frigate/detectors/plugins/cpu_tfl.py +++ b/frigate/detectors/plugins/cpu_tfl.py @@ -10,14 +10,16 @@ import tflite_runtime.interpreter as tflite logger = logging.getLogger(__name__) +DETECTOR_KEY = "cpu" + class CpuDetectorConfig(BaseDetectorConfig): - type: Literal["cpu"] + type: Literal[DETECTOR_KEY] num_threads: int = Field(default=3, title="Number of detection threads") class CpuTfl(DetectionApi): - type_key = "cpu" + type_key = DETECTOR_KEY def __init__(self, detector_config: CpuDetectorConfig): self.interpreter = tflite.Interpreter( diff --git a/frigate/detectors/plugins/edgetpu_tfl.py b/frigate/detectors/plugins/edgetpu_tfl.py index d8ba0b2e1..49fd14e77 100644 --- a/frigate/detectors/plugins/edgetpu_tfl.py +++ b/frigate/detectors/plugins/edgetpu_tfl.py @@ -11,14 +11,16 @@ from tflite_runtime.interpreter import load_delegate logger = logging.getLogger(__name__) +DETECTOR_KEY = "edgetpu" + class EdgeTpuDetectorConfig(BaseDetectorConfig): - type: Literal["edgetpu"] + type: Literal[DETECTOR_KEY] device: str = Field(default="usb", title="Device Type") class EdgeTpuTfl(DetectionApi): - type_key = "edgetpu" + type_key = DETECTOR_KEY def __init__(self, detector_config: EdgeTpuDetectorConfig): device_config = {"device": "usb"} diff --git a/frigate/detectors/plugins/openvino.py b/frigate/detectors/plugins/openvino.py index 91195f7cc..b4eb024a2 100644 --- a/frigate/detectors/plugins/openvino.py +++ b/frigate/detectors/plugins/openvino.py @@ -10,14 +10,16 @@ from pydantic import Extra, Field logger = logging.getLogger(__name__) +DETECTOR_KEY = "openvino" + class OvDetectorConfig(BaseDetectorConfig): - type: Literal["openvino"] + type: Literal[DETECTOR_KEY] device: str = Field(default="AUTO", title="Device Type") class OvDetector(DetectionApi): - type_key = "openvino" + type_key = DETECTOR_KEY def __init__(self, detector_config: OvDetectorConfig): self.ov_core = ov.Core()