mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-10-16 19:52:49 +03:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c3cf6cf3cb | ||
|
|
aa42b17911 | ||
|
|
698b1ce628 | ||
|
|
cfa08c56b2 |
@@ -5,6 +5,8 @@ location /auth {
|
|||||||
## Essential Proxy Configuration
|
## Essential Proxy Configuration
|
||||||
internal;
|
internal;
|
||||||
proxy_pass $upstream_auth;
|
proxy_pass $upstream_auth;
|
||||||
|
# $go2rtc_stream_proxy is only set by the go2rtc stream locations
|
||||||
|
uninitialized_variable_warn off;
|
||||||
|
|
||||||
## Headers
|
## Headers
|
||||||
|
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ Along with picking a detector for your hardware, you will choose a model's **inp
|
|||||||
|
|
||||||
:::tip
|
:::tip
|
||||||
|
|
||||||
The best detection accuracy comes from a model trained on images that look like what Frigate actually sees: security camera footage cropped to regions of interest. You can train or fine-tune your own model on images like this and run it as a custom model (see the per-detector sections below), but [Frigate+](/plus) makes this much easier by handling the training for you on images submitted from your own cameras. For YOLOv9, the `s` (small) variant at `320x320` resolution is a good place to start.
|
The best detection accuracy comes from a model trained on images that look like what Frigate actually sees: security camera footage cropped to regions of interest. You can train or fine-tune your own model on images like this and run it as a custom model (see the per-detector sections below), but [Frigate+](/plus) makes this much easier by handling the training for you on images submitted from your own cameras. For YOLOv9, the `s` (small) variant at `320x320` resolution is a good place to start, and the larger `c` variant is available for more powerful hardware.
|
||||||
|
|
||||||
:::
|
:::
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ title: Updating
|
|||||||
|
|
||||||
# Updating Frigate
|
# Updating Frigate
|
||||||
|
|
||||||
The current stable version of Frigate is **0.18.1**. The release notes and any breaking changes for this version can be found on the [Frigate GitHub releases page](https://github.com/blakeblackshear/frigate/releases/tag/v0.18.1).
|
The current stable version of Frigate is **0.18.2**. The release notes and any breaking changes for this version can be found on the [Frigate GitHub releases page](https://github.com/blakeblackshear/frigate/releases/tag/v0.18.2).
|
||||||
|
|
||||||
Keeping Frigate up to date ensures you benefit from the latest features, performance improvements, and bug fixes. The update process varies slightly depending on your installation method (Docker, Home Assistant App, etc.). Below are instructions for the most common setups.
|
Keeping Frigate up to date ensures you benefit from the latest features, performance improvements, and bug fixes. The update process varies slightly depending on your installation method (Docker, Home Assistant App, etc.). Below are instructions for the most common setups.
|
||||||
|
|
||||||
@@ -31,21 +31,21 @@ If you’re running Frigate via Docker (recommended method), follow these steps:
|
|||||||
|
|
||||||
2. **Update and Pull the Latest Image**:
|
2. **Update and Pull the Latest Image**:
|
||||||
- If using Docker Compose:
|
- If using Docker Compose:
|
||||||
- Edit your `docker-compose.yml` file to specify the desired version tag (e.g., `0.18.1` instead of `0.17.1`). For example:
|
- Edit your `docker-compose.yml` file to specify the desired version tag (e.g., `0.18.2` instead of `0.17.1`). For example:
|
||||||
```yaml
|
```yaml
|
||||||
services:
|
services:
|
||||||
frigate:
|
frigate:
|
||||||
image: ghcr.io/blakeblackshear/frigate:0.18.1
|
image: ghcr.io/blakeblackshear/frigate:0.18.2
|
||||||
```
|
```
|
||||||
- Then pull the image:
|
- Then pull the image:
|
||||||
```bash
|
```bash
|
||||||
docker pull ghcr.io/blakeblackshear/frigate:0.18.1
|
docker pull ghcr.io/blakeblackshear/frigate:0.18.2
|
||||||
```
|
```
|
||||||
- **Note for `stable` Tag Users**: If your `docker-compose.yml` uses the `stable` tag (e.g., `ghcr.io/blakeblackshear/frigate:stable`), you don’t need to update the tag manually. The `stable` tag always points to the latest stable release after pulling.
|
- **Note for `stable` Tag Users**: If your `docker-compose.yml` uses the `stable` tag (e.g., `ghcr.io/blakeblackshear/frigate:stable`), you don’t need to update the tag manually. The `stable` tag always points to the latest stable release after pulling.
|
||||||
- If using `docker run`:
|
- If using `docker run`:
|
||||||
- Pull the image with the appropriate tag (e.g., `0.18.1`, `0.18.1-tensorrt`, or `stable`):
|
- Pull the image with the appropriate tag (e.g., `0.18.2`, `0.18.2-tensorrt`, or `stable`):
|
||||||
```bash
|
```bash
|
||||||
docker pull ghcr.io/blakeblackshear/frigate:0.18.1
|
docker pull ghcr.io/blakeblackshear/frigate:0.18.2
|
||||||
```
|
```
|
||||||
|
|
||||||
3. **Start the Container**:
|
3. **Start the Container**:
|
||||||
@@ -100,7 +100,7 @@ If an update causes issues:
|
|||||||
1. Stop Frigate.
|
1. Stop Frigate.
|
||||||
2. Restore your backed-up config file and database.
|
2. Restore your backed-up config file and database.
|
||||||
3. Revert to the previous image version:
|
3. Revert to the previous image version:
|
||||||
- For Docker: Specify an older tag (e.g., `ghcr.io/blakeblackshear/frigate:0.18.0`) in your `docker run` command.
|
- For Docker: Specify an older tag (e.g., `ghcr.io/blakeblackshear/frigate:0.18.1`) in your `docker run` command.
|
||||||
- For Docker Compose: Edit your `docker-compose.yml`, specify the older version tag (e.g., `ghcr.io/blakeblackshear/frigate:0.16.4`), and re-run `docker compose up -d`.
|
- For Docker Compose: Edit your `docker-compose.yml`, specify the older version tag (e.g., `ghcr.io/blakeblackshear/frigate:0.16.4`), and re-run `docker compose up -d`.
|
||||||
- For Home Assistant: Restore from the app/addon backup you took before you updated.
|
- For Home Assistant: Restore from the app/addon backup you took before you updated.
|
||||||
4. Verify the old version is running again.
|
4. Verify the old version is running again.
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ You can view all of your submitted images at [https://plus.frigate.video](https:
|
|||||||
|
|
||||||
Once you have [requested your first model](../plus/first_model.md) and gotten your own model ID, it can be used with a special model path. No other information needs to be configured for Frigate+ models because it fetches the remaining config from Frigate+ automatically.
|
Once you have [requested your first model](../plus/first_model.md) and gotten your own model ID, it can be used with a special model path. No other information needs to be configured for Frigate+ models because it fetches the remaining config from Frigate+ automatically.
|
||||||
|
|
||||||
You can either choose the new model from the <NavPath path="Settings > System > Detectors and model" /> pane in the Frigate UI (the **Frigate+ Model** tab), or manually set the model at the root level in your config:
|
You can either choose the new model from the <NavPath path="Settings > System > Detectors and model" /> pane in the Frigate UI (the **Frigate+** tab), or manually set the model at the root level in your config:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
detectors: ...
|
detectors: ...
|
||||||
|
|||||||
@@ -25,6 +25,12 @@ If you have an active Frigate+ subscription, new uploads will be scanned for the
|
|||||||
|
|
||||||
Suggestions are converted to labels when saving, so you should remove any errant suggestions. There is already some logic designed to avoid duplicate labels, but you may still occasionally see some duplicate suggestions. You should keep the most accurate bounding box and delete any duplicates so that you have just one label per object remaining.
|
Suggestions are converted to labels when saving, so you should remove any errant suggestions. There is already some logic designed to avoid duplicate labels, but you may still occasionally see some duplicate suggestions. You should keep the most accurate bounding box and delete any duplicates so that you have just one label per object remaining.
|
||||||
|
|
||||||
|
## Reviewing annotations with Patches
|
||||||
|
|
||||||
|
The Patches tab on the Images page shows a cropped view of every annotation for a label in a grid. Scanning the crops makes it much easier to spot a mislabeled object than paging through full images one at a time. Pick a label to get started, and optionally narrow the results to a single camera. Clicking a patch opens that image in the editor so you can fix the annotation.
|
||||||
|
|
||||||
|
Patches only include annotations from images you have already verified.
|
||||||
|
|
||||||
## False positive labels
|
## False positive labels
|
||||||
|
|
||||||
False positives will be shown with a red box and the label will have a strike through. These can't be adjusted, but they can be deleted if you accidentally submit a true positive as a false positive from Frigate.
|
False positives will be shown with a red box and the label will have a strike through. These can't be adjusted, but they can be deleted if you accidentally submit a true positive as a false positive from Frigate.
|
||||||
@@ -51,3 +57,12 @@ Misidentified objects should have a correct label added. For example, if a perso
|
|||||||
| `scrollwheel` | Zoom in/out |
|
| `scrollwheel` | Zoom in/out |
|
||||||
| `f` | Hide/show all but current box |
|
| `f` | Hide/show all but current box |
|
||||||
| `spacebar` | Verify and save |
|
| `spacebar` | Verify and save |
|
||||||
|
|
||||||
|
## Deleting images
|
||||||
|
|
||||||
|
In most cases, you should keep your existing images. Removing training data usually makes accuracy worse, not better, so you shouldn't delete images just because you think you made some annotation mistakes. Deleting images makes sense when you move to a new location, or significantly upgrade or reposition your cameras.
|
||||||
|
|
||||||
|
- To delete all images for a camera, use the **Delete Images** button for that camera on the Cameras page.
|
||||||
|
- To delete all images in your account, use **Delete All Images** on the Settings page.
|
||||||
|
|
||||||
|
Deletions run in the background, and their progress is shown in the bulk operations panel. Deleted images cannot be recovered and are no longer used to train your models.
|
||||||
|
|||||||
@@ -26,7 +26,9 @@ Yes. Subscriptions to Frigate+ provide access to the infrastructure used to trai
|
|||||||
### Can I use Frigate+ models commercially?
|
### Can I use Frigate+ models commercially?
|
||||||
|
|
||||||
A standard subscription covers use on camera systems you own or operate, including for your business. A shop, restaurant, warehouse, or office running Frigate+ at its own locations (including multiple locations) is exactly the kind of use the subscription is for.
|
A standard subscription covers use on camera systems you own or operate, including for your business. A shop, restaurant, warehouse, or office running Frigate+ at its own locations (including multiple locations) is exactly the kind of use the subscription is for.
|
||||||
|
|
||||||
What the standard subscription does not cover is using Frigate+ models to provide a product or service to others. If you're deploying models at your customers' sites, bundling them with hardware you sell, or running them as part of a hosted or managed service, even if your customers never receive the model files themselves, you'll need a commercial license.
|
What the standard subscription does not cover is using Frigate+ models to provide a product or service to others. If you're deploying models at your customers' sites, bundling them with hardware you sell, or running them as part of a hosted or managed service, even if your customers never receive the model files themselves, you'll need a commercial license.
|
||||||
|
|
||||||
Note that professional installers are fine under standard subscriptions when each customer holds their own Frigate+ subscription. The commercial license is for cases where your license powers your customers' sites.
|
Note that professional installers are fine under standard subscriptions when each customer holds their own Frigate+ subscription. The commercial license is for cases where your license powers your customers' sites.
|
||||||
|
|
||||||
### Why can't I submit images to Frigate+?
|
### Why can't I submit images to Frigate+?
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ For more detailed recommendations, you can refer to the docs on [annotating](./a
|
|||||||
|
|
||||||
## Step 2: Submit a model request
|
## Step 2: Submit a model request
|
||||||
|
|
||||||
Once you have an initial set of verified images, you can request a model on the Models page. For guidance on choosing a model type, refer to [this part of the documentation](./index.md#available-model-types). If you are unsure which type to request, you can test the base model for each version from the "Base Models" tab. Each model request requires 1 of the 12 trainings that you receive with your annual subscription. This model will support all [label types available](./index.md#available-label-types) even if you do not submit any examples for those labels. Model creation can take up to 36 hours.
|
Once you have an initial set of verified images, you can request a model on the Models page. For guidance on choosing a model type, refer to [this part of the documentation](./index.md#available-model-types). If you are unsure which type to request, you can test the base model for each version from the "Base Models" tab. For most hardware, `yolov9` is recommended; `mobiledet` is a legacy model type and will be removed in 2027. Each model request requires 1 of the 12 trainings that you receive with your annual subscription. This model will support all [label types available](./index.md#available-label-types) even if you do not submit any examples for those labels. Model creation can take up to 36 hours.
|
||||||

|

|
||||||
|
|
||||||
## Step 3: Set your model
|
## Step 3: Set your model
|
||||||
|
|||||||
+15
-9
@@ -5,25 +5,31 @@ title: Models
|
|||||||
|
|
||||||
<a href="https://frigate.video/plus" target="_blank" rel="nofollow">Frigate+</a> offers models trained on images submitted by Frigate+ users from their security cameras and is specifically designed for the way Frigate NVR analyzes video footage. These models offer higher accuracy with less resources. The images you upload are used to fine tune a base model trained from images uploaded by all Frigate+ users. This fine tuning process results in a model that is optimized for accuracy in your specific conditions.
|
<a href="https://frigate.video/plus" target="_blank" rel="nofollow">Frigate+</a> offers models trained on images submitted by Frigate+ users from their security cameras and is specifically designed for the way Frigate NVR analyzes video footage. These models offer higher accuracy with less resources. The images you upload are used to fine tune a base model trained from images uploaded by all Frigate+ users. This fine tuning process results in a model that is optimized for accuracy in your specific conditions.
|
||||||
|
|
||||||
With a subscription, 12 model trainings to fine tune your model per year are included. In addition, you will have access to any base models published while your subscription is active. If you cancel your subscription, you will retain access to any trained and base models in your account. An active subscription is required to submit model requests or purchase additional trainings. New base models are published quarterly with target dates of January 15th, April 15th, July 15th, and October 15th.
|
With a subscription, 12 model trainings to fine tune your model per year are included. In addition, you will have access to any base models published while your subscription is active. If you cancel your subscription, you will retain access to any trained and base models in your account. An active subscription is required to submit model requests or purchase additional trainings. New base models are published twice per year.
|
||||||
|
|
||||||
Information on how to integrate Frigate+ with Frigate can be found in the [integration docs](../integrations/plus.md).
|
Information on how to integrate Frigate+ with Frigate can be found in the [integration docs](../integrations/plus.md).
|
||||||
|
|
||||||
## Available model types
|
## Available model types
|
||||||
|
|
||||||
There are three model types offered in Frigate+, `mobiledet`, `yolonas`, and `yolov9`. All of these models are object detection models and are trained to detect the same set of labels [listed below](#available-label-types).
|
There are three model types offered in Frigate+, `yolov9`, `yolonas`, and `mobiledet` (legacy). All of these models are object detection models and are trained to detect the same set of labels [listed below](#available-label-types).
|
||||||
|
|
||||||
Not all model types are supported by all detectors, so it's important to choose a model type to match your detector as shown in the table under [supported detector types](#supported-detector-types). You can test model types for compatibility and speed on your hardware by using the base models.
|
Not all model types are supported by all detectors, so it's important to choose a model type to match your detector as shown in the table under [supported detector types](#supported-detector-types). You can test model types for compatibility and speed on your hardware by using the base models.
|
||||||
|
|
||||||
| Model Type | Description |
|
| Model Type | Description |
|
||||||
| ----------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
| ----------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||||
| `mobiledet` | Based on the same architecture as the default model included with Frigate. Runs on Google Coral devices and CPUs. |
|
|
||||||
| `yolonas` | A newer architecture that offers slightly higher accuracy and improved detection of small objects. Runs on Intel, NVidia GPUs, and AMD GPUs. |
|
|
||||||
| `yolov9` | A leading SOTA (state of the art) object detection model with similar performance to yolonas, but on a wider range of hardware options. Runs on most hardware. |
|
| `yolov9` | A leading SOTA (state of the art) object detection model with similar performance to yolonas, but on a wider range of hardware options. Runs on most hardware. |
|
||||||
|
| `yolonas` | A newer architecture that offers slightly higher accuracy and improved detection of small objects. Runs on Intel, NVidia GPUs, and AMD GPUs. |
|
||||||
|
| `mobiledet` | Legacy. Based on the same architecture as the default model included with Frigate. Runs on Google Coral devices and CPUs. |
|
||||||
|
|
||||||
|
:::warning
|
||||||
|
|
||||||
|
`mobiledet` is a legacy model type. Base model 2026.3 is the last base model update for `mobiledet`, and it is planned to be removed from Frigate+ in 2027. If you are using `mobiledet` with a Google Coral, request a `yolov9` model with the `edgetpu` variant instead.
|
||||||
|
|
||||||
|
:::
|
||||||
|
|
||||||
### YOLOv9 Details
|
### YOLOv9 Details
|
||||||
|
|
||||||
YOLOv9 models are available in `s`, `t`, `edgetpu` variants. When requesting a `yolov9` model, you will be prompted to choose a variant. If you want the model to be compatible with a Google Coral, you will need to choose the `edgetpu` variant. If you are unsure what variant to choose, you should perform some tests with the base models to find the performance level that suits you. The `s` size is most similar to the current `yolonas` models in terms of inference times and accuracy, and a good place to start is the `320x320` resolution model for `yolov9s`.
|
YOLOv9 models are available in `t`, `s`, `c`, and `edgetpu` variants, and an `m` size is coming soon. When requesting a `yolov9` model, you will be prompted to choose a variant. If you want the model to be compatible with a Google Coral, you will need to choose the `edgetpu` variant, which requires Frigate 0.17 or later. If you are unsure what variant to choose, you should perform some tests with the base models to find the performance level that suits you. The `s` size is most similar to the current `yolonas` models in terms of inference times and accuracy, and a good place to start is the `320x320` resolution model for `yolov9s`. The `c` size is larger and offers higher accuracy at the cost of slower inference, so it is best suited to more powerful hardware such as GPUs.
|
||||||
|
|
||||||
:::info
|
:::info
|
||||||
|
|
||||||
@@ -33,7 +39,7 @@ When switching to YOLOv9, you may need to adjust your thresholds for some object
|
|||||||
|
|
||||||
#### Hailo Support
|
#### Hailo Support
|
||||||
|
|
||||||
If you have a Hailo device, you will need to specify the hardware you have when submitting a model request because they are not cross compatible. Please test using the available base models before submitting your model request.
|
If you have a Hailo device, you will need to specify the hardware you have when submitting a model request because they are not cross compatible. Hailo models are available for the `t`, `s`, and `c` variants on Hailo8, Hailo8L, and Hailo8R devices. Please test using the available base models before submitting your model request.
|
||||||
|
|
||||||
#### Rockchip (RKNN) Support
|
#### Rockchip (RKNN) Support
|
||||||
|
|
||||||
@@ -45,7 +51,7 @@ Currently, Frigate+ models support CPU (`cpu`), Google Coral (`edgetpu`), OpenVi
|
|||||||
|
|
||||||
| Hardware | Recommended Detector Type | Recommended Model Type |
|
| Hardware | Recommended Detector Type | Recommended Model Type |
|
||||||
| -------------------------------------------------------------------------------- | ------------------------- | ---------------------- |
|
| -------------------------------------------------------------------------------- | ------------------------- | ---------------------- |
|
||||||
| [CPU](/configuration/object_detectors.md#cpu-detector-not-recommended) | `cpu` | `mobiledet` |
|
| [CPU](/configuration/object_detectors.md#cpu-detector-not-recommended) | `cpu` | `yolov9` |
|
||||||
| [Coral (all form factors)](/configuration/object_detectors.md#edge-tpu-detector) | `edgetpu` | `yolov9` |
|
| [Coral (all form factors)](/configuration/object_detectors.md#edge-tpu-detector) | `edgetpu` | `yolov9` |
|
||||||
| [Intel](/configuration/object_detectors.md#openvino-detector) | `openvino` | `yolov9` |
|
| [Intel](/configuration/object_detectors.md#openvino-detector) | `openvino` | `yolov9` |
|
||||||
| [NVidia GPU](/configuration/object_detectors#onnx) | `onnx` | `yolov9` |
|
| [NVidia GPU](/configuration/object_detectors#onnx) | `onnx` | `yolov9` |
|
||||||
@@ -66,7 +72,7 @@ Some users may find that Frigate+ models result in more false positives initiall
|
|||||||
Frigate+ models support a more relevant set of objects for security cameras. The labels for annotation in Frigate+ are configurable by editing the camera in the Cameras section of Frigate+. Currently, the following objects are supported:
|
Frigate+ models support a more relevant set of objects for security cameras. The labels for annotation in Frigate+ are configurable by editing the camera in the Cameras section of Frigate+. Currently, the following objects are supported:
|
||||||
|
|
||||||
- **People**: `person`, `face`, `baby`
|
- **People**: `person`, `face`, `baby`
|
||||||
- **Vehicles**: `car`, `motorcycle`, `bicycle`, `boat`, `school_bus`, `garbage truck`, `license_plate`
|
- **Vehicles**: `car`, `motorcycle`, `bicycle`, `boat`, `school_bus`, `garbage_truck`, `license_plate`
|
||||||
- **Delivery Logos**: `amazon`, `usps`, `ups`, `fedex`, `dhl`, `an_post`, `purolator`, `postnl`, `nzpost`, `postnord`, `gls`, `dpd`, `canada_post`, `royal_mail`
|
- **Delivery Logos**: `amazon`, `usps`, `ups`, `fedex`, `dhl`, `an_post`, `purolator`, `postnl`, `nzpost`, `postnord`, `gls`, `dpd`, `canada_post`, `royal_mail`
|
||||||
- **Animals**: `dog`, `cat`, `deer`, `horse`, `bird`, `raccoon`, `fox`, `bear`, `cow`, `squirrel`, `goat`, `rabbit`, `skunk`, `kangaroo`, `possum`, `rodent`
|
- **Animals**: `dog`, `cat`, `deer`, `horse`, `bird`, `raccoon`, `fox`, `bear`, `cow`, `squirrel`, `goat`, `rabbit`, `skunk`, `kangaroo`, `possum`, `rodent`
|
||||||
- **Other**: `package`, `waste_bin`, `bbq_grill`, `robot_lawnmower`, `umbrella`, `baby_stroller`
|
- **Other**: `package`, `waste_bin`, `bbq_grill`, `robot_lawnmower`, `umbrella`, `baby_stroller`
|
||||||
@@ -81,7 +87,7 @@ Where possible, these labels are mapped to existing labels during training. For
|
|||||||
|
|
||||||
- **Vehicles**: `tractor`, `golf_cart`, `bus`, `airplane`, `helicopter`, `rickshaw`, `scooter`
|
- **Vehicles**: `tractor`, `golf_cart`, `bus`, `airplane`, `helicopter`, `rickshaw`, `scooter`
|
||||||
- **Delivery Logos**: `bpost`, `auspost`, `aramex`, `transoflex`, `parcelforce`, `hermes`, `cargus`, `fan_courier`, `sameday`, `la_poste`
|
- **Delivery Logos**: `bpost`, `auspost`, `aramex`, `transoflex`, `parcelforce`, `hermes`, `cargus`, `fan_courier`, `sameday`, `la_poste`
|
||||||
- **Animals**: `badger`, `chicken`, `duck`, `turkey`, `groundhog`, `boar`, `hedgehog`, `wombat`, `bobcat`, `mustelid`, `mountain_lion`, `crocodile`, `monkey`, `coyote`, `porcupine`, `sheep`, `snake`, `lizard`, `heron`, `elk`, `moose`, `pig`, `donkey`, `civet`
|
- **Animals**: `badger`, `chicken`, `duck`, `turkey`, `groundhog`, `boar`, `hedgehog`, `wombat`, `bobcat`, `mustelid`, `mountain_lion`, `crocodile`, `monkey`, `coyote`, `porcupine`, `sheep`, `snake`, `lizard`, `heron`, `elk`, `moose`, `pig`, `donkey`, `civet`, `chipmunk`
|
||||||
- **Other**: `sports_ball`, `drone`, `lawnmower`
|
- **Other**: `sports_ball`, `drone`, `lawnmower`
|
||||||
|
|
||||||
Candidate labels are not available for automatic suggestions.
|
Candidate labels are not available for automatic suggestions.
|
||||||
|
|||||||
@@ -162,7 +162,7 @@ Open one of the tracked objects in Explore → **Tracking Details**. If the dete
|
|||||||
What helps:
|
What helps:
|
||||||
|
|
||||||
- **Improve the view**: even a small angle change that gets more of the car visible could lift scores enough to stabilize tracking.
|
- **Improve the view**: even a small angle change that gets more of the car visible could lift scores enough to stabilize tracking.
|
||||||
- **Use a more accurate model**: switching from `mobiledet` to `yolov9`, or stepping up to a larger variant like `yolov9-s` over `yolov9-t`, can help (at the cost of inference time, and still on the COCO dataset). The biggest gains usually come from fine-tuning a model on images from your own cameras so it learns your specific scene. [Frigate+](https://frigate.video/plus) is a paid option that does this - models are trained on security-camera footage and can be fine-tuned on images you submit from your own setup.
|
- **Use a more accurate model**: switching from `mobiledet` to `yolov9`, or stepping up to a larger variant like `yolov9-s` over `yolov9-t` (or `yolov9-c` on more powerful hardware), can help (at the cost of inference time, and still on the COCO dataset). The biggest gains usually come from fine-tuning a model on images from your own cameras so it learns your specific scene. [Frigate+](https://frigate.video/plus) is a paid option that does this - models are trained on security-camera footage and can be fine-tuned on images you submit from your own setup.
|
||||||
- **Don't set `detect -> stationary -> max_frames` for `car`**: it artificially ends tracking and forces re-detection as a new object. See [Stationary Objects](../configuration/stationary_objects.md).
|
- **Don't set `detect -> stationary -> max_frames` for `car`**: it artificially ends tracking and forces re-detection as a new object. See [Stationary Objects](../configuration/stationary_objects.md).
|
||||||
- **Restrict alerts to the areas you care about** with `required_zones`. See [Zones](../configuration/zones.md#restricting-alerts-and-detections-to-specific-zones). Make sure those zones use the default `loitering_time: 0` unless you specifically want the review item to stay open until the car leaves.
|
- **Restrict alerts to the areas you care about** with `required_zones`. See [Zones](../configuration/zones.md#restricting-alerts-and-detections-to-specific-zones). Make sure those zones use the default `loitering_time: 0` unless you specifically want the review item to stay open until the car leaves.
|
||||||
- **Filter impossible locations** with [object filter masks](../configuration/masks.md#object-filter-masks) if cars are being detected on rooftops, treetops, etc.
|
- **Filter impossible locations** with [object filter masks](../configuration/masks.md#object-filter-masks) if cars are being detected on rooftops, treetops, etc.
|
||||||
|
|||||||
+5
-34
@@ -11,7 +11,7 @@ import secrets
|
|||||||
import time
|
import time
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from urllib.parse import parse_qs, unquote
|
from urllib.parse import parse_qs
|
||||||
|
|
||||||
import requests
|
import requests
|
||||||
from fastapi import APIRouter, Depends, HTTPException, Request, Response
|
from fastapi import APIRouter, Depends, HTTPException, Request, Response
|
||||||
@@ -31,6 +31,8 @@ from frigate.api.media_auth import (
|
|||||||
check_camera_access,
|
check_camera_access,
|
||||||
deny_response_for_media_uri,
|
deny_response_for_media_uri,
|
||||||
is_role_restricted,
|
is_role_restricted,
|
||||||
|
normalize_request_path,
|
||||||
|
split_request_uri,
|
||||||
)
|
)
|
||||||
from frigate.config import AuthConfig, ProxyConfig
|
from frigate.config import AuthConfig, ProxyConfig
|
||||||
from frigate.const import CONFIG_DIR, JWT_SECRET_ENV_VAR, PASSWORD_HASH_ALGORITHM
|
from frigate.const import CONFIG_DIR, JWT_SECRET_ENV_VAR, PASSWORD_HASH_ALGORITHM
|
||||||
@@ -1185,37 +1187,6 @@ GO2RTC_STREAM_PROXY_PATHS = frozenset(
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
_URI_SCHEME_AND_AUTHORITY = re.compile(r"^[A-Za-z][A-Za-z0-9+.-]*://[^/?]*")
|
|
||||||
|
|
||||||
|
|
||||||
def _split_request_uri(request_uri: str) -> tuple[str, str]:
|
|
||||||
"""Split a raw request URI into its path and query string.
|
|
||||||
|
|
||||||
urlparse is not used since it reads a path starting with `//` as a host.
|
|
||||||
"""
|
|
||||||
uri = _URI_SCHEME_AND_AUTHORITY.sub("", request_uri, count=1)
|
|
||||||
path, _, query = uri.partition("?")
|
|
||||||
return path, query
|
|
||||||
|
|
||||||
|
|
||||||
def _normalize_request_path(path: str) -> str:
|
|
||||||
"""Normalize a raw request path the way nginx does before matching locations.
|
|
||||||
|
|
||||||
nginx percent-decodes the path, merges repeated slashes and resolves dot
|
|
||||||
segments, while `X-Original-URL` carries the raw `$request_uri`.
|
|
||||||
"""
|
|
||||||
segments: list[str] = []
|
|
||||||
for segment in unquote(path).split("/"):
|
|
||||||
if segment in ("", "."):
|
|
||||||
continue
|
|
||||||
if segment == "..":
|
|
||||||
if segments:
|
|
||||||
segments.pop()
|
|
||||||
continue
|
|
||||||
segments.append(segment)
|
|
||||||
|
|
||||||
return "/" + "/".join(segments)
|
|
||||||
|
|
||||||
|
|
||||||
def _is_go2rtc_stream_proxy_request(path: str, request: Request) -> bool:
|
def _is_go2rtc_stream_proxy_request(path: str, request: Request) -> bool:
|
||||||
# nginx marks requests routed through the go2rtc stream locations, and the
|
# nginx marks requests routed through the go2rtc stream locations, and the
|
||||||
@@ -1223,7 +1194,7 @@ def _is_go2rtc_stream_proxy_request(path: str, request: Request) -> bool:
|
|||||||
if request.headers.get("x-go2rtc-stream-proxy") == "1":
|
if request.headers.get("x-go2rtc-stream-proxy") == "1":
|
||||||
return True
|
return True
|
||||||
|
|
||||||
normalized = _normalize_request_path(path)
|
normalized = normalize_request_path(path)
|
||||||
return any(normalized.startswith(p) for p in GO2RTC_STREAM_PROXY_PATHS)
|
return any(normalized.startswith(p) for p in GO2RTC_STREAM_PROXY_PATHS)
|
||||||
|
|
||||||
|
|
||||||
@@ -1242,7 +1213,7 @@ def deny_response_for_go2rtc_stream(
|
|||||||
if not original_url:
|
if not original_url:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
path, query = _split_request_uri(original_url)
|
path, query = split_request_uri(original_url)
|
||||||
if not _is_go2rtc_stream_proxy_request(path, request):
|
if not _is_go2rtc_stream_proxy_request(path, request):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|||||||
+42
-10
@@ -13,8 +13,9 @@ from __future__ import annotations
|
|||||||
|
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
|
import re
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
from urllib.parse import unquote, urlparse
|
from urllib.parse import unquote
|
||||||
|
|
||||||
from peewee import DoesNotExist
|
from peewee import DoesNotExist
|
||||||
|
|
||||||
@@ -24,6 +25,8 @@ from frigate.models import Export, User
|
|||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
_URI_SCHEME_AND_AUTHORITY = re.compile(r"^[A-Za-z][A-Za-z0-9+.-]*://[^/?]*")
|
||||||
|
|
||||||
|
|
||||||
class MediaAuthResolution(str, Enum):
|
class MediaAuthResolution(str, Enum):
|
||||||
"""Classification of an `X-Original-URL` path for media-auth purposes."""
|
"""Classification of an `X-Original-URL` path for media-auth purposes."""
|
||||||
@@ -41,6 +44,36 @@ class MediaAuthResolution(str, Enum):
|
|||||||
UNKNOWN = "unknown"
|
UNKNOWN = "unknown"
|
||||||
|
|
||||||
|
|
||||||
|
def split_request_uri(request_uri: str) -> tuple[str, str]:
|
||||||
|
"""Split a raw request URI into its path and query string.
|
||||||
|
|
||||||
|
urlparse is not used since it reads a path starting with `//` as a host.
|
||||||
|
nginx ends the URI at a literal `#`, so anything after it is dropped.
|
||||||
|
"""
|
||||||
|
uri = _URI_SCHEME_AND_AUTHORITY.sub("", request_uri, count=1)
|
||||||
|
path, _, query = uri.partition("#")[0].partition("?")
|
||||||
|
return path, query
|
||||||
|
|
||||||
|
|
||||||
|
def normalize_request_path(path: str) -> str:
|
||||||
|
"""Normalize a raw request path the way nginx does before matching locations.
|
||||||
|
|
||||||
|
nginx percent-decodes the path, merges repeated slashes and resolves dot
|
||||||
|
segments, while `X-Original-URL` carries the raw `$request_uri`.
|
||||||
|
"""
|
||||||
|
segments: list[str] = []
|
||||||
|
for segment in unquote(path).split("/"):
|
||||||
|
if segment in ("", "."):
|
||||||
|
continue
|
||||||
|
if segment == "..":
|
||||||
|
if segments:
|
||||||
|
segments.pop()
|
||||||
|
continue
|
||||||
|
segments.append(segment)
|
||||||
|
|
||||||
|
return "/" + "/".join(segments)
|
||||||
|
|
||||||
|
|
||||||
def extract_path(original_url: str | None) -> str | None:
|
def extract_path(original_url: str | None) -> str | None:
|
||||||
"""Return the decoded path component of nginx's `X-Original-URL` header.
|
"""Return the decoded path component of nginx's `X-Original-URL` header.
|
||||||
|
|
||||||
@@ -49,14 +82,14 @@ def extract_path(original_url: str | None) -> str | None:
|
|||||||
request like `/recordings/.../allowed_cam/../forbidden_cam/file.mp4`
|
request like `/recordings/.../allowed_cam/../forbidden_cam/file.mp4`
|
||||||
would (1) parse as the allowed camera in our auth check, (2) be served
|
would (1) parse as the allowed camera in our auth check, (2) be served
|
||||||
as the forbidden camera by nginx. To close the bypass we reject any URI
|
as the forbidden camera by nginx. To close the bypass we reject any URI
|
||||||
whose path contains `.` or `..` segments outright.
|
whose path contains `.` or `..` segments outright. Repeated slashes are
|
||||||
|
merged, as nginx does before matching locations.
|
||||||
"""
|
"""
|
||||||
if not original_url:
|
if not original_url:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
parsed = urlparse(original_url)
|
path, _ = split_request_uri(original_url)
|
||||||
raw_path = parsed.path or original_url
|
decoded = re.sub(r"/{2,}", "/", unquote(path))
|
||||||
decoded = unquote(raw_path)
|
|
||||||
if not decoded:
|
if not decoded:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@@ -252,12 +285,11 @@ def deny_response_for_media_uri(
|
|||||||
path = extract_path(original_url)
|
path = extract_path(original_url)
|
||||||
|
|
||||||
# `extract_path` returns None for URIs containing `.` or `..` segments.
|
# `extract_path` returns None for URIs containing `.` or `..` segments.
|
||||||
# For media-root URIs that's a traversal attempt — deny outright. For
|
# Deny them when nginx would resolve them under a media root, and pass
|
||||||
# non-media URIs, pass through (nginx / the backend handle them).
|
# the rest through to nginx and the backend.
|
||||||
if path is None:
|
if path is None:
|
||||||
raw = urlparse(original_url).path or original_url
|
normalized = normalize_request_path(split_request_uri(original_url)[0])
|
||||||
decoded = unquote(raw)
|
first = normalized.lstrip("/").split("/", 1)[0]
|
||||||
first = decoded.lstrip("/").split("/", 1)[0] if decoded else ""
|
|
||||||
if first in ("clips", "recordings", "exports"):
|
if first in ("clips", "recordings", "exports"):
|
||||||
return 403
|
return 403
|
||||||
return None
|
return None
|
||||||
|
|||||||
@@ -76,6 +76,20 @@ class TestExtractPath(unittest.TestCase):
|
|||||||
self.assertIsNone(extract_path(None))
|
self.assertIsNone(extract_path(None))
|
||||||
self.assertIsNone(extract_path(""))
|
self.assertIsNone(extract_path(""))
|
||||||
|
|
||||||
|
def test_leading_double_slash_is_path(self):
|
||||||
|
self.assertEqual(
|
||||||
|
extract_path("//clips/front_door-1.jpg"), "/clips/front_door-1.jpg"
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_repeated_slashes_merged(self):
|
||||||
|
self.assertEqual(
|
||||||
|
extract_path("/recordings//2026-05-11/14//front_door/00.00.mp4"),
|
||||||
|
"/recordings/2026-05-11/14/front_door/00.00.mp4",
|
||||||
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
extract_path("/%2Fclips/front_door-1.jpg"), "/clips/front_door-1.jpg"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class TestResolveMediaUri(unittest.TestCase):
|
class TestResolveMediaUri(unittest.TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
@@ -376,6 +390,34 @@ class TestDenyResponseForMediaUri(unittest.TestCase):
|
|||||||
self.assertIsNone(self._deny("/clips/nonexistent-1.jpg", "admin"))
|
self.assertIsNone(self._deny("/clips/nonexistent-1.jpg", "admin"))
|
||||||
self.assertIsNone(self._deny("/clips/nonexistent-1.jpg", "viewer"))
|
self.assertIsNone(self._deny("/clips/nonexistent-1.jpg", "viewer"))
|
||||||
|
|
||||||
|
def test_repeated_slashes_resolve_to_owning_camera(self):
|
||||||
|
# nginx merges repeated slashes before matching the media locations
|
||||||
|
for url in (
|
||||||
|
"//clips/back_door-1.jpg",
|
||||||
|
"/clips//back_door-1.jpg",
|
||||||
|
"//recordings/2026-05-11/14/back_door/00.00.mp4",
|
||||||
|
"/recordings//2026-05-11/14/back_door/00.00.mp4",
|
||||||
|
):
|
||||||
|
self.assertEqual(self._deny(url, "limited_user"), 403, url)
|
||||||
|
self.assertIsNone(self._deny("//clips/front_door-1.jpg", "limited_user"))
|
||||||
|
|
||||||
|
def test_traversal_with_leading_double_slash_denied(self):
|
||||||
|
self.assertEqual(
|
||||||
|
self._deny("//clips/front_door/../back_door-1.jpg", "admin"), 403
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_traversal_from_non_media_prefix_denied(self):
|
||||||
|
# nginx resolves these into a media root before serving
|
||||||
|
for url in (
|
||||||
|
"/x/../clips/back_door-1.jpg",
|
||||||
|
"/x/%2E%2E/clips/back_door-1.jpg",
|
||||||
|
"/./clips/front_door/../back_door-1.jpg",
|
||||||
|
"/api/../recordings/2026-05-11/14/back_door/00.00.mp4",
|
||||||
|
"/clips/back_door-1.jpg#/../../x",
|
||||||
|
):
|
||||||
|
self.assertEqual(self._deny(url, "limited_user"), 403, url)
|
||||||
|
self.assertIsNone(self._deny("/x/../api/events", "limited_user"))
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|||||||
Reference in New Issue
Block a user