Skip to content

Visualizers Plugin

Description

The Visualizers plugin collection provides comprehensive real-time visualization capabilities for AI inference results within CVEDIA-RT. This modular system consists of specialized visualization plugins that render various types of detection and analysis data including bounding boxes, points, lines, polygons, and text overlays.

Designed for both debugging and production use, the visualizer system offers interactive visual feedback, professional presentation features, and detailed inspection tools. Each visualizer implements a common interface while providing specialized rendering capabilities optimized for different data types and use cases.

Key Features

  • Modular Architecture: Specialized visualizers for different data types (2D/3D boxes, points, lines, polygons, text)
  • Real-Time Rendering: Low-latency visualization optimized for live video streams
  • Interactive Elements: Mouse interaction, entity selection, and detailed inspection tools
  • Professional Styling: Extensive customization options for colors, fonts, transparency, and effects
  • Multiple Display Modes: Table view, mosaic, histograms, count graphs, and occupancy visualization
  • Dual Rendering: Both ImGui overlay and direct buffer rendering support
  • Performance Optimized: Efficient scrolling buffers, image caching, and conditional rendering
  • Debugging Tools: Inspector functionality with cropping, event tables, and detailed analysis
  • Cross-Platform: Compatible across CVEDIA-RT's supported platforms

Available Visualizers

Bbox Visualizer

Standard 2D bounding box visualization for object detection results with extensive styling options, label formats, and display modes.

Bbox3d Visualizer

3D bounding box visualization for spatial object detection with separate styling for top, bottom, sides, and center points.

Point Visualizer

Point and keypoint visualization for pose estimation, landmarks, and point cloud data.

Poly Visualizer

Polygon visualization for zones, regions, and complex shapes with occupancy tracking and state visualization.

Line Visualizer

Line segment visualization for tripwires and boundaries with directional hit counting and statistics.

Text Visualizer

Text and image overlay visualization with font customization, effects, and background control.

Event Visualizer

Event-based visualization for temporal analytics with event tables and history tracking.

Use Cases

  • Real-Time Monitoring: Live visualization of AI inference results in production systems
  • Development and Debugging: Visual feedback during AI model development and testing
  • Quality Assurance: Visual validation of detection accuracy and system performance
  • Demonstration and Presentation: Professional visual output for demonstrations and client presentations
  • Analytics Dashboards: Interactive dashboards for security, retail, and industrial applications
  • Training and Education: Visual tools for understanding AI system behavior
  • System Integration: Visual feedback for integrating CVEDIA-RT with other systems
  • Performance Analysis: Visual tools for analyzing detection patterns and system behavior

Requirements

Hardware Requirements

  • CPU: Multi-core processor for real-time rendering
  • Memory: Minimum 2GB RAM (4GB+ recommended for complex visualizations)
  • Graphics: GPU with OpenGL support recommended for smooth rendering
  • Display: Monitor with appropriate resolution for visualization output

Software Dependencies

  • OpenCV: Computer vision library for image processing and rendering
  • ImGui: Immediate mode GUI library for interactive visualizations
  • RTCORE: CVEDIA-RT core library for plugin infrastructure
  • FontAwesome: Icon font library for symbol rendering
  • Graphics Drivers: Up-to-date graphics drivers for optimal performance

Platform Requirements

  • Windows: Full support with hardware acceleration
  • Linux: Full cross-platform compatibility with X11/Wayland
  • Graphics APIs: OpenGL support for rendering acceleration
  • Font Support: System fonts and FontAwesome for text rendering

Configuration

Basic Visualizer Configuration

{
  "visualizers": {
    "bbox": {
      "enabled": true,
      "style": "rectangle",
      "label_format": "label_confidence",
      "label_alignment": "top_left",
      "colors": {
        "border": [255, 0, 0, 255],
        "fill": [255, 0, 0, 64],
        "font": [255, 255, 255, 255]
      },
      "thickness": 2,
      "font_scale": 1.0
    },
    "point": {
      "enabled": true,
      "radius": 3,
      "color": [0, 255, 0, 255]
    },
    "text": {
      "enabled": true,
      "font_scale": 1.0,
      "background_color": [0, 0, 0, 128],
      "padding": {
        "top": 5,
        "bottom": 5,
        "left": 10,
        "right": 10
      }
    }
  }
}

Advanced Bbox Visualizer Configuration

{
  "bbox_visualizer": {
    "style": "rectangle",
    "label_format": "multiline",
    "label_alignment": "top_left",
    "display_mode": "normal",
    "events_only": false,
    "use_data_color": false,
    "styling": {
      "rectangle_rounding": 5,
      "ellipse_segments": 32,
      "lightweight_percentage": 0.1,
      "thickness": 2
    },
    "colors": {
      "border": [255, 255, 255, 255],
      "fill": [128, 128, 128, 64],
      "font": [255, 255, 255, 255]
    },
    "font": {
      "scale": 1.0,
      "icon_based": false,
      "fontawesome_icons": true
    },
    "display_modes": {
      "table": {
        "enabled": true,
        "max_entries": 100
      },
      "mosaic": {
        "enabled": true,
        "tile_size": 128
      },
      "histogram": {
        "enabled": true,
        "bins": 20
      },
      "count_graph": {
        "enabled": true,
        "time_window": 60
      }
    },
    "inspector": {
      "enabled": true,
      "cropping": true,
      "crop_padding": 10
    }
  }
}

