Skip to main content

Advanced Usage

Advanced use cases and patterns for the SAM3 detector filter.

Pipeline IntegrationDirect link to Pipeline Integration

Multi-Filter PipelinesDirect link to Multi-Filter Pipelines

Combine SAM3 detector with other OpenFilter filters:

from openfilter.filter_runtime.filter import Filter
from openfilter.filter_runtime.filters.video_in import VideoIn
from openfilter.filter_runtime.filters.resize import Resize
from openfilter.filter_runtime.filters.filter_by_score import FilterByScore
from openfilter.filter_runtime.filters.recorder import Recorder
from filter_sam3_detector import FilterSAM3Detector

filters = [
# Input: Stream video frames
(VideoIn, {
"sources": "file://input.mp4",
"outputs": ["tcp://127.0.0.1:5555"],
}),

# Pre-processing: Resize for performance
(Resize, {
"sources": "tcp://127.0.0.1:5555",
"outputs": ["tcp://127.0.0.1:5556"],
"width": 640,
"height": 480,
}),

# Detection: SAM3 detector
(FilterSAM3Detector, {
"sources": "tcp://127.0.0.1:5556",
"outputs": ["tcp://127.0.0.1:5557"],
"text_prompt": "person",
"confidence_threshold": 0.5,
}),

# Post-processing: Filter by confidence
(FilterByScore, {
"sources": "tcp://127.0.0.1:5557",
"outputs": ["tcp://127.0.0.1:5558"],
"min_score": 0.7,
}),

# Output: Save results
(Recorder, {
"sources": "tcp://127.0.0.1:5558",
"path": "detections.jsonl",
"format": "jsonl",
}),
]

Filter.run_multi(filters)

Topic ForwardingDirect link to Topic Forwarding

Preserve original frames while adding detections:

# Using same imports from above example
filters = [
(VideoIn, {
"sources": "file://input.mp4",
"outputs": ["tcp://127.0.0.1:5555", "tcp://127.0.0.1:5559"], # Split output
}),

# Detection branch
(FilterSAM3Detector, {
"sources": "tcp://127.0.0.1:5555",
"outputs": ["tcp://127.0.0.1:5556"],
"text_prompt": "person",
}),

(Recorder, {
"sources": "tcp://127.0.0.1:5556",
"path": "detections.jsonl",
}),

# Original frames branch (preserved)
(Recorder, {
"sources": "tcp://127.0.0.1:5559",
"path": "original_frames.jsonl",
}),
]

Custom ProcessingDirect link to Custom Processing

Accessing Detection ResultsDirect link to Accessing Detection Results

from openfilter.filter_runtime.filter import Filter, Frame
from filter_sam3_detector import FilterSAM3Detector

class CustomProcessor(Filter):
def process(self, frames: dict[str, Frame]) -> dict[str, Frame]:
output_frames = {}

for topic, frame in frames.items():
# Access detections
detections = frame.data.get('meta', {}).get('sam3_detections', [])

# Process detections
for det in detections:
box = det['box']
score = det['score']

# Custom logic here
if score > 0.8:
# High confidence detection
pass

output_frames[topic] = frame

return output_frames

# Use in pipeline
filters = [
(FilterSAM3Detector, {
"sources": "tcp://127.0.0.1:5555",
"outputs": ["tcp://127.0.0.1:5556"],
"text_prompt": "person",
}),
(CustomProcessor, {
"sources": "tcp://127.0.0.1:5556",
"outputs": ["tcp://127.0.0.1:5557"],
}),
]

Filtering DetectionsDirect link to Filtering Detections

def filter_high_confidence(frames):
"""Keep only high-confidence detections."""
output_frames = {}

for topic, frame in frames.items():
detections = frame.data.get('meta', {}).get('sam3_detections', [])

# Filter by confidence
filtered = [d for d in detections if d['score'] > 0.7]

# Update frame
frame.data.setdefault('meta', {})['sam3_detections'] = filtered
output_frames[topic] = frame

return output_frames

Batch ProcessingDirect link to Batch Processing

Processing Multiple VideosDirect link to Processing Multiple Videos

from pathlib import Path

video_files = [
"video1.mp4",
"video2.mp4",
"video3.mp4",
]

for video in video_files:
filters = [
(VideoIn, {
"sources": f"file://{Path(video).absolute()}",
"outputs": ["tcp://127.0.0.1:5555"],
}),
(FilterSAM3Detector, {
"sources": "tcp://127.0.0.1:5555",
"outputs": ["tcp://127.0.0.1:5556"],
"text_prompt": "person",
}),
(Recorder, {
"sources": "tcp://127.0.0.1:5556",
"path": f"output_{Path(video).stem}.jsonl",
}),
]

