This document describes the detection zone configuration feature for lightNVR.
Detection zones allow you to define specific regions in your camera's field of view where object detection should be active. This helps:
- Reduce false positives by ignoring areas like trees, roads, or sky
- Focus on areas of interest like doorways, driveways, or specific zones
- Improve performance by limiting detection to relevant areas
- Configure per-zone settings like class filters and confidence thresholds
- Visual polygon drawing on live camera snapshot
- Multiple zones per stream with different configurations
- Color-coded zones for easy identification
- Enable/disable zones individually
- Per-zone class filtering (e.g., only detect persons in entrance zone)
- Per-zone confidence thresholds
When a zone is configured, detections are filtered based on the zone mode:
- Center mode: Detection's bounding box center must be in zone
- Any mode: Any part of detection's bounding box must overlap with zone
- All mode: Entire detection's bounding box must be within zone
- Navigate to Streams page
- Click Edit on a stream
- Enable AI Detection Recording
- Expand the Detection Zones section
- Click Configure Zones button
- Click Draw Zone button
- Click on the camera preview to add points
- Click multiple points to create a polygon (minimum 3 points)
- Click Complete Zone when done
- Repeat for additional zones
- Click Select mode
- Click on a zone to select it
- Edit zone properties in the sidebar:
- Zone name
- Color
- Enabled/disabled status
- Click Save Zones when done
- Click Delete mode
- Click on a zone to delete it
- Or select a zone and use the delete button in the sidebar
CREATE TABLE detection_zones (
id TEXT PRIMARY KEY,
stream_name TEXT NOT NULL,
name TEXT NOT NULL,
enabled INTEGER DEFAULT 1,
color TEXT DEFAULT '#3b82f6',
polygon TEXT NOT NULL, -- JSON array of points
filter_classes TEXT DEFAULT '',
min_confidence REAL DEFAULT 0.0,
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL,
FOREIGN KEY (stream_name) REFERENCES streams(name) ON DELETE CASCADE
);Polygons are stored as JSON arrays of normalized coordinates (0.0 - 1.0):
[
{"x": 0.0, "y": 0.0},
{"x": 0.5, "y": 0.0},
{"x": 0.5, "y": 1.0},
{"x": 0.0, "y": 1.0}
]GET /api/streams/{stream_name}/zonesResponse:
{
"zones": [
{
"id": "zone_1234567890",
"stream_name": "front_door",
"name": "Entrance",
"enabled": true,
"color": "#3b82f6",
"polygon": [
{"x": 0.0, "y": 0.0},
{"x": 0.5, "y": 0.0},
{"x": 0.5, "y": 1.0},
{"x": 0.0, "y": 1.0}
],
"filter_classes": "person",
"min_confidence": 0.7
}
]
}POST /api/streams/{stream_name}/zones
Content-Type: application/json
{
"zones": [
{
"id": "zone_1234567890",
"name": "Entrance",
"enabled": true,
"color": "#3b82f6",
"polygon": [
{"x": 0.0, "y": 0.0},
{"x": 0.5, "y": 0.0},
{"x": 0.5, "y": 1.0},
{"x": 0.0, "y": 1.0}
],
"filter_classes": "person",
"min_confidence": 0.7
}
]
}Response:
{
"success": true,
"message": "Zones saved successfully",
"count": 1
}DELETE /api/streams/{stream_name}/zonesWhen detection is triggered, lightNVR sends zone configuration to the light-object-detect API:
curl -X POST "http://localhost:8000/api/v1/detect" \
-F "file=@frame.jpg" \
-F "zones={\"zones\":[...],\"zone_mode\":\"center\"}"The API filters detections based on the zones and returns only detections within the configured zones.
Monitor only the entrance area for persons:
{
"id": "entrance_zone",
"name": "Front Entrance",
"enabled": true,
"color": "#3b82f6",
"polygon": [
{"x": 0.2, "y": 0.3},
{"x": 0.8, "y": 0.3},
{"x": 0.8, "y": 0.9},
{"x": 0.2, "y": 0.9}
],
"filter_classes": "person",
"min_confidence": 0.75
}Monitor parking lot for vehicles:
{
"id": "parking_zone",
"name": "Parking Lot",
"enabled": true,
"color": "#10b981",
"polygon": [
{"x": 0.0, "y": 0.5},
{"x": 1.0, "y": 0.5},
{"x": 1.0, "y": 1.0},
{"x": 0.0, "y": 1.0}
],
"filter_classes": "car,truck,motorcycle",
"min_confidence": 0.6
}Combine multiple zones for comprehensive monitoring:
{
"zones": [
{
"id": "entrance",
"name": "Entrance",
"enabled": true,
"color": "#3b82f6",
"polygon": [...],
"filter_classes": "person",
"min_confidence": 0.75
},
{
"id": "driveway",
"name": "Driveway",
"enabled": true,
"color": "#10b981",
"polygon": [...],
"filter_classes": "car,truck,person",
"min_confidence": 0.65
},
{
"id": "backyard",
"name": "Backyard",
"enabled": false,
"color": "#f59e0b",
"polygon": [...],
"filter_classes": "",
"min_confidence": 0.5
}
]
}- Start with simple zones: Begin with one or two zones and refine as needed
- Use appropriate confidence thresholds: Higher for critical areas, lower for general monitoring
- Avoid overlapping zones: Can cause duplicate detections
- Test your zones: Use the live preview to verify zone coverage
- Name zones descriptively: Makes it easier to identify in logs and alerts
- Disable unused zones: Rather than deleting, disable zones you might need later
- Ensure the stream has a valid snapshot available
- Check browser console for errors
- Verify the stream is running
- Verify zones are enabled
- Check zone polygon coordinates are valid (0.0 - 1.0)
- Ensure light-object-detect API is receiving zone configuration
- Check API logs for zone filtering errors
- Reduce number of zones (max 16 per stream recommended)
- Simplify polygon shapes (fewer points)
- Use larger zones rather than many small ones
Potential future improvements:
- Zone crossing detection and counting
- Heatmap generation from zone detections
- Zone-based alerts and notifications
- Time-based zone activation
- Zone templates for common scenarios
- Zone analytics and statistics