3D Bbox Visualizer Configuration

{
  "bbox3d_visualizer": {
    "top_face": {
      "enabled": true,
      "thickness": 2,
      "color": [255, 0, 0, 255]
    },
    "bottom_face": {
      "enabled": true,
      "thickness": 2,
      "color": [0, 255, 0, 255]
    },
    "side_faces": {
      "enabled": true,
      "thickness": 1,
      "color": [0, 0, 255, 255]
    },
    "center_points": {
      "enabled": true,
      "radius": 3,
      "color": [255, 255, 0, 255]
    }
  }
}

Poly Visualizer Configuration

{
  "poly_visualizer": {
    "fill": {
      "enabled": true,
      "color": [128, 128, 255, 64],
      "transparency": 0.25
    },
    "outline": {
      "enabled": true,
      "color": [255, 255, 255, 255],
      "thickness": 2
    },
    "zone_modes": {
      "per_zone_occupancy": true,
      "total_occupancy": true,
      "zone_states": true
    },
    "labels": {
      "enabled": true,
      "show_occupancy_count": true,
      "font_scale": 1.0
    }
  }
}

Configuration Schema

Parameter Type Default Description
Bbox Visualizer
style string "rectangle" Rendering style ("rectangle", "ellipsis", "lightweight")
label_format string "label_confidence" Label format ("none", "label", "label_confidence", "multiline", "confidence_only")
label_alignment string "top_left" Label position ("top_left", "top_right", "bottom_left", "bottom_right", "center")
thickness int 2 Border thickness in pixels
rectangle_rounding int 0 Corner rounding radius for rectangles
use_data_color bool false Use colors from detection data
events_only bool false Show only event-triggered detections
Point Visualizer
radius int 3 Point radius in pixels
color array [255,255,255,255] RGBA color for points
Text Visualizer
font_scale float 1.0 Font scaling factor
blinking bool false Enable blinking text effect
padding.top int 5 Top padding in pixels
padding.bottom int 5 Bottom padding in pixels
padding.left int 10 Left padding in pixels
padding.right int 10 Right padding in pixels
Line Visualizer
thickness int 2 Line thickness in pixels
show_hit_statistics bool true Display hit count statistics
band_visualization bool true Show cross and cooldown bands
Poly Visualizer
fill.enabled bool true Enable polygon fill
outline.enabled bool true Enable polygon outline
transparency float 0.25 Fill transparency (0.0-1.0)
Event Visualizer
table_view bool true Show event table
history_size int 1000 Maximum events in history
popup_duration int 5000 Event popup duration in milliseconds

API Reference

C++ API (iface::Visualizer)

Core Visualizer Interface

class Visualizer {
public:
    // Core rendering methods
    virtual pCValue draw(pCValue input, pCValue config) = 0;
    virtual pCValue draw(cv::Mat& imageBuffer, pCValue input, pCValue config) = 0;

    // UI and interaction methods
    virtual pCValue visualize(pCValue input) = 0;
    virtual pCValue config(pCValue data) = 0;
    virtual pCValue configData(pCValue input) = 0;
    virtual pCValue inspector(pCValue input, pCValue config) = 0;

    // Mouse interaction
    virtual pCValue onLeftMouseClick(pCValue input, pCValue config) = 0;
    virtual pCValue onRightMouseClick(pCValue input) = 0;

    // Entity management
    virtual pCValue getEntityById(pCValue input) = 0;

    // ImGui context management
    virtual void setCurrentContext(ImGuiContext* ctx) = 0;
    virtual ImGuiContext* getCurrentContext() = 0;
};

Bbox Visualizer Specific API

class BboxHandler : public Visualizer {
public:
    // Bounding box rendering
    pCValue draw(pCValue input, pCValue config) override;
    pCValue draw(cv::Mat& imageBuffer, pCValue input, pCValue config) override;

    // Inspector with cropping functionality
    pCValue inspector(pCValue input, pCValue config) override;

    // Configuration UI
    pCValue config(pCValue data) override;

private:
    // Style rendering methods
    void drawRectangleStyle(cv::Mat& image, const BboxData& bbox, const Config& config);
    void drawEllipsisStyle(cv::Mat& image, const BboxData& bbox, const Config& config);
    void drawLightweightStyle(cv::Mat& image, const BboxData& bbox, const Config& config);

    // Label rendering
    void renderLabel(cv::Mat& image, const BboxData& bbox, const Config& config);

