Skip to main content

Filter Protege Model - Technical Documentation

This document provides detailed technical information about the Filter Protege Model implementation, architecture, and usage patterns.

Table of ContentsDirect link to Table of Contents

  1. Architecture Overview
  2. Implementation Details
  3. Configuration Reference
  4. API Reference
  5. Development Guide
  6. Testing
  7. Generic Filter Usage Guide - How to use the filter with different task types

Architecture OverviewDirect link to Architecture Overview

Base/Abstract PatternDirect link to Base/Abstract Pattern

The filter uses a robust base/abstract class pattern for extensibility:

BaseModel (Abstract)
├── OCRModel (Concrete)
├── DetectionModel (Future)
├── SegmentationModel (Future)
└── ClassificationModel (Future)

BaseModel Features:

  • Common interface for all model types
  • Performance monitoring and timing
  • Error handling and validation
  • Utility methods for visualization
  • Confidence threshold management

Optional Visualization with Separate TopicsDirect link to Optional Visualization with Separate Topics

Visualization is optional and uses separate ZMQ topics:

# When visualization is enabled:
return {
"main": Frame(original_image, frame_data, "BGR"),
"viz": Frame(annotated_image, viz_data, "BGR")
}

# When visualization is disabled:
return {
"main": Frame(original_image, frame_data, "BGR")
}

Benefits:

  • Downstream consumers can choose which stream to process
  • Original frame is not modified
  • Optimized performance (optional visualization)
  • Facilitated debugging (original vs annotated frame comparison)

Data SignatureDirect link to Data Signature

The filter implements a standardized data structure for consistent downstream processing:

Frame Metadata Structure:

For OCR models:

{
"ocr_texts": ["fgj235", "another_text"],
"ocr_confidence": 0.999,
"ocr_architecture": "TPS_ResNet_BiLSTM_Attn",
"ocr_processing_time": 0.040160179138183594,
"ocr_timestamp": 1754418436.610824
}

For Detection models:

{
"detections": [
{"label": "person", "confidence": 0.95, "box": [x1, y1, x2, y2]},
{"label": "car", "confidence": 0.87, "box": [x1, y1, x2, y2]}
],
"detection_confidence": 0.91
}

For Multilabel Classification models:

{
"classes": ["avocado", "fish", "chicken"],
"confidences": [0.9828291535377502, 0.8622298240661621, 0.7891234567890123],
"architecture": "resnet50",
"timestamp": 1760985061.0605319,
"filter_id": "filter_protege_multilabel_classification"
}

For Regular Classification models:

{
"classes": ["cat"],
"confidences": [0.95],
"architecture": "resnet18",
"timestamp": 1760985061.0605319,
"filter_id": "filter_protege_classification"
}

Key Design Principles:

  • Multiple Detections: Support for multiple detections per frame
  • Array Format: All detections returned as arrays for consistency
  • Confidence Filtering: Only detections above threshold included
  • JSON Serializable: All data structures are JSON serializable
  • Model-specific Fields: Each model type adds its own specific fields to metadata

Implementation DetailsDirect link to Implementation Details

Main ClassesDirect link to Main Classes

FilterProtegeModelDirect link to FilterProtegeModel

Main filter class that:

  • Manages processing pipeline
  • Configures optional visualization
  • Coordinates between model and runtime
  • Returns processed frames
  • Monitors performance and timing
class FilterProtegeModel(Filter):
def setup(self, config: FilterProtegeModelConfig):
# Initialize runtime and model
# Auto-detect device and configurations
pass

def process(self, frames: dict[str, Frame]):
# Process frames with timing
# Return results with optional visualization
pass

BaseModelDirect link to BaseModel

Abstract class that defines common interface:

  • process_frame(): Process frame and return results
  • create_visualization(): Create visualization of results
  • Manages runtime and configurations
  • Monitors performance and statistics
class BaseModel(ABC):
@abstractmethod
def process_frame(self, frame, frame_id, frame_meta):
pass

