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¶
- Renderer Plugin - Cross-platform rendering capabilities
- LuaEngine Plugin - Lua scripting for custom visualizations
- Instance Plugin - Runtime instance management
- All Plugins - Complete plugin ecosystem
- UI Development Guide - User interface development patterns