    // Display modes
    void renderTableMode(pCValue input);
    void renderMosaicMode(pCValue input);
    void renderCountGraph(pCValue input);
};

Factory Registration and Creation

// Register visualizer implementation
api::factory::Visualizer::registerImplementation("bbox", &BboxHandler::create);
api::factory::Visualizer::registerImplementation("point", &PointHandler::create);
api::factory::Visualizer::registerImplementation("poly", &PolyHandler::create);

// Create visualizer instances
auto bboxVisualizer = api::factory::Visualizer::create("bbox");
auto pointVisualizer = api::factory::Visualizer::create("point");
auto polyVisualizer = api::factory::Visualizer::create("poly");

Integration API

Output Window Integration

// Integrate visualizers with output window
class OutputWindow {
public:
    void addVisualizer(const std::string& type, std::shared_ptr<Visualizer> visualizer) {
        visualizers_[type] = visualizer;
    }

    void renderVisualization(pCValue detectionData, pCValue config) {
        for (auto& [type, visualizer] : visualizers_) {
            visualizer->draw(detectionData, config);
        }
    }

private:
    std::map<std::string, std::shared_ptr<Visualizer>> visualizers_;
};

Buffer Rendering API

// Direct buffer rendering for non-interactive scenarios
class BufferRenderer {
public:
    cv::Mat renderToBuffer(cv::Mat& inputImage, 
                          pCValue detectionData, 
                          const VisualizerConfig& config) {
        cv::Mat outputImage = inputImage.clone();

        // Render each visualizer to buffer
        for (const auto& visualizerConfig : config.visualizers) {
            auto visualizer = api::factory::Visualizer::create(visualizerConfig.type);
            visualizer->draw(outputImage, detectionData, visualizerConfig.config);
        }

        return outputImage;
    }
};

Lua API Integration

UI Drawing Primitives

-- Access to low-level drawing functions through UIAPILua
local ui = api.ui

-- Draw basic shapes
ui.drawRect(x, y, width, height, color, thickness)
ui.drawCircle(centerX, centerY, radius, color, thickness)
ui.drawLine(x1, y1, x2, y2, color, thickness)
ui.drawPolygon(points, color, thickness, filled)
ui.drawText(text, x, y, fontSize, color, backgroundColor)

-- Advanced drawing
ui.drawRoundedRect(x, y, width, height, rounding, color, thickness)
ui.drawEllipse(centerX, centerY, radiusX, radiusY, color, thickness)

Bbox Drawing Utilities

-- Specialized bbox drawing utilities from draw_bbox.lua
function drawDetectionBox(detection, config)
    local x, y, w, h = detection.x, detection.y, detection.w, detection.h
    local color = config.color or {255, 255, 255, 255}
    local thickness = config.thickness or 2

    -- Draw bounding box
    ui.drawRect(x, y, w, h, color, thickness)

    -- Draw label if present
    if detection.label then
        local labelText = string.format("%s (%.2f)", detection.label, detection.confidence)
        ui.drawText(labelText, x, y - 20, 0.7, color)
    end
end

-- Multiple detection rendering
function drawAllDetections(detections, config)
    for _, detection in ipairs(detections) do
        drawDetectionBox(detection, config)
    end
end

Examples

Basic Bbox Visualization Setup

#include "visualizers.h"
#include "rtcore.h"

// Basic bbox visualization system
class DetectionVisualizer {
public:
    void initialize() {
        // Create bbox visualizer
        bboxVisualizer_ = api::factory::Visualizer::create("bbox");

        // Setup configuration
        setupVisualizationConfig();

        LOGI << "Detection visualizer initialized";
    }

    void visualizeDetections(cv::Mat& image, pCValue detections) {
        if (!bboxVisualizer_ || !detections) {
            return;
        }

        // Render bounding boxes to image
        bboxVisualizer_->draw(image, detections, config_);

        // Optional: Show inspector window
        if (showInspector_) {
            bboxVisualizer_->inspector(detections, config_);
        }
    }

private:
    std::shared_ptr<Visualizer> bboxVisualizer_;
    pCValue config_;
    bool showInspector_ = false;

    void setupVisualizationConfig() {
        config_ = CValue::create();

        // Style configuration
        config_->set("style", "rectangle");
        config_->set("label_format", "label_confidence");
        config_->set("label_alignment", "top_left");
        config_->set("thickness", 2);

        // Color configuration
        auto colors = CValue::create();
        colors->set("border", std::vector<int>{255, 0, 0, 255}); // Red border
        colors->set("fill", std::vector<int>{255, 0, 0, 64});    // Semi-transparent red fill
        colors->set("font", std::vector<int>{255, 255, 255, 255}); // White text
        config_->set("colors", colors);

        // Font configuration
        config_->set("font_scale", 1.0);
        config_->set("rectangle_rounding", 3);
    }
};

Advanced Multi-Visualizer System