@abstractmethod
def create_visualization(self, image, results):
pass

def process_frame_with_timing(self, frame, frame_id, frame_meta):
# Wrapper with timing and statistics
pass

OCRModelDirect link to OCRModel

Concrete implementation for OCR:

  • Inherits from BaseModel
  • Processes frames for text extraction
  • Creates visualization with overlaid text
  • Uses AlignCollate for preprocessing
  • Validates confidence threshold
class OCRModel(BaseModel):
def process_frame(self, frame, frame_id, frame_meta):
# Convert to grayscale
# Preprocess with AlignCollate
# Execute OCR inference
# Validate confidence threshold
# Return text and confidence
pass

def create_visualization(self, image, results):
# Draw extracted text
# Show confidence score
# Use BaseModel utility method
pass

ConfigurationDirect link to Configuration

FilterProtegeModelConfigDirect link to FilterProtegeModelConfig

Filter configuration with:

  • Visualization parameters
  • Model configurations
  • OCR-specific configurations
  • Comprehensive validation
class FilterProtegeModelConfig(FilterConfig):
draw_visualization: bool = False
visualization_topic: str = "viz"
visualization_alpha: float = 0.7
protege_confidence_threshold: float = 0.5
ocr_img_height: int = 32
ocr_img_width: int = 100

Configuration ReferenceDirect link to Configuration Reference

Environment VariablesDirect link to Environment Variables

VariableTypeDefaultDescription
FILTER_MODEL_ARTIFACT_PATHstrRequiredPath to Protege model artifact
FILTER_DEVICEstrautoDevice to use (cpu, cuda, or auto)
FILTER_PROTEGE_CONFIDENCE_THRESHOLDfloat0.5Confidence threshold for detection
FILTER_PROTEGE_TASKstrautoTask type (ocr, detection, etc.)
FILTER_OCR_IMG_HEIGHTint32Image height for OCR preprocessing
FILTER_OCR_IMG_WIDTHint100Image width for OCR preprocessing
FILTER_DRAW_VISUALIZATIONboolfalseEnable visualization
FILTER_VISUALIZATION_TOPICstrvizTopic name for visualization
FILTER_VISUALIZATION_ALPHAfloat0.7Transparency for overlays
FILTER_VISUALIZATION_SOURCE_TOPICstrSource topic for main visualization (e.g., main, viz_chit)

Auto-Detection FeaturesDirect link to Auto-Detection Features

The filter automatically detects:

  • Task Type: From model's .MODELCONFIG.json file
  • Architecture: From runtime.artifact.architecture
  • Device: CPU/CUDA availability
  • Dimensions: OCR preprocessing dimensions

API ReferenceDirect link to API Reference

FilterProtegeModelConfigDirect link to FilterProtegeModelConfig

class FilterProtegeModelConfig(FilterConfig):
# Visualization options
draw_visualization: bool = False
visualization_topic: str = "viz"
visualization_alpha: float = 0.7
visualization_source_topic: str = None

# Model options
model_artifact_path: str = None
device: str = None
protege_confidence_threshold: float = 0.5
protege_task: str = None

# OCR options
ocr_img_height: int = 32
ocr_img_width: int = 100

BaseModelDirect link to BaseModel

class BaseModel(ABC):
def process_frame(self, frame, frame_id, frame_meta):
"""Process a single frame and return results."""
pass

def create_visualization(self, image, results):
"""Create visualization of results."""
pass

def get_processing_stats(self):
"""Get processing statistics."""
pass

def reset_processing_stats(self):
"""Reset processing statistics."""
pass

OCRModelDirect link to OCRModel

class OCRModel(BaseModel):
def process_frame(self, frame, frame_id, frame_meta):
"""Process frame for OCR text extraction."""
# Implementation details...
pass

def create_visualization(self, image, results):
"""Create OCR visualization with text overlay."""
# Implementation details...
pass

Development GuideDirect link to Development Guide

