Skip to content

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);
    }
};

See Also