// Comprehensive visualization system with multiple visualizers
class AdvancedVisualizationSystem {
public:
    void initialize() {
        // Create all visualizer types
        visualizers_["bbox"] = api::factory::Visualizer::create("bbox");
        visualizers_["bbox3d"] = api::factory::Visualizer::create("bbox3d");
        visualizers_["point"] = api::factory::Visualizer::create("point");
        visualizers_["poly"] = api::factory::Visualizer::create("poly");
        visualizers_["line"] = api::factory::Visualizer::create("line");
        visualizers_["text"] = api::factory::Visualizer::create("text");
        visualizers_["event"] = api::factory::Visualizer::create("event");

        // Setup configurations for each visualizer
        setupConfigurations();

        LOGI << "Advanced visualization system initialized with " 
             << visualizers_.size() << " visualizers";
    }

    void renderFrame(cv::Mat& image, const AnalysisResults& results) {
        // Render 2D bounding boxes
        if (!results.detections.empty()) {
            renderDetections(image, results.detections);
        }

        // Render 3D bounding boxes
        if (!results.detections3d.empty()) {
            render3DDetections(image, results.detections3d);
        }

        // Render keypoints
        if (!results.keypoints.empty()) {
            renderKeypoints(image, results.keypoints);
        }

        // Render zones and polygons
        if (!results.zones.empty()) {
            renderZones(image, results.zones);
        }

        // Render tripwires and lines
        if (!results.tripwires.empty()) {
            renderTripwires(image, results.tripwires);
        }

        // Render text overlays
        if (!results.textOverlays.empty()) {
            renderTextOverlays(image, results.textOverlays);
        }

        // Render events
        if (!results.events.empty()) {
            renderEvents(results.events);
        }
    }

private:
    std::map<std::string, std::shared_ptr<Visualizer>> visualizers_;
    std::map<std::string, pCValue> configs_;

    void renderDetections(cv::Mat& image, const std::vector<Detection>& detections) {
        // Convert detections to CValue format
        auto detectionsData = convertDetectionsToCValue(detections);

        // Render using bbox visualizer
        auto& visualizer = visualizers_["bbox"];
        visualizer->draw(image, detectionsData, configs_["bbox"]);
    }

    void render3DDetections(cv::Mat& image, const std::vector<Detection3D>& detections3d) {
        auto detectionsData = convertDetections3DToCValue(detections3d);
        auto& visualizer = visualizers_["bbox3d"];
        visualizer->draw(image, detectionsData, configs_["bbox3d"]);
    }

    void renderKeypoints(cv::Mat& image, const std::vector<Keypoint>& keypoints) {
        auto keypointsData = convertKeypointsToCValue(keypoints);
        auto& visualizer = visualizers_["point"];
        visualizer->draw(image, keypointsData, configs_["point"]);
    }

    void renderZones(cv::Mat& image, const std::vector<Zone>& zones) {
        auto zonesData = convertZonesToCValue(zones);
        auto& visualizer = visualizers_["poly"];
        visualizer->draw(image, zonesData, configs_["poly"]);
    }

    void renderTripwires(cv::Mat& image, const std::vector<Tripwire>& tripwires) {
        auto tripwiresData = convertTripwiresToCValue(tripwires);
        auto& visualizer = visualizers_["line"];
        visualizer->draw(image, tripwiresData, configs_["line"]);
    }

    void renderTextOverlays(cv::Mat& image, const std::vector<TextOverlay>& textOverlays) {
        auto textData = convertTextOverlaysToCValue(textOverlays);
        auto& visualizer = visualizers_["text"];
        visualizer->draw(image, textData, configs_["text"]);
    }

    void renderEvents(const std::vector<AnalysisEvent>& events) {
        // Events are typically rendered in separate windows, not on image
        auto eventsData = convertEventsToCValue(events);
        auto& visualizer = visualizers_["event"];
        visualizer->visualize(eventsData);
    }

    void setupConfigurations() {
        // Bbox configuration
        auto bboxConfig = CValue::create();
        bboxConfig->set("style", "rectangle");
        bboxConfig->set("label_format", "multiline");
        bboxConfig->set("thickness", 2);
        bboxConfig->set("rectangle_rounding", 5);
        configs_["bbox"] = bboxConfig;

        // Point configuration
        auto pointConfig = CValue::create();
        pointConfig->set("radius", 4);
        pointConfig->set("color", std::vector<int>{0, 255, 0, 255});
        configs_["point"] = pointConfig;

        // Polygon configuration
        auto polyConfig = CValue::create();
        polyConfig->set("fill_enabled", true);
        polyConfig->set("outline_enabled", true);
        polyConfig->set("transparency", 0.3);
        configs_["poly"] = polyConfig;

        // Line configuration
        auto lineConfig = CValue::create();
        lineConfig->set("thickness", 3);
        lineConfig->set("show_hit_statistics", true);
        configs_["line"] = lineConfig;

        // Text configuration
        auto textConfig = CValue::create();
        textConfig->set("font_scale", 1.2);
        textConfig->set("padding_top", 10);
        textConfig->set("padding_bottom", 10);
        configs_["text"] = textConfig;

        // Event configuration
        auto eventConfig = CValue::create();
        eventConfig->set("table_view", true);
        eventConfig->set("history_size", 500);
        configs_["event"] = eventConfig;
    }
};

