# How Frigate Motion Detection Determines Where to Run AI Object Detection

> Learn how Frigate's motion detection efficiently directs AI object detection to specific areas, minimizing computational load and boosting performance by focusing on relevant frame regions.

- Repository: [Blake Blackshear/frigate](https://github.com/blakeblackshear/frigate)
- Tags: internals
- Published: 2026-05-25

---

**Frigate uses motion detection as a lightweight pre-filter to generate targeted bounding boxes that dictate exactly which regions of a video frame are sent to the AI object detector, dramatically reducing computational overhead by avoiding full-frame analysis.**

Frigate is an open-source network video recorder (NVR) designed for real-time AI object detection using computer vision. According to the Frigate source code, the system relies on a sophisticated **motion-to-AI pipeline** orchestrated by the `CameraTracker` process in [`frigate/video/detect.py`](https://github.com/blakeblackshear/frigate/blob/main/frigate/video/detect.py). This architecture ensures that resource-intensive object detection runs only on areas where motion has actually occurred, optimizing CPU and GPU utilization for continuous video surveillance.

## The Motion-to-AI Pipeline Overview

The workflow connecting motion detection to AI inference operates as a six-stage filter. First, the motion detector identifies changed pixels. Next, the system excludes stationary objects and builds regions from currently tracked objects. Crucially, it then adds **motion-only regions**—areas with motion that do not overlap existing tracked objects. Finally, the AI detector processes only these specific regions, skipping the rest of the frame entirely.

This region-based approach means that if motion occurs in only 10% of the frame, the AI model processes just that 10%, not the full 1920x1080 image.

## Step 1: Detecting Motion with ImprovedMotionDetector

For every incoming frame, Frigate invokes the `ImprovedMotionDetector` (a subclass of `MotionDetector`) to identify areas of change. This happens at line 302 of [`detect.py`](https://github.com/blakeblackshear/frigate/blob/main/detect.py):

```python
motion_boxes = motion_detector.detect(frame)   # detect.py L302-L304

```

The detector implements frame differencing, contrast improvement, masking, and contour analysis in [`frigate/motion/improved_motion.py`](https://github.com/blakeblackshear/frigate/blob/main/frigate/motion/improved_motion.py) (lines 54-62 and 122-155). It returns a list of bounding boxes (`motion_boxes`) containing movement, or an empty list if motion detection is disabled.

## Step 2: Filtering Stationary Objects

Before processing motion boxes, Frigate identifies **stationary objects**—objects that have remained static longer than the configured `stationary_threshold`. These objects are excluded from motion-based region generation because they are handled by a separate tracking mechanism. This filtering occurs only when the detector is not in a calibrating state.

## Step 3: Building Regions from Tracked Objects

The system first creates detection regions based on existing tracked objects. In [`detect.py`](https://github.com/blakeblackshear/frigate/blob/main/detect.py) (lines 350-358), Frigate gathers bounding boxes of all non-stationary tracked objects into `tracked_object_boxes`. These boxes are clustered using `get_cluster_candidates()` and converted into rectangular **regions** via `get_cluster_region()`:

```python
regions = [
    get_cluster_region(
        frame_shape,
        get_min_region_size(model_config),
        candidate,
        tracked_object_boxes,
    )
    for candidate in get_cluster_candidates(
        frame_shape,
        get_min_region_size(model_config),
        tracked_object_boxes,
    )
]

```

These object-derived regions ensure that the AI continues to track objects even when they temporarily stop moving.

## Step 4: Adding Motion-Only Regions

This is the critical step where motion detection directly determines AI execution boundaries. If the detector is not calibrating and the PTZ camera is not moving, Frigate searches for motion boxes that do **not** intersect any existing object regions using the `inside_any()` helper function.

In [`detect.py`](https://github.com/blakeblackshear/frigate/blob/main/detect.py) (lines 360-388), these "stand-alone" motion boxes are clustered and converted into additional regions:

```python
if not motion_detector.is_calibrating() and not ptz_moving_at_frame_time(...):
    stand_alone = [b for b in motion_boxes if not inside_any(b, regions)]
    if stand_alone:
        motion_clusters = get_cluster_candidates(
            frame_shape,
            get_min_region_size(model_config),
            stand_alone
        )
        motion_regions = [
            get_cluster_region_from_grid(
                frame_shape,
                get_min_region_size(model_config),
                cand,
                stand_alone,
                region_grid
            )
            for cand in motion_clusters
        ]
        regions += motion_regions

```

Only these motion-only regions trigger new AI detection for previously untracked objects.

## Step 5: Running AI Detection on Region Subsets

The final region set—combining object-derived regions and motion-only regions—determines exactly where AI inference occurs. In [`detect.py`](https://github.com/blakeblackshear/frigate/blob/main/detect.py) (lines 13-24), Frigate iterates through each region and runs the object detector only on those specific bounding boxes:

```python
for region in regions:
    detections.extend(
        detect(
            camera_config.detect,
            object_detector,
            frame,
            model_config,
            region,
            camera_config.objects.track,
            camera_config.objects.filters,
        )
    )

```

Only pixels inside these regions are ever fed to the AI model, reducing compute load by 80-90% in typical scenarios where motion is localized.

## Calibration and PTZ Movement Guards

Frigate implements safeguards to prevent false positives during unstable conditions. When `motion_detector.is_calibrating()` returns `True`—such as after sudden lighting changes or during initialization—the system skips both motion-only region generation and AI detection for that frame (lines 60-73 in [`improved_motion.py`](https://github.com/blakeblackshear/frigate/blob/main/improved_motion.py) and lines 360-368 in [`detect.py`](https://github.com/blakeblackshear/frigate/blob/main/detect.py)).

Similarly, if PTZ movement is detected at the frame timestamp via `ptz_moving_at_frame_time()`, motion detection returns early with a full-frame box or empty list, preventing errant detections during camera repositioning.

## Configuration and Key Files

The motion detection and region generation logic spans several critical files in the Frigate repository:

- **[`frigate/motion/improved_motion.py`](https://github.com/blakeblackshear/frigate/blob/main/frigate/motion/improved_motion.py)** – Implements the motion detection algorithm, background subtraction, calibration logic, and contrast handling.
- **[`frigate/video/detect.py`](https://github.com/blakeblackshear/frigate/blob/main/frigate/video/detect.py)** – Orchestrates the frame processing pipeline, converts motion boxes to regions, and manages the AI detection loop.
- **[`frigate/util/object.py`](https://github.com/blakeblackshear/frigate/blob/main/frigate/util/object.py)** – Provides clustering utilities including `get_cluster_candidates`, `get_cluster_region`, and `inside_any` for merging overlapping boxes.
- **[`frigate/config/camera/motion.py`](https://github.com/blakeblackshear/frigate/blob/main/frigate/config/camera/motion.py)** – Contains configurable parameters including motion threshold, contour area minimums, and mask definitions that control detector sensitivity.

## Summary

- **Motion detection acts as a gatekeeper:** The `ImprovedMotionDetector` identifies changed areas before any AI processing occurs.
- **Regions determine AI boundaries:** Frigate creates rectangular regions from both tracked objects and stand-alone motion boxes, running detection only within these boundaries.
- **Stand-alone motion triggers new detection:** Motion boxes that do not intersect existing object regions (`inside_any` check) generate new AI detection zones.
- **Calibration guards prevent errors:** When `is_calibrating()` is true or during PTZ movement, motion-based region generation is suspended to allow background model stabilization.
- **Dramatic compute savings:** By processing only motion-derived regions rather than full frames, Frigate reduces AI inference workload by focusing compute on relevant image areas.

## Frequently Asked Questions

### What happens when the motion detector is calibrating?

When the motion detector enters a calibrating state—typically after sudden lighting changes or during camera initialization—the `is_calibrating()` method returns `True`. In this state, Frigate skips the creation of motion-only regions and may skip AI detection entirely for that frame, allowing the background subtraction model to stabilize and preventing false object detections from transient environmental changes.

### How does Frigate handle motion from PTZ camera movements?

Frigate checks for PTZ movement using `ptz_moving_at_frame_time()` before processing motion boxes. If the camera is currently panning, tilting, or zooming, the system either returns an empty motion list or a full-frame bounding box, depending on the calibration state. This prevents the AI detector from generating false positive detections based on the background motion caused by camera repositioning.

### Why doesn't Frigate run AI detection on the entire frame?

Running AI object detection on full-resolution video frames is computationally expensive and would overwhelm most consumer hardware. By using lightweight motion detection as a pre-filter, Frigate identifies only the regions containing potential activity (typically 5-15% of the frame) and constrains AI inference to those specific areas. This approach enables real-time processing on edge devices like Raspberry Pi or low-power NUCs without sacrificing detection accuracy.

### What is the relationship between motion boxes and tracked object regions?

Motion boxes and tracked object regions operate in a complementary hierarchy. Tracked object regions take priority and ensure continuous detection of objects that may have temporarily stopped moving. Motion boxes are then filtered against these existing regions using `inside_any()`—only motion occurring **outside** current object boundaries generates new detection regions. This prevents redundant AI processing on areas already being tracked while ensuring new objects entering the scene trigger immediate detection.