Zone Plugin¶
Description¶
Zone is an area-based analytics plugin for CVEDIA-RT that provides zone and region-based event detection. It monitors defined polygonal areas for object presence, entry/exit events, occupancy counting, and behavioral analysis within specified zones.
The Zone plugin implements comprehensive area-based analytics that can detect various events within predefined polygonal zones, including intrusion detection, loitering analysis, occupancy monitoring, and movement pattern recognition. It provides flexible zone definitions with sophisticated event generation for security, crowd management, and behavioral analysis applications.
Key Features¶
- Polygonal Zone Definition: Create custom zones with complex polygonal shapes
- Entry/Exit Detection: Detect when objects enter or leave defined zones
- Occupancy Monitoring: Track object count and density within zones
- Loitering Detection: Identify objects that remain in zones beyond threshold time
- Intrusion Alerts: Generate alerts for unauthorized zone access
- Behavioral Analysis: Analyze object behavior patterns within zones
- Multi-Zone Support: Manage multiple zones with different configurations
- Zone Interactions: Detect relationships and interactions between zones
- Event Generation: Comprehensive event system with metadata and context
- Group Management: Organize zones into logical groups for batch processing
- Lua Integration: Full Lua scripting support for custom zone logic
- Point-in-Polygon: Fast geometric algorithms for zone containment testing
Requirements¶
Hardware Requirements¶
- CPU: Multi-core processor for real-time zone analysis
- Memory: Minimum 2GB RAM for typical zone monitoring scenarios
- Platform: All supported platforms (Windows, Linux, embedded)
Software Dependencies¶
- CVEDIA-RT Core: Base plugin infrastructure and interfaces
- Tracking System: Requires tracked objects with positions for zone analysis
- Geometric Libraries: Point-in-polygon and spatial analysis algorithms
- Sol2: Lua scripting integration
Configuration¶
Basic Configuration¶
{
"zones": [
{
"name": "restricted_area",
"group": "security",
"vertices": [
{"x": 100, "y": 100},
{"x": 300, "y": 100},
{"x": 300, "y": 200},
{"x": 100, "y": 200}
],
"color": [1.0, 0.0, 0.0, 0.5],
"enabled": true,
"intrusion_detection": true,
"loitering_time": 30.0
}
]
}
Advanced Configuration¶
{
"zones": [
{
"name": "security_perimeter",
"group": "high_security",
"vertices": [
{"x": 50, "y": 50},
{"x": 400, "y": 60},
{"x": 450, "y": 300},
{"x": 380, "y": 350},
{"x": 80, "y": 320}
],
"color": [1.0, 0.0, 0.0, 0.3],
"enabled": true,
"intrusion_detection": true,
"loitering_time": 15.0,
"max_occupancy": 5,
"entry_detection": true,
"exit_detection": true,
"dwell_time_analysis": true,
"min_time_for_enter": 1.0,
"density_monitoring": true,
"alert_on_empty": false,
"alert_on_overcrowded": true
},
{
"name": "queue_area",
"group": "customer_service",
"vertices": [
{"x": 500, "y": 200},
{"x": 600, "y": 200},
{"x": 600, "y": 400},
{"x": 500, "y": 400}
],
"color": [0.0, 1.0, 0.0, 0.3],
"occupancy_monitoring": true,
"max_occupancy": 10,
"average_dwell_time": true,
"queue_analysis": true
}
]
}
Configuration Schema¶
Parameter | Type | Default | Description |
---|---|---|---|
name |
string | required | Unique identifier for the zone |
group |
string | "default" | Logical group for batch processing |
vertices |
array | required | Array of points defining the polygonal zone |
color |
array | [1,0,0,0.5] | RGBA color for visualization |
enabled |
bool | true | Enable/disable the zone |
intrusion_detection |
bool | false | Enable intrusion detection alerts |
loitering_time |
float | 30.0 | Time threshold for loitering detection (seconds) |
max_occupancy |
int | 0 | Maximum allowed occupancy (0 = unlimited) |
entry_detection |
bool | false | Enable entry event detection |
exit_detection |
bool | false | Enable exit event detection |
dwell_time_analysis |
bool | false | Enable dwell time analysis |
min_time_for_enter |
float | 0.5 | Minimum time to confirm entry |
density_monitoring |
bool | false | Enable density analysis |
alert_on_empty |
bool | false | Generate alert when zone becomes empty |
alert_on_overcrowded |
bool | false | Generate alert when max occupancy exceeded |
occupancy_monitoring |
bool | false | Enable real-time occupancy tracking |
average_dwell_time |
bool | false | Calculate average time objects spend in zone |
queue_analysis |
bool | false | Enable queue management analytics |
API Reference¶
C++ API (ZoneManaged)¶
Zone Management¶
expected<std::string> createZone(std::string const& name, std::string const& group,
std::vector<Point2f> const& shape,
std::array<float, 4> const& color)
- Parameters: Name, group, polygon vertices, color
- Returns: Expected zone ID string
- Usage: Create new zone with specified polygonal shape
Processing Operations¶
expected<void> processZones(std::map<std::string, std::vector<Point2f>> const& points,
cmap const& options = {})
expected<void> processZones(std::map<std::string, std::vector<Point2f>> const& points,
std::vector<std::string> const& zonesFilter,
cmap const& options = {})
expected<void> processZones(std::map<std::string, std::vector<Point2f>> const& points,
std::string const& groupFilter,
cmap const& options = {})
- Parameters: Track points, optional filters, processing options
- Returns: Expected void, generates zone events internally
- Usage: Process tracked objects against zone definitions
Zone Queries¶
bool hasZoneId(std::string const& zoneid)
expected<std::vector<std::string>> getZoneIds()
expected<pCValue> getZoneById(std::string const& zoneid, int dictType)
expected<cmap> getZones(int dictType)
- Existence Check: Verify zone exists by ID
- ID Retrieval: Get all zone identifiers
- Data Access: Retrieve zone configuration and state data
Value Management¶
expected<pCValue> getZoneValue(std::string const& zoneid, std::string const& key,
int dictType = DICT_STATE)
expected<void> setZoneValue(std::string const& zoneid, std::string const& key,
pCValue const& value, int dictType = DICT_STATE)
expected<void> setZoneValue(std::string const& zoneid, cmap const& values,
int dictType = DICT_STATE)
- Property Access: Get and set individual zone properties
- Batch Updates: Set multiple properties simultaneously
- State Management: Access both configuration and runtime state
Geometric Operations¶
expected<std::vector<std::string>> isPointInZone(Point2f const& pt)
- Parameters: Point coordinates to test
- Returns: List of zone IDs containing the point
- Usage: Fast point-in-polygon testing for zone containment
Lifecycle Management¶
expected<void> registerKnownZones(bool skipRecalculate = false)
expected<void> recalculateZone(std::string const& zoneid)
expected<void> recalculateZones()
expected<void> deleteZoneById(std::string const& zoneid)
expected<void> resetZones()
expected<void> deleteZones()
- Registration: Register zones from configuration
- Recalculation: Update zone geometry and parameters
- Cleanup: Remove specific zones or reset entire system
Event Handling¶
expected<void> registerCallback(sol::protected_function callback)
expected<void> unregisterCallback()
expected<cvec> getZoneEvents()
- Callback Registration: Set Lua callback for zone events
- Event Retrieval: Get generated zone events for processing
Lua API¶
Factory Methods¶
-- Create zone manager
local zones = api.factory.zone.create(instance, "security_zones")
-- Get existing zone manager
local zones = api.factory.zone.get(instance, "security_zones")
Basic Operations¶
-- Create zone
local zoneId = zones:createZone(
"restricted_area",
"security",
{{x = 100, y = 100}, {x = 300, y = 100}, {x = 300, y = 200}, {x = 100, y = 200}},
{1.0, 0.0, 0.0, 0.5}
)
-- Register callback for zone events
zones:registerCallback(function(event)
print("Zone event:", event.zone_id, event.event_type, event.track_id)
end)
-- Process tracks against zones
local trackPoints = {
["track_1"] = {{x = 150, y = 150}}
}
zones:processZones(trackPoints)
-- Check if point is in zone
local containingZones = zones:isPointInZone({x = 200, y = 150})
print("Point is in zones:", table.concat(containingZones, ", "))
Examples¶
Basic Intrusion Detection¶
#include "zonemanaged.h"
// Create zone manager for security monitoring
auto zones = ZoneManaged::create("intrusion_detection");
// Define restricted area
std::vector<Point2f> restrictedArea = {
{100.0f, 100.0f}, {400.0f, 100.0f},
{400.0f, 300.0f}, {100.0f, 300.0f}
};
std::array<float, 4> redColor = {1.0f, 0.0f, 0.0f, 0.3f};
// Create intrusion detection zone
auto result = zones->createZone(
"restricted_area", "security", restrictedArea, redColor);
if (result) {
std::string zoneId = result.value();
// Configure for intrusion detection
zones->setZoneValue(zoneId, "intrusion_detection", CValue::create(true));
zones->setZoneValue(zoneId, "loitering_time", CValue::create(10.0));
zones->setZoneValue(zoneId, "entry_detection", CValue::create(true));
zones->setZoneValue(zoneId, "exit_detection", CValue::create(true));
// Register event callback
zones->registerCallback([](sol::table event) {
std::string eventType = event["event_type"];
std::string trackId = event["track_id"];
std::string zoneId = event["zone_id"];
double timestamp = event["timestamp"];
if (eventType == "intrusion") {
LOGW << "INTRUSION DETECTED: Track " << trackId
<< " in zone " << zoneId << " at " << timestamp;
generateSecurityAlert("INTRUSION", trackId, zoneId);
}
else if (eventType == "entry") {
LOGI << "Entry detected: " << trackId << " -> " << zoneId;
}
else if (eventType == "exit") {
LOGI << "Exit detected: " << trackId << " <- " << zoneId;
}
else if (eventType == "loitering") {
LOGW << "Loitering detected: " << trackId << " in " << zoneId;
generateSecurityAlert("LOITERING", trackId, zoneId);
}
});
// Process tracking data
while (videoStream.hasFrame()) {
auto tracks = tracker->getTracks();
// Extract track positions
std::map<std::string, std::vector<Point2f>> trackPoints;
for (const auto& [id, track] : tracks) {
Point2f center = {
track->bbox.x + track->bbox.width / 2.0f,
track->bbox.y + track->bbox.height / 2.0f
};
trackPoints[std::to_string(id)] = {center};
}
// Process zones
zones->processZones(trackPoints);
}
}
Multi-Zone Occupancy Monitoring¶
// Create occupancy monitoring system
auto occupancyZones = ZoneManaged::create("occupancy_monitor");
// Define multiple monitoring zones
struct ZoneConfig {
std::string name, group;
std::vector<Point2f> vertices;
int maxOccupancy;
float loiteringTime;
};
std::vector<ZoneConfig> zoneConfigs = {
{"lobby", "public", {{50,50}, {200,50}, {200,200}, {50,200}}, 20, 60.0f},
{"queue_area", "service", {{250,100}, {400,100}, {400,250}, {250,250}}, 10, 30.0f},
{"vip_area", "restricted", {{450,150}, {600,150}, {600,300}, {450,300}}, 5, 15.0f}
};
std::map<std::string, std::string> zoneIds;
for (const auto& config : zoneConfigs) {
auto zoneId = occupancyZones->createZone(
config.name, config.group, config.vertices,
{0.0f, 1.0f, 0.0f, 0.3f} // Green zones
);
if (zoneId) {
zoneIds[config.name] = zoneId.value();
// Configure occupancy monitoring
occupancyZones->setZoneValue(zoneId.value(), "occupancy_monitoring", CValue::create(true));
occupancyZones->setZoneValue(zoneId.value(), "max_occupancy", CValue::create(config.maxOccupancy));
occupancyZones->setZoneValue(zoneId.value(), "loitering_time", CValue::create(config.loiteringTime));
occupancyZones->setZoneValue(zoneId.value(), "alert_on_overcrowded", CValue::create(true));
occupancyZones->setZoneValue(zoneId.value(), "dwell_time_analysis", CValue::create(true));
occupancyZones->setZoneValue(zoneId.value(), "density_monitoring", CValue::create(true));
}
}
// Track occupancy statistics
struct OccupancyStats {
int currentCount = 0;
int maxCount = 0;
double totalDwellTime = 0.0;
int totalVisitors = 0;
double averageDwellTime = 0.0;
};
std::map<std::string, OccupancyStats> occupancyStats;
// Register comprehensive event callback
occupancyZones->registerCallback([&](sol::table event) {
std::string eventType = event["event_type"];
std::string zoneId = event["zone_id"];
std::string trackId = event["track_id"];
auto& stats = occupancyStats[zoneId];
if (eventType == "entry") {
stats.currentCount++;
stats.totalVisitors++;
stats.maxCount = std::max(stats.maxCount, stats.currentCount);
LOGI << "Zone " << zoneId << " occupancy: " << stats.currentCount;
}
else if (eventType == "exit") {
stats.currentCount = std::max(0, stats.currentCount - 1);
// Calculate dwell time if available
if (event["dwell_time"] != nullptr) {
double dwellTime = event["dwell_time"];
stats.totalDwellTime += dwellTime;
stats.averageDwellTime = stats.totalDwellTime / stats.totalVisitors;
LOGI << "Track " << trackId << " spent " << dwellTime
<< "s in zone " << zoneId;
}
}
else if (eventType == "overcrowded") {
LOGW << "Zone " << zoneId << " is overcrowded: " << stats.currentCount;
generateCapacityAlert(zoneId, stats.currentCount);
}
else if (eventType == "loitering") {
LOGW << "Loitering in zone " << zoneId << ": " << trackId;
}
});
Lua-Based Queue Management System¶
-- Queue management system with zone analytics
local zones = api.factory.zone.create(instance, "queue_manager")
-- Define queue zones
local queueAreas = {
{
name = "waiting_area",
group = "queue",
vertices = {{100, 200}, {300, 200}, {300, 400}, {100, 400}},
max_occupancy = 15,
target_wait_time = 300 -- 5 minutes
},
{
name = "service_counter",
group = "service",
vertices = {{350, 250}, {500, 250}, {500, 350}, {350, 350}},
max_occupancy = 3,
target_wait_time = 120 -- 2 minutes
},
{
name = "express_lane",
group = "express",
vertices = {{520, 200}, {650, 200}, {650, 300}, {520, 300}},
max_occupancy = 5,
target_wait_time = 60 -- 1 minute
}
}
-- Queue statistics
local queueStats = {
waiting_area = {current = 0, total = 0, avg_wait = 0, max_wait = 0},
service_counter = {current = 0, total = 0, avg_wait = 0, max_wait = 0},
express_lane = {current = 0, total = 0, avg_wait = 0, max_wait = 0}
}
-- Create zones
local zoneIds = {}
for _, area in ipairs(queueAreas) do
local zoneId = zones:createZone(
area.name,
area.group,
area.vertices,
{0.0, 0.0, 1.0, 0.3} -- Blue zones
)
if zoneId then
zoneIds[area.name] = zoneId
-- Configure queue monitoring
zones:setZoneValue(zoneId, "occupancy_monitoring", true)
zones:setZoneValue(zoneId, "max_occupancy", area.max_occupancy)
zones:setZoneValue(zoneId, "loitering_time", area.target_wait_time)
zones:setZoneValue(zoneId, "alert_on_overcrowded", true)
zones:setZoneValue(zoneId, "dwell_time_analysis", true)
zones:setZoneValue(zoneId, "entry_detection", true)
zones:setZoneValue(zoneId, "exit_detection", true)
end
end
-- Register queue event callback
zones:registerCallback(function(event)
local eventType = event.event_type
local zoneId = event.zone_id
local trackId = event.track_id
local timestamp = event.timestamp or os.time()
-- Find zone name from ID
local zoneName = nil
for name, id in pairs(zoneIds) do
if id == zoneId then
zoneName = name
break
end
end
if not zoneName then return end
local stats = queueStats[zoneName]
if eventType == "entry" then
stats.current = stats.current + 1
stats.total = stats.total + 1
print(string.format("Queue entry: %s -> %s (occupancy: %d)",
trackId, zoneName, stats.current))
-- Store entry time for wait calculation
api.storage.set("entry_time_" .. trackId, timestamp)
-- Check for overcrowding
local maxOccupancy = zones:getZoneValue(zoneId, "max_occupancy")
if stats.current > maxOccupancy.data then
generateQueueAlert("OVERCROWDED", zoneName, stats.current)
end
elseif eventType == "exit" then
stats.current = math.max(0, stats.current - 1)
-- Calculate wait time
local entryTime = api.storage.get("entry_time_" .. trackId)
if entryTime then
local waitTime = timestamp - entryTime.data
stats.avg_wait = (stats.avg_wait * (stats.total - 1) + waitTime) / stats.total
stats.max_wait = math.max(stats.max_wait, waitTime)
print(string.format("Queue exit: %s <- %s (wait: %.1fs, avg: %.1fs)",
trackId, zoneName, waitTime, stats.avg_wait))
-- Clean up storage
api.storage.remove("entry_time_" .. trackId)
end
elseif eventType == "loitering" then
print(string.format("Long wait detected: %s in %s", trackId, zoneName))
generateQueueAlert("LONG_WAIT", zoneName, trackId)
elseif eventType == "overcrowded" then
print(string.format("Queue overcrowded: %s (%d people)", zoneName, stats.current))
generateQueueAlert("OVERCROWDED", zoneName, stats.current)
end
-- Update queue management system
updateQueueDisplay(zoneName, stats)
end)
-- Process queue frame
function processQueueFrame(tracks)
local trackPoints = {}
for trackId, track in pairs(tracks) do
if track.state == "active" then
local center = {
x = track.bbox.x + track.bbox.w / 2,
y = track.bbox.y + track.bbox.h / 2
}
trackPoints[tostring(trackId)] = {center}
end
end
-- Process all queue zones
zones:processZones(trackPoints)
end
-- Generate queue management reports
function generateQueueReport()
local report = {
timestamp = os.time(),
zones = {}
}
for zoneName, stats in pairs(queueStats) do
report.zones[zoneName] = {
current_occupancy = stats.current,
total_visitors = stats.total,
average_wait_time = stats.avg_wait,
maximum_wait_time = stats.max_wait,
efficiency_rating = calculateEfficiency(zoneName, stats)
}
end
return report
end
Best Practices¶
Zone Design¶
- Simple Polygons: Use simple, convex polygons when possible for better performance
- Adequate Size: Ensure zones are large enough to account for tracking accuracy
- Clear Boundaries: Define zones with clear, unambiguous boundaries
- Logical Grouping: Organize related zones into groups for efficient processing
Configuration Optimization¶
- Occupancy Limits: Set realistic occupancy limits based on zone size and purpose
- Time Thresholds: Adjust loitering and dwell time based on expected behavior
- Event Selection: Enable only necessary events to reduce processing overhead
- Density Monitoring: Use density analysis for crowd management scenarios
Integration Guidelines¶
- Tracking Quality: Ensure reliable object tracking before zone processing
- Event Processing: Handle zone events promptly to maintain system performance
- State Cleanup: Regularly clean up old zone states and event data
- Performance: Use group filtering to process only relevant zones
Troubleshooting¶
Common Issues¶
False Entry/Exit Events¶
// Increase minimum time for entry confirmation
zones->setZoneValue(zoneId, "min_time_for_enter", CValue::create(1.0));
// Enable more strict occupancy tracking
zones->setZoneValue(zoneId, "occupancy_monitoring", CValue::create(true));
Missed Zone Events¶
// Verify point-in-polygon testing
Point2f testPoint = {150.0f, 150.0f};
auto containingZones = zones->isPointInZone(testPoint);
for (const auto& zoneId : containingZones.value()) {
LOGI << "Point is in zone: " << zoneId;
}
Performance Issues¶
- Zone Complexity: Simplify complex polygonal zones
- Processing Filters: Use group or zone filters to reduce processing load
- Event Cleanup: Regularly clear processed events
- Geometry Caching: Cache zone geometry calculations
Debugging Tools¶
// Monitor zone statistics
auto zoneList = zones->getZones(DICT_STATE);
for (const auto& [id, data] : zoneList.value()) {
auto occupancy = zones->getZoneValue(id, "current_occupancy", DICT_STATE);
auto totalEntries = zones->getZoneValue(id, "total_entries", DICT_STATE);
auto avgDwell = zones->getZoneValue(id, "average_dwell_time", DICT_STATE);
LOGI << "Zone " << id << " - Occupancy: " << occupancy.value()->getInt()
<< ", Entries: " << totalEntries.value()->getInt()
<< ", Avg Dwell: " << avgDwell.value()->getDouble();
}
// Check for pending events
auto events = zones->getZoneEvents();
LOGI << "Pending zone events: " << events.value().size();
Integration Examples¶
Comprehensive Security System¶
// Integrated security system with zones, tripwires, and tracking
class ComprehensiveSecuritySystem {
private:
std::shared_ptr<ZoneManaged> securityZones_;
std::shared_ptr<TripwireManaged> perimeters_;
std::shared_ptr<TrackerManaged> tracker_;
struct SecurityEvent {
std::string type;
std::string sourceId;
std::string trackId;
Point2f location;
double timestamp;
std::string severity;
};
std::vector<SecurityEvent> pendingAlerts_;
public:
void initialize() {
// Initialize security components
securityZones_ = ZoneManaged::create("security_zones");
perimeters_ = TripwireManaged::create("perimeter_lines");
tracker_ = TrackerManaged::create("security_tracker");
// Setup security infrastructure
setupSecurityZones();
setupPerimeterTripwires();
// Register event callbacks
registerSecurityCallbacks();
}
void processSecurityFrame(const cbuffer& frame,
const std::vector<Detection>& detections) {
// Update tracking
auto tracks = updateTracking(frame, detections);
// Extract positions for analytics
std::map<std::string, std::vector<Point2f>> trackPositions;
extractPositions(tracks, trackPositions);
// Process security analytics
securityZones_->processZones(trackPositions, "security");
perimeters_->processTripwires(trackPositions, "perimeter");
// Evaluate and respond to security events
evaluateSecurityThreats();
respondToAlerts();
}
private:
void setupSecurityZones() {
// High security areas
std::vector<Point2f> serverRoom = {
{50, 50}, {150, 50}, {150, 150}, {50, 150}
};
auto zoneId = securityZones_->createZone(
"server_room", "critical", serverRoom, {1,0,0,0.5});
if (zoneId) {
securityZones_->setZoneValue(zoneId.value(), "intrusion_detection", CValue::create(true));
securityZones_->setZoneValue(zoneId.value(), "max_occupancy", CValue::create(2));
securityZones_->setZoneValue(zoneId.value(), "loitering_time", CValue::create(5.0));
}
}
void registerSecurityCallbacks() {
// Zone event callback
securityZones_->registerCallback([this](sol::table event) {
handleZoneSecurityEvent(event);
});
// Tripwire event callback
perimeters_->registerCallback([this](sol::table event) {
handlePerimeterSecurityEvent(event);
});
}
void handleZoneSecurityEvent(sol::table event) {
SecurityEvent alert;
alert.type = event["event_type"];
alert.sourceId = event["zone_id"];
alert.trackId = event["track_id"];
alert.timestamp = event["timestamp"];
if (alert.type == "intrusion") {
alert.severity = "HIGH";
triggerImmediateResponse(alert);
} else if (alert.type == "loitering") {
alert.severity = "MEDIUM";
} else {
alert.severity = "LOW";
}
pendingAlerts_.push_back(alert);
}
};