Interactive Visualization with Inspector

// Interactive visualization system with detailed inspection
class InteractiveVisualizer {
public:
    void initialize() {
        visualizer_ = api::factory::Visualizer::create("bbox");
        setupInteractiveConfig();
    }

    void renderInteractive(pCValue detections) {
        if (!visualizer_ || !detections) return;

        // Main visualization
        visualizer_->draw(detections, config_);

        // Show different analysis modes
        if (showTableMode_) {
            renderTableMode(detections);
        }

        if (showMosaicMode_) {
            renderMosaicMode(detections);
        }

        if (showCountGraph_) {
            renderCountGraph(detections);
        }

        if (showInspector_) {
            renderInspector(detections);
        }

        // Handle user interactions
        handleMouseInteractions(detections);
    }

    void enableMode(const std::string& mode, bool enabled) {
        if (mode == "table") showTableMode_ = enabled;
        else if (mode == "mosaic") showMosaicMode_ = enabled;
        else if (mode == "count_graph") showCountGraph_ = enabled;
        else if (mode == "inspector") showInspector_ = enabled;
    }

private:
    std::shared_ptr<Visualizer> visualizer_;
    pCValue config_;
    bool showTableMode_ = false;
    bool showMosaicMode_ = false;
    bool showCountGraph_ = false;
    bool showInspector_ = false;

    void renderTableMode(pCValue detections) {
        // Display detections in table format
        auto tableConfig = config_->clone();
        tableConfig->set("display_mode", "table");
        visualizer_->visualize(detections);
    }

    void renderMosaicMode(pCValue detections) {
        // Display detection crops in mosaic
        auto mosaicConfig = config_->clone();
        mosaicConfig->set("display_mode", "mosaic");
        visualizer_->visualize(detections);
    }

    void renderCountGraph(pCValue detections) {
        // Display count over time graph
        auto graphConfig = config_->clone();
        graphConfig->set("display_mode", "count_graph");
        visualizer_->visualize(detections);
    }

    void renderInspector(pCValue detections) {
        // Detailed inspection with cropping
        visualizer_->inspector(detections, config_);
    }

    void handleMouseInteractions(pCValue detections) {
        // Handle left mouse clicks for selection
        if (ImGui::IsMouseClicked(0)) {
            auto clickResult = visualizer_->onLeftMouseClick(detections, config_);
            if (clickResult) {
                handleEntitySelection(clickResult);
            }
        }

        // Handle right mouse clicks for context menu
        if (ImGui::IsMouseClicked(1)) {
            auto contextResult = visualizer_->onRightMouseClick(detections);
            if (contextResult) {
                showContextMenu(contextResult);
            }
        }
    }

    void setupInteractiveConfig() {
        config_ = CValue::create();

        // Enable interactive features
        config_->set("interactive", true);
        config_->set("inspector_enabled", true);
        config_->set("cropping_enabled", true);

        // Visual styling
        config_->set("style", "rectangle");
        config_->set("label_format", "multiline");
        config_->set("rectangle_rounding", 8);
        config_->set("thickness", 3);

        // Enable all display modes
        auto displayModes = CValue::create();
        displayModes->set("table", true);
        displayModes->set("mosaic", true);
        displayModes->set("histogram", true);
        displayModes->set("count_graph", true);
        config_->set("display_modes", displayModes);
    }
};

Lua-Based Custom Visualization

-- Custom visualization system using Lua scripting
local ui = api.ui
local logger = api.logger

-- Custom visualizer state
local customVisualizer = {
    config = {
        bbox_style = "rounded_rectangle",
        color_scheme = "traffic_light",
        animation_enabled = true,
        fade_duration = 2000, -- ms
        confidence_bar = true,
        track_trails = true,
        trail_length = 10
    },
    track_history = {},
    animation_state = {}
}

-- Initialize custom visualizer
function initializeCustomVisualizer()
    logger.info("Initializing custom Lua-based visualizer")

    -- Setup color schemes
    customVisualizer.color_schemes = {
        traffic_light = {
            high_confidence = {0, 255, 0, 255},    -- Green
            medium_confidence = {255, 255, 0, 255}, -- Yellow  
            low_confidence = {255, 0, 0, 255}       -- Red
        },
        thermal = {
            high_confidence = {255, 0, 0, 255},     -- Hot red
            medium_confidence = {255, 128, 0, 255}, -- Orange
            low_confidence = {0, 0, 255, 255}       -- Cool blue
        }
    }