Adding New Model TypesDirect link to Adding New Model Types

To add a new model type (e.g., DetectionModel):

  1. Create a new file in filter_protege_model/models/
  2. Inherit from BaseModel
  3. Implement required abstract methods
  4. Add to filter_protege_model/models/__init__.py

Example:

# filter_protege_model/models/detection_model.py
from .base_model import BaseModel

class DetectionModel(BaseModel):
def process_frame(self, frame, frame_id, frame_meta):
# Detection-specific processing
pass

def create_visualization(self, image, results):
# Detection-specific visualization
pass

Performance MonitoringDirect link to Performance Monitoring

The filter includes comprehensive performance monitoring:

# Get processing statistics
stats = model.get_processing_stats()
print(f"Average processing time: {stats['avg_processing_time']:.3f}s")
print(f"Total frames processed: {stats['total_frames']}")
print(f"Error count: {stats['error_count']}")

# Reset statistics
model.reset_processing_stats()

Error HandlingDirect link to Error Handling

The filter includes robust error handling:

# Error information in results
{
"error": "Model inference failed",
"error_type": "RuntimeError",
"processing_time": 0.123,
"timestamp": "2024-01-01T12:00:00Z"
}

TestingDirect link to Testing

Running TestsDirect link to Running Tests

# Run all tests
make test

# Run with coverage
make test-coverage

# Run specific test file
pytest tests/test_ocr_model_and_visualization.py -v

Test StructureDirect link to Test Structure

  • test_filter_integration.py: Integration tests
  • test_ocr_model_and_visualization.py: OCR model and visualization tests

Test CoverageDirect link to Test Coverage

The tests cover:

  • Model initialization and configuration
  • Frame processing and OCR extraction
  • Visualization creation
  • Error handling scenarios
  • Performance monitoring
  • Configuration validation

Comparison with Other FiltersDirect link to Comparison with Other Filters

The improved implementation follows the same patterns as other OpenFilter filters:

FeatureSpyEye FilterProtege Filter
Base class pattern✅✅
Optional visualization✅✅
Separate viz topic✅✅
Performance monitoring✅✅
Error handling✅✅
Configuration validation✅✅

Data Signature ReferenceDirect link to Data Signature Reference

OCR Task Data StructureDirect link to OCR Task Data Structure

The filter implements a standardized data signature for consistent downstream processing:

Frame Metadata StructureDirect link to Frame Metadata Structure

For OCR models:

{
"ocr_texts": ["fgj235", "another_text"],
"ocr_confidence": 0.999,
"ocr_architecture": "TPS_ResNet_BiLSTM_Attn",
"ocr_processing_time": 0.040160179138183594,
"ocr_timestamp": 1754418436.610824
}

For Detection models:

{
"detections": [
{
"class": "person",
"rois": [[x1, y1, x2, y2]]
},
{
"class": "car",
"rois": [[x1, y1, x2, y2], [x3, y3, x4, y4]]
}
],
"detection_confidence": 0.91
}

Main Frame DataDirect link to Main Frame Data

  • Original frame data preserved
  • Processing results stored in frame metadata by each model type

Data Field DescriptionsDirect link to Data Field Descriptions

For OCR models:

FieldTypeDescription
ocr_textsarray[string]Array of detected text strings
ocr_confidencefloatAverage confidence score (0.0-1.0)
ocr_architecturestringModel architecture name
ocr_processing_timefloatTime taken for processing (seconds)
ocr_timestampfloatProcessing timestamp

For Detection models:

FieldTypeDescription
detectionsarray[object]Array of detection objects grouped by class with multiple ROIs
detection_confidencefloatAverage confidence score (0.0-1.0)
detections[].classstringClass name of the detected object
detections[].roisarray[array[float]]Array of bounding boxes for this class (normalized coordinates)

For Multilabel Classification models:

FieldTypeDescription
classesarray[string]Array of detected class names
confidencesarray[float]Array of confidence scores for each class (0.0-1.0)
architecturestringModel architecture name
timestampfloatProcessing timestamp
filter_idstringFilter identifier