Filter.run_multi(filters)

Dynamic ConfigurationDirect link to Dynamic Configuration

Runtime Configuration ChangesDirect link to Runtime Configuration Changes

class DynamicDetector(Filter):
def setup(self, config):
self.base_config = config
self.current_prompt = config.get("text_prompt", "person")

def process(self, frames):
# Change prompt based on frame content
if self.should_switch_prompt(frames):
self.current_prompt = "car"

# Create detector with current prompt
detector = FilterSAM3Detector({
**self.base_config,
"text_prompt": self.current_prompt,
})
detector.setup(detector.normalize_config({
**self.base_config,
"text_prompt": self.current_prompt,
}))

return detector.process(frames)

Performance OptimizationDirect link to Performance Optimization

Async ProcessingDirect link to Async Processing

import asyncio
from concurrent.futures import ThreadPoolExecutor

async def process_video_async(video_path, prompt):
loop = asyncio.get_event_loop()
executor = ThreadPoolExecutor()

def run_pipeline():
filters = [
(VideoIn, {"sources": f"file://{video_path}"}),
(FilterSAM3Detector, {"text_prompt": prompt}),
(Recorder, {"path": f"output_{video_path}.jsonl"}),
]
Filter.run_multi(filters)

return await loop.run_in_executor(executor, run_pipeline)

# Process multiple videos concurrently
async def main():
videos = ["video1.mp4", "video2.mp4", "video3.mp4"]
tasks = [process_video_async(v, "person") for v in videos]
results = await asyncio.gather(*tasks)

asyncio.run(main())

Memory ManagementDirect link to Memory Management

class MemoryEfficientDetector(Filter):
def setup(self, config):
# Disable masks to save memory
config["output_masks"] = False
config["max_detections"] = 20

self.detector = FilterSAM3Detector()
self.detector.setup(self.detector.normalize_config(config))

def process(self, frames):
# Process in batches
batch_size = 10
results = {}

frame_list = list(frames.items())
for i in range(0, len(frame_list), batch_size):
batch = dict(frame_list[i:i+batch_size])
batch_results = self.detector.process(batch)
results.update(batch_results)

return results

Error HandlingDirect link to Error Handling

Robust PipelineDirect link to Robust Pipeline

class RobustDetector(Filter):
def setup(self, config):
self.config = config
self.detector = None
self.error_count = 0
self.max_errors = 10

def process(self, frames):
if self.detector is None:
try:
self.detector = FilterSAM3Detector()
self.detector.setup(
self.detector.normalize_config(self.config)
)
except Exception as e:
logger.error(f"Failed to initialize detector: {e}")
return frames # Forward unchanged

try:
return self.detector.process(frames)
except Exception as e:
self.error_count += 1
logger.error(f"Processing error ({self.error_count}/{self.max_errors}): {e}")

if self.error_count >= self.max_errors:
logger.error("Too many errors, reinitializing detector")
self.detector = None
self.error_count = 0

return frames # Forward unchanged on error

Integration ExamplesDirect link to Integration Examples

With DatabaseDirect link to With Database

import sqlite3

class DatabaseRecorder(Filter):
def setup(self, config):
self.db_path = config.get("db_path", "detections.db")
self.conn = sqlite3.connect(self.db_path)
self.conn.execute("""
CREATE TABLE IF NOT EXISTS detections (
frame_id INTEGER,
box_x1 INTEGER, box_y1 INTEGER, box_x2 INTEGER, box_y2 INTEGER,
score REAL,
timestamp DATETIME DEFAULT CURRENT_TIMESTAMP
)
""")

def process(self, frames):
for topic, frame in frames.items():
detections = frame.data.get('meta', {}).get('sam3_detections', [])

for det in detections:
box = det['box']
self.conn.execute(
"INSERT INTO detections (frame_id, box_x1, box_y1, box_x2, box_y2, score) VALUES (?, ?, ?, ?, ?, ?)",
(frame.data.get('frame_id', 0), box[0], box[1], box[2], box[3], det['score'])
)

self.conn.commit()

return frames

With Web APIDirect link to With Web API

import requests

class APISender(Filter):
def setup(self, config):
self.api_url = config.get("api_url")
self.api_key = config.get("api_key")

def process(self, frames):
for topic, frame in frames.items():
detections = frame.data.get('meta', {}).get('sam3_detections', [])

if detections:
response = requests.post(
self.api_url,
json={"detections": detections},
headers={"Authorization": f"Bearer {self.api_key}"}
)
response.raise_for_status()

return frames