end

-- Main rendering function
function renderCustomVisualizations(detections)
    if not detections or #detections == 0 then
        return
    end

    local currentTime = os.time()

    -- Process each detection
    for _, detection in ipairs(detections) do
        renderCustomDetection(detection, currentTime)
    end

    -- Update animations
    updateAnimations(currentTime)
end

-- Render individual detection with custom styling
function renderCustomDetection(detection, currentTime)
    local x, y, w, h = detection.x, detection.y, detection.w, detection.h
    local confidence = detection.confidence or 0.0
    local trackId = detection.track_id

    -- Determine color based on confidence
    local color = getConfidenceColor(confidence)

    -- Apply animation effects
    if customVisualizer.config.animation_enabled then
        color = applyAnimationEffects(color, detection, currentTime)
    end

    -- Render detection based on style
    if customVisualizer.config.bbox_style == "rounded_rectangle" then
        renderRoundedBbox(x, y, w, h, color, confidence)
    elseif customVisualizer.config.bbox_style == "gradient_box" then
        renderGradientBbox(x, y, w, h, color, confidence)
    elseif customVisualizer.config.bbox_style == "neon_glow" then
        renderNeonBbox(x, y, w, h, color, confidence)
    end

    -- Render confidence bar
    if customVisualizer.config.confidence_bar then
        renderConfidenceBar(x, y, w, confidence, color)
    end

    -- Render track trails
    if customVisualizer.config.track_trails and trackId then
        renderTrackTrail(trackId, x + w/2, y + h/2, color)
    end

    -- Render enhanced labels
    renderEnhancedLabel(detection, x, y, color)
end

-- Get color based on confidence level
function getConfidenceColor(confidence)
    local scheme = customVisualizer.color_schemes[customVisualizer.config.color_scheme]

    if confidence >= 0.8 then
        return scheme.high_confidence
    elseif confidence >= 0.5 then
        return scheme.medium_confidence
    else
        return scheme.low_confidence
    end
end

-- Apply animation effects to color
function applyAnimationEffects(color, detection, currentTime)
    local animKey = detection.id or (detection.x .. "_" .. detection.y)

    -- Initialize animation state if needed
    if not customVisualizer.animation_state[animKey] then
        customVisualizer.animation_state[animKey] = {
            start_time = currentTime,
            fade_progress = 0.0
        }
    end

    local animState = customVisualizer.animation_state[animKey]
    local elapsed = currentTime - animState.start_time

    -- Calculate fade effect
    if elapsed < customVisualizer.config.fade_duration then
        local progress = elapsed / customVisualizer.config.fade_duration
        local alpha_multiplier = 0.3 + 0.7 * (1.0 - progress) -- Fade from 100% to 30%

        return {
            color[1], 
            color[2], 
            color[3], 
            math.floor(color[4] * alpha_multiplier)
        }
    end

    return color
end

-- Render rounded rectangle bbox
function renderRoundedBbox(x, y, w, h, color, confidence)
    local rounding = math.min(w, h) * 0.1 -- 10% of smaller dimension
    local thickness = math.max(2, confidence * 4) -- Thickness based on confidence

    -- Draw rounded rectangle
    ui.drawRoundedRect(x, y, w, h, rounding, color, thickness)

    -- Optional fill for high confidence
    if confidence > 0.9 then
        local fillColor = {color[1], color[2], color[3], 32} -- Semi-transparent
        ui.drawRoundedRect(x, y, w, h, rounding, fillColor, -1) -- Filled
    end
end

-- Render gradient-style bbox
function renderGradientBbox(x, y, w, h, color, confidence)
    local steps = 5
    local thickness = 2

    -- Draw multiple rectangles with varying alpha for gradient effect
    for i = 0, steps - 1 do
        local offset = i * 2
        local alpha = color[4] * (1.0 - i / steps * 0.7)
        local gradColor = {color[1], color[2], color[3], math.floor(alpha)}

        ui.drawRect(x - offset, y - offset, w + 2*offset, h + 2*offset, gradColor, thickness)
    end
end

-- Render neon glow effect bbox
function renderNeonBbox(x, y, w, h, color, confidence)
    local glowRadius = math.floor(confidence * 10)

    -- Draw multiple layers for glow effect
    for i = glowRadius, 1, -1 do
        local alpha = math.floor(255 * confidence * (1.0 - i / glowRadius) * 0.3)
        local glowColor = {color[1], color[2], color[3], alpha}

        ui.drawRect(x - i, y - i, w + 2*i, h + 2*i, glowColor, 1)
    end

    -- Main bbox
    ui.drawRect(x, y, w, h, color, 2)
end

-- Render confidence bar
function renderConfidenceBar(x, y, w, confidence, color)
    local barHeight = 4
    local barY = y + barHeight + 2

    -- Background bar
    local bgColor = {128, 128, 128, 128}
    ui.drawRect(x, barY, w, barHeight, bgColor, -1)

    -- Confidence fill
    local fillWidth = w * confidence
    ui.drawRect(x, barY, fillWidth, barHeight, color, -1)