Design PrinciplesDirect link to Design Principles

  1. Multiple Detections: Support for multiple detections per frame
  2. Array Format: All detections returned as arrays for consistency
  3. Confidence Filtering: Only detections above threshold included
  4. JSON Serializable: All data structures are JSON serializable
  5. Model-specific Fields: Each model type adds its own specific fields to metadata
  6. Empty Arrays: Indicate no detections or all below threshold

Multilabel Classification Specific FeaturesDirect link to Multilabel Classification Specific Features

Non-exclusive Classification:

  • Multiple classes can be detected simultaneously in a single frame
  • Each class has an independent confidence score
  • Uses sigmoid activation instead of softmax for independent probabilities
  • Supports simultaneous detection of multiple non-exclusive classes

Enhanced Visualization:

  • Larger fonts for better readability of multiple labels
  • Consistent green color scheme for all multilabel classes
  • Enhanced spacing to prevent text overlap
  • Support for flexible positioning (left, right, top, bottom)
  • Background rectangles for improved text visibility

Testing Support:

  • Comprehensive test suite in test_multilabel_task_support.py
  • Tests sigmoid activation vs softmax behavior
  • Validates multiple class detection
  • Tests confidence threshold filtering
  • Verifies enhanced visualization features

Configuration Options:

  • classification_confidence_threshold: Threshold for each class (default: 0.8)
  • classification_sigmoid: Use sigmoid activation (default: True)
  • classification_class_names: List of class names for multilabel classification
  • max_objects_per_frame: Maximum number of objects to detect per frame (default: None, no limit)

Output Format:

  • classes: Array of detected class names
  • confidences: Array of confidence scores aligned with classes
  • architecture: Model architecture identifier
  • timestamp: Processing timestamp
  • filter_id: Filter instance identifier

Usage ExamplesDirect link to Usage Examples

# Access frame metadata
frame_meta = frame.data.get('meta', {})

# For OCR models
if 'ocr_texts' in frame_meta:
texts = frame_meta['ocr_texts']
confidence = frame_meta['ocr_confidence']
architecture = frame_meta['ocr_architecture']

if texts:
print(f"Detected {len(texts)} texts: {texts}")
print(f"Confidence: {confidence}")
print(f"Architecture: {architecture}")
else:
print("No text detected")

# For Detection models
elif 'detections' in frame_meta:
detections = frame_meta['detections']
confidence = frame_meta['detection_confidence']

if detections:
print(f"Detected {len(detections)} object classes")
print(f"Confidence: {confidence}")

# Process each class and its ROIs
for detection in detections:
class_name = detection['class']
rois = detection['rois']
print(f" {class_name}: {len(rois)} ROI(s)")
for i, roi in enumerate(rois):
print(f" ROI {i+1}: {roi}")
else:
print("No objects detected")

# For Multilabel Classification models
elif 'classes' in frame_meta:
classes = frame_meta['classes']
confidences = frame_meta['confidences']
architecture = frame_meta.get('architecture', 'unknown')

if classes:
print(f"Detected {len(classes)} classes: {classes}")
print(f"Confidences: {confidences}")
print(f"Architecture: {architecture}")

# Process each class with its confidence
for class_name, confidence in zip(classes, confidences):
print(f" {class_name}: {confidence:.3f}")
else:
print("No classes detected above threshold")

Future EnhancementsDirect link to Future Enhancements

The current architecture supports easy addition of:

  1. New Model Types: Detection, segmentation, classification
  2. Advanced Visualization: Custom drawing utilities
  3. Caching: Frame caching for performance
  4. Batch Processing: Multi-frame processing
  5. Metrics Export: Prometheus/OpenTelemetry integration
  6. Model Versioning: Support for multiple model versions
  7. A/B Testing: Multiple model comparison
  8. Custom Preprocessing: User-defined preprocessing pipelines