end

-- Render track trail
function renderTrackTrail(trackId, centerX, centerY, color)
    -- Update track history
    if not customVisualizer.track_history[trackId] then
        customVisualizer.track_history[trackId] = {}
    end

    local history = customVisualizer.track_history[trackId]
    table.insert(history, {x = centerX, y = centerY})

    -- Keep only recent history
    local maxLength = customVisualizer.config.trail_length
    if #history > maxLength then
        table.remove(history, 1)
    end

    -- Draw trail
    for i = 2, #history do
        local prev = history[i - 1]
        local curr = history[i]

        -- Trail alpha decreases with age
        local alpha = math.floor(color[4] * (i / #history) * 0.6)
        local trailColor = {color[1], color[2], color[3], alpha}

        ui.drawLine(prev.x, prev.y, curr.x, curr.y, trailColor, 2)

        -- Draw point
        ui.drawCircle(curr.x, curr.y, 2, trailColor, -1)
    end
end

-- Render enhanced label with background and effects
function renderEnhancedLabel(detection, x, y, color)
    local label = detection.label or "Unknown"
    local confidence = detection.confidence or 0.0
    local labelText = string.format("%s (%.1f%%)", label, confidence * 100)

    -- Calculate label dimensions
    local fontSize = 0.8
    local padding = 8
    local labelWidth = string.len(labelText) * fontSize * 8 -- Approximate
    local labelHeight = 20

    -- Label position (above bbox)
    local labelX = x
    local labelY = y - labelHeight - 5

    -- Background rectangle
    local bgColor = {0, 0, 0, 180} -- Semi-transparent black
    ui.drawRect(labelX, labelY, labelWidth + padding, labelHeight, bgColor, -1)

    -- Border
    ui.drawRect(labelX, labelY, labelWidth + padding, labelHeight, color, 1)

    -- Text
    ui.drawText(labelText, labelX + padding/2, labelY + 5, fontSize, color)

    -- Optional: Add icons for specific classes
    if detection.label == "person" then
        -- Draw person icon (simplified)
        ui.drawCircle(labelX + labelWidth + 5, labelY + 10, 4, color, -1)
    elseif detection.label == "vehicle" then
        -- Draw vehicle icon (simplified)
        ui.drawRect(labelX + labelWidth + 2, labelY + 6, 8, 8, color, -1)
    end
end

-- Update animation states
function updateAnimations(currentTime)
    local fadeTime = customVisualizer.config.fade_duration

    -- Clean up old animation states
    for key, state in pairs(customVisualizer.animation_state) do
        if currentTime - state.start_time > fadeTime then
            customVisualizer.animation_state[key] = nil
        end
    end

    -- Clean up old track histories
    for trackId, history in pairs(customVisualizer.track_history) do
        if #history == 0 then
            customVisualizer.track_history[trackId] = nil
        end
    end
end

-- Configuration interface
function configureCustomVisualizer(config)
    if config.bbox_style then
        customVisualizer.config.bbox_style = config.bbox_style
    end

    if config.color_scheme then
        customVisualizer.config.color_scheme = config.color_scheme
    end

    if config.animation_enabled ~= nil then
        customVisualizer.config.animation_enabled = config.animation_enabled
    end

    if config.confidence_bar ~= nil then
        customVisualizer.config.confidence_bar = config.confidence_bar
    end

    if config.track_trails ~= nil then
        customVisualizer.config.track_trails = config.track_trails
    end
end

-- Initialize the custom visualizer
initializeCustomVisualizer()

logger.info("Custom Lua visualizer system is ready")

Best Practices

Performance Optimization

  • Selective Rendering: Only render visible elements and use culling for off-screen objects
  • Level of Detail: Reduce rendering complexity for distant or small objects
  • Batch Rendering: Group similar rendering operations to minimize state changes
  • Caching: Cache expensive computations like text metrics and image data

Visual Design

  • Color Consistency: Use consistent color schemes across different visualizers
  • Contrast: Ensure sufficient contrast between overlays and background video
  • Information Hierarchy: Use size, color, and opacity to indicate importance
  • Accessibility: Consider color-blind friendly palettes and alternative visual cues

User Experience

  • Interactive Feedback: Provide immediate visual feedback for user interactions
  • Contextual Information: Show relevant information based on hover and selection states
  • Customization: Allow users to customize visual styles and information display
  • Performance Indicators: Show system performance metrics when appropriate

Integration Guidelines

  • Modular Design: Keep visualizers loosely coupled and easily replaceable
  • Configuration Management: Use centralized configuration with runtime updates
  • Event Integration: Connect visualizers with event systems for reactive updates
  • Cross-Platform: Test visualizations across different platforms and display densities

Troubleshooting

Common Issues

Poor Rendering Performance

// Performance monitoring for visualizers
void monitorVisualizationPerformance() {
    static auto lastTime = std::chrono::high_resolution_clock::now();
    auto currentTime = std::chrono::high_resolution_clock::now();
    auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(currentTime - lastTime);

    if (duration.count() > 33) { // More than 30 FPS threshold
        LOGW << "Visualization rendering taking too long: " << duration.count() << "ms";
        // Consider reducing complexity or enabling performance optimizations
    }

    lastTime = currentTime;
}

Solutions: - Reduce the number of rendered elements - Use lower level of detail for distant objects - Enable hardware acceleration where available - Optimize drawing operations and reduce overdraw

Visual Artifacts

// Check for common visual issues
void validateRenderingParameters(const RenderConfig& config) {
    // Check color values
    for (auto& color : config.colors) {
        if (color < 0 || color > 255) {
            LOGW << "Invalid color value: " << color;
        }
    }

    // Check dimensions
    if (config.thickness <= 0) {
        LOGW << "Invalid thickness value: " << config.thickness;
    }

    // Check transparency
    if (config.transparency < 0.0f || config.transparency > 1.0f) {
        LOGW << "Invalid transparency value: " << config.transparency;
    }
}

Solutions: - Validate all rendering parameters before use - Check for coordinate system mismatches - Ensure proper alpha blending settings - Verify image format compatibility

Missing Text or Labels

-- Debug text rendering issues
function debugTextRendering(text, x, y, fontSize, color)
    print(string.format("Rendering text: '%s' at (%d, %d), size: %.2f", 
                     text, x, y, fontSize))

    -- Check if position is within screen bounds
    if x < 0 or y < 0 then
        print("Warning: Text position is off-screen")
    end

    -- Check font size
    if fontSize <= 0 then
        print("Warning: Invalid font size: " .. tostring(fontSize))
    end

    ui.drawText(text, x, y, fontSize, color)
end

Solutions: - Verify font loading and availability - Check text positioning and clipping - Ensure proper font scaling for different resolutions - Validate text encoding for special characters

ImGui Context Issues

// Ensure proper ImGui context handling
class VisualizerContextManager {
public:
    void setContext(std::shared_ptr<Visualizer> visualizer, ImGuiContext* context) {
        if (!context) {
            LOGE << "Null ImGui context provided";
            return;
        }

        visualizer->setCurrentContext(context);

        // Verify context is properly set
        auto currentContext = visualizer->getCurrentContext();
        if (currentContext != context) {
            LOGE << "Failed to set ImGui context";
        }
    }
};

Solutions: - Ensure ImGui context is properly initialized before use - Verify context switching between different visualizers - Check for context conflicts in multi-threaded scenarios - Validate ImGui version compatibility

Debug Tools

// Comprehensive visualization debugging system
class VisualizationDebugger {
public:
    void debugVisualization(const std::string& visualizerType, 
                           pCValue input, 
                           pCValue config) {
        LOGI << "=== Visualization Debug ===";
        LOGI << "Visualizer Type: " << visualizerType;

        // Debug input data
        debugInputData(input);

        // Debug configuration
        debugConfiguration(config);

        // Check system resources
        debugSystemResources();
    }

private:
    void debugInputData(pCValue input) {
        if (!input) {
            LOGW << "No input data provided";
            return;
        }

        LOGI << "Input data type: " << input->getTypeName();

        if (input->isArray()) {
            LOGI << "Input array size: " << input->size();
        }
    }

    void debugConfiguration(pCValue config) {
        if (!config) {
            LOGW << "No configuration provided";
            return;
        }

        // Log key configuration parameters
        auto keys = config->getKeys();
        for (const auto& key : keys) {
            auto value = config->get(key);
            LOGI << "Config[" << key << "] = " << value->toString();
        }
    }

    void debugSystemResources() {
        // Check available memory
        // Check GPU memory if applicable
        // Log system performance metrics
    }
};

Integration Examples

Security System Integration

// Security monitoring system with advanced visualizations
class SecurityVisualizationSystem {
public:
    void initialize() {
        setupSecurityVisualizers();
        configureSecurity();
    }

    void renderSecurityFrame(const SecurityAnalysis& analysis) {
        // Render different security elements with appropriate styling
        renderIntruderDetections(analysis.intruders);
        renderSecurityZones(analysis.zones);
        renderTripwireStatus(analysis.tripwires);
        renderAlertOverlays(analysis.alerts);
        renderSecurityMetrics(analysis.metrics);
    }

private:
    void setupSecurityVisualizers() {
        // High-visibility styling for security applications
        auto securityConfig = createSecurityConfig();

        bboxVisualizer_->configure(securityConfig.bbox);
        zoneVisualizer_->configure(securityConfig.zones);
        lineVisualizer_->configure(securityConfig.tripwires);
        textVisualizer_->configure(securityConfig.alerts);
    }
};

See Also