matrice-analytics 0.1.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of matrice-analytics might be problematic. Click here for more details.
- matrice_analytics/__init__.py +28 -0
- matrice_analytics/boundary_drawing_internal/README.md +305 -0
- matrice_analytics/boundary_drawing_internal/__init__.py +45 -0
- matrice_analytics/boundary_drawing_internal/boundary_drawing_internal.py +1207 -0
- matrice_analytics/boundary_drawing_internal/boundary_drawing_tool.py +429 -0
- matrice_analytics/boundary_drawing_internal/boundary_tool_template.html +1036 -0
- matrice_analytics/boundary_drawing_internal/data/.gitignore +12 -0
- matrice_analytics/boundary_drawing_internal/example_usage.py +206 -0
- matrice_analytics/boundary_drawing_internal/usage/README.md +110 -0
- matrice_analytics/boundary_drawing_internal/usage/boundary_drawer_launcher.py +102 -0
- matrice_analytics/boundary_drawing_internal/usage/simple_boundary_launcher.py +107 -0
- matrice_analytics/post_processing/README.md +455 -0
- matrice_analytics/post_processing/__init__.py +732 -0
- matrice_analytics/post_processing/advanced_tracker/README.md +650 -0
- matrice_analytics/post_processing/advanced_tracker/__init__.py +17 -0
- matrice_analytics/post_processing/advanced_tracker/base.py +99 -0
- matrice_analytics/post_processing/advanced_tracker/config.py +77 -0
- matrice_analytics/post_processing/advanced_tracker/kalman_filter.py +370 -0
- matrice_analytics/post_processing/advanced_tracker/matching.py +195 -0
- matrice_analytics/post_processing/advanced_tracker/strack.py +230 -0
- matrice_analytics/post_processing/advanced_tracker/tracker.py +367 -0
- matrice_analytics/post_processing/config.py +142 -0
- matrice_analytics/post_processing/core/__init__.py +63 -0
- matrice_analytics/post_processing/core/base.py +704 -0
- matrice_analytics/post_processing/core/config.py +3188 -0
- matrice_analytics/post_processing/core/config_utils.py +925 -0
- matrice_analytics/post_processing/face_reg/__init__.py +43 -0
- matrice_analytics/post_processing/face_reg/compare_similarity.py +556 -0
- matrice_analytics/post_processing/face_reg/embedding_manager.py +681 -0
- matrice_analytics/post_processing/face_reg/face_recognition.py +1870 -0
- matrice_analytics/post_processing/face_reg/face_recognition_client.py +339 -0
- matrice_analytics/post_processing/face_reg/people_activity_logging.py +283 -0
- matrice_analytics/post_processing/ocr/__init__.py +0 -0
- matrice_analytics/post_processing/ocr/easyocr_extractor.py +248 -0
- matrice_analytics/post_processing/ocr/postprocessing.py +271 -0
- matrice_analytics/post_processing/ocr/preprocessing.py +52 -0
- matrice_analytics/post_processing/post_processor.py +1153 -0
- matrice_analytics/post_processing/test_cases/__init__.py +1 -0
- matrice_analytics/post_processing/test_cases/run_tests.py +143 -0
- matrice_analytics/post_processing/test_cases/test_advanced_customer_service.py +841 -0
- matrice_analytics/post_processing/test_cases/test_basic_counting_tracking.py +523 -0
- matrice_analytics/post_processing/test_cases/test_comprehensive.py +531 -0
- matrice_analytics/post_processing/test_cases/test_config.py +852 -0
- matrice_analytics/post_processing/test_cases/test_customer_service.py +585 -0
- matrice_analytics/post_processing/test_cases/test_data_generators.py +583 -0
- matrice_analytics/post_processing/test_cases/test_people_counting.py +510 -0
- matrice_analytics/post_processing/test_cases/test_processor.py +524 -0
- matrice_analytics/post_processing/test_cases/test_utilities.py +356 -0
- matrice_analytics/post_processing/test_cases/test_utils.py +743 -0
- matrice_analytics/post_processing/usecases/Histopathological_Cancer_Detection_img.py +604 -0
- matrice_analytics/post_processing/usecases/__init__.py +267 -0
- matrice_analytics/post_processing/usecases/abandoned_object_detection.py +797 -0
- matrice_analytics/post_processing/usecases/advanced_customer_service.py +1601 -0
- matrice_analytics/post_processing/usecases/age_detection.py +842 -0
- matrice_analytics/post_processing/usecases/age_gender_detection.py +1043 -0
- matrice_analytics/post_processing/usecases/anti_spoofing_detection.py +656 -0
- matrice_analytics/post_processing/usecases/assembly_line_detection.py +841 -0
- matrice_analytics/post_processing/usecases/banana_defect_detection.py +624 -0
- matrice_analytics/post_processing/usecases/basic_counting_tracking.py +667 -0
- matrice_analytics/post_processing/usecases/blood_cancer_detection_img.py +881 -0
- matrice_analytics/post_processing/usecases/car_damage_detection.py +834 -0
- matrice_analytics/post_processing/usecases/car_part_segmentation.py +946 -0
- matrice_analytics/post_processing/usecases/car_service.py +1601 -0
- matrice_analytics/post_processing/usecases/cardiomegaly_classification.py +864 -0
- matrice_analytics/post_processing/usecases/cell_microscopy_segmentation.py +897 -0
- matrice_analytics/post_processing/usecases/chicken_pose_detection.py +648 -0
- matrice_analytics/post_processing/usecases/child_monitoring.py +814 -0
- matrice_analytics/post_processing/usecases/color/clip.py +232 -0
- matrice_analytics/post_processing/usecases/color/clip_processor/merges.txt +48895 -0
- matrice_analytics/post_processing/usecases/color/clip_processor/preprocessor_config.json +28 -0
- matrice_analytics/post_processing/usecases/color/clip_processor/special_tokens_map.json +30 -0
- matrice_analytics/post_processing/usecases/color/clip_processor/tokenizer.json +245079 -0
- matrice_analytics/post_processing/usecases/color/clip_processor/tokenizer_config.json +32 -0
- matrice_analytics/post_processing/usecases/color/clip_processor/vocab.json +1 -0
- matrice_analytics/post_processing/usecases/color/color_map_utils.py +70 -0
- matrice_analytics/post_processing/usecases/color/color_mapper.py +468 -0
- matrice_analytics/post_processing/usecases/color_detection.py +1835 -0
- matrice_analytics/post_processing/usecases/color_map_utils.py +70 -0
- matrice_analytics/post_processing/usecases/concrete_crack_detection.py +827 -0
- matrice_analytics/post_processing/usecases/crop_weed_detection.py +781 -0
- matrice_analytics/post_processing/usecases/customer_service.py +1008 -0
- matrice_analytics/post_processing/usecases/defect_detection_products.py +936 -0
- matrice_analytics/post_processing/usecases/distracted_driver_detection.py +822 -0
- matrice_analytics/post_processing/usecases/drone_traffic_monitoring.py +930 -0
- matrice_analytics/post_processing/usecases/drowsy_driver_detection.py +829 -0
- matrice_analytics/post_processing/usecases/dwell_detection.py +829 -0
- matrice_analytics/post_processing/usecases/emergency_vehicle_detection.py +827 -0
- matrice_analytics/post_processing/usecases/face_emotion.py +813 -0
- matrice_analytics/post_processing/usecases/face_recognition.py +827 -0
- matrice_analytics/post_processing/usecases/fashion_detection.py +835 -0
- matrice_analytics/post_processing/usecases/field_mapping.py +902 -0
- matrice_analytics/post_processing/usecases/fire_detection.py +1112 -0
- matrice_analytics/post_processing/usecases/flare_analysis.py +891 -0
- matrice_analytics/post_processing/usecases/flower_segmentation.py +1006 -0
- matrice_analytics/post_processing/usecases/gas_leak_detection.py +837 -0
- matrice_analytics/post_processing/usecases/gender_detection.py +832 -0
- matrice_analytics/post_processing/usecases/human_activity_recognition.py +871 -0
- matrice_analytics/post_processing/usecases/intrusion_detection.py +1672 -0
- matrice_analytics/post_processing/usecases/leaf.py +821 -0
- matrice_analytics/post_processing/usecases/leaf_disease.py +840 -0
- matrice_analytics/post_processing/usecases/leak_detection.py +837 -0
- matrice_analytics/post_processing/usecases/license_plate_detection.py +914 -0
- matrice_analytics/post_processing/usecases/license_plate_monitoring.py +1194 -0
- matrice_analytics/post_processing/usecases/litter_monitoring.py +717 -0
- matrice_analytics/post_processing/usecases/mask_detection.py +869 -0
- matrice_analytics/post_processing/usecases/natural_disaster.py +907 -0
- matrice_analytics/post_processing/usecases/parking.py +787 -0
- matrice_analytics/post_processing/usecases/parking_space_detection.py +822 -0
- matrice_analytics/post_processing/usecases/pcb_defect_detection.py +888 -0
- matrice_analytics/post_processing/usecases/pedestrian_detection.py +808 -0
- matrice_analytics/post_processing/usecases/people_counting.py +1728 -0
- matrice_analytics/post_processing/usecases/people_tracking.py +1842 -0
- matrice_analytics/post_processing/usecases/pipeline_detection.py +605 -0
- matrice_analytics/post_processing/usecases/plaque_segmentation_img.py +874 -0
- matrice_analytics/post_processing/usecases/pothole_segmentation.py +915 -0
- matrice_analytics/post_processing/usecases/ppe_compliance.py +645 -0
- matrice_analytics/post_processing/usecases/price_tag_detection.py +822 -0
- matrice_analytics/post_processing/usecases/proximity_detection.py +1901 -0
- matrice_analytics/post_processing/usecases/road_lane_detection.py +623 -0
- matrice_analytics/post_processing/usecases/road_traffic_density.py +832 -0
- matrice_analytics/post_processing/usecases/road_view_segmentation.py +915 -0
- matrice_analytics/post_processing/usecases/shelf_inventory_detection.py +583 -0
- matrice_analytics/post_processing/usecases/shoplifting_detection.py +822 -0
- matrice_analytics/post_processing/usecases/shopping_cart_analysis.py +899 -0
- matrice_analytics/post_processing/usecases/skin_cancer_classification_img.py +864 -0
- matrice_analytics/post_processing/usecases/smoker_detection.py +833 -0
- matrice_analytics/post_processing/usecases/solar_panel.py +810 -0
- matrice_analytics/post_processing/usecases/suspicious_activity_detection.py +1030 -0
- matrice_analytics/post_processing/usecases/template_usecase.py +380 -0
- matrice_analytics/post_processing/usecases/theft_detection.py +648 -0
- matrice_analytics/post_processing/usecases/traffic_sign_monitoring.py +724 -0
- matrice_analytics/post_processing/usecases/underground_pipeline_defect_detection.py +775 -0
- matrice_analytics/post_processing/usecases/underwater_pollution_detection.py +842 -0
- matrice_analytics/post_processing/usecases/vehicle_monitoring.py +950 -0
- matrice_analytics/post_processing/usecases/warehouse_object_segmentation.py +899 -0
- matrice_analytics/post_processing/usecases/waterbody_segmentation.py +923 -0
- matrice_analytics/post_processing/usecases/weapon_detection.py +771 -0
- matrice_analytics/post_processing/usecases/weld_defect_detection.py +615 -0
- matrice_analytics/post_processing/usecases/wildlife_monitoring.py +898 -0
- matrice_analytics/post_processing/usecases/windmill_maintenance.py +834 -0
- matrice_analytics/post_processing/usecases/wound_segmentation.py +856 -0
- matrice_analytics/post_processing/utils/__init__.py +150 -0
- matrice_analytics/post_processing/utils/advanced_counting_utils.py +400 -0
- matrice_analytics/post_processing/utils/advanced_helper_utils.py +317 -0
- matrice_analytics/post_processing/utils/advanced_tracking_utils.py +461 -0
- matrice_analytics/post_processing/utils/alerting_utils.py +213 -0
- matrice_analytics/post_processing/utils/category_mapping_utils.py +94 -0
- matrice_analytics/post_processing/utils/color_utils.py +592 -0
- matrice_analytics/post_processing/utils/counting_utils.py +182 -0
- matrice_analytics/post_processing/utils/filter_utils.py +261 -0
- matrice_analytics/post_processing/utils/format_utils.py +293 -0
- matrice_analytics/post_processing/utils/geometry_utils.py +300 -0
- matrice_analytics/post_processing/utils/smoothing_utils.py +358 -0
- matrice_analytics/post_processing/utils/tracking_utils.py +234 -0
- matrice_analytics/py.typed +0 -0
- matrice_analytics-0.1.2.dist-info/METADATA +481 -0
- matrice_analytics-0.1.2.dist-info/RECORD +160 -0
- matrice_analytics-0.1.2.dist-info/WHEEL +5 -0
- matrice_analytics-0.1.2.dist-info/licenses/LICENSE.txt +21 -0
- matrice_analytics-0.1.2.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,380 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Template Use Case for creating new standardized use cases.
|
|
3
|
+
|
|
4
|
+
This template shows how to create a new use case that follows the standardized
|
|
5
|
+
agg_summary structure. Copy this file and modify it for your specific use case.
|
|
6
|
+
|
|
7
|
+
Example use case: Fire Detection
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from typing import Any, Dict, List, Optional, Union
|
|
11
|
+
from dataclasses import asdict
|
|
12
|
+
import time
|
|
13
|
+
|
|
14
|
+
from ..core.base import BaseProcessor, ProcessingContext, ProcessingResult, ConfigProtocol, ResultFormat
|
|
15
|
+
from ..core.config import BaseConfig
|
|
16
|
+
from ..utils import (
|
|
17
|
+
filter_by_confidence,
|
|
18
|
+
filter_by_categories,
|
|
19
|
+
apply_category_mapping,
|
|
20
|
+
count_objects_by_category,
|
|
21
|
+
calculate_counting_summary,
|
|
22
|
+
match_results_structure
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class TemplateUseCaseConfig(BaseConfig):
|
|
27
|
+
"""Configuration for Template Use Case."""
|
|
28
|
+
|
|
29
|
+
def __init__(self,
|
|
30
|
+
usecase: str = "template_usecase",
|
|
31
|
+
category: str = "general",
|
|
32
|
+
confidence_threshold: float = 0.5,
|
|
33
|
+
target_categories: List[str] = None,
|
|
34
|
+
enable_analytics: bool = True,
|
|
35
|
+
alert_threshold: int = 5,
|
|
36
|
+
**kwargs):
|
|
37
|
+
super().__init__(usecase=usecase, category=category, **kwargs)
|
|
38
|
+
self.confidence_threshold = confidence_threshold
|
|
39
|
+
self.target_categories = target_categories or ["fire", "smoke"] # Example categories
|
|
40
|
+
self.enable_analytics = enable_analytics
|
|
41
|
+
self.alert_threshold = alert_threshold
|
|
42
|
+
|
|
43
|
+
def validate(self) -> List[str]:
|
|
44
|
+
"""Validate configuration."""
|
|
45
|
+
errors = super().validate()
|
|
46
|
+
|
|
47
|
+
if not 0.0 <= self.confidence_threshold <= 1.0:
|
|
48
|
+
errors.append("confidence_threshold must be between 0.0 and 1.0")
|
|
49
|
+
|
|
50
|
+
if self.alert_threshold < 1:
|
|
51
|
+
errors.append("alert_threshold must be positive")
|
|
52
|
+
|
|
53
|
+
return errors
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
class TemplateUseCase(BaseProcessor):
|
|
57
|
+
"""Template use case showing how to implement standardized agg_summary structure."""
|
|
58
|
+
|
|
59
|
+
def __init__(self):
|
|
60
|
+
"""Initialize template use case."""
|
|
61
|
+
super().__init__("template_usecase")
|
|
62
|
+
self.category = "general"
|
|
63
|
+
|
|
64
|
+
# Add any state tracking variables here
|
|
65
|
+
self._detection_count = 0
|
|
66
|
+
self._total_detections = 0
|
|
67
|
+
|
|
68
|
+
def get_config_schema(self) -> Dict[str, Any]:
|
|
69
|
+
"""Get configuration schema for template use case."""
|
|
70
|
+
return {
|
|
71
|
+
"type": "object",
|
|
72
|
+
"properties": {
|
|
73
|
+
"confidence_threshold": {
|
|
74
|
+
"type": "number",
|
|
75
|
+
"minimum": 0.0,
|
|
76
|
+
"maximum": 1.0,
|
|
77
|
+
"default": 0.5,
|
|
78
|
+
"description": "Minimum confidence threshold for detections"
|
|
79
|
+
},
|
|
80
|
+
"target_categories": {
|
|
81
|
+
"type": "array",
|
|
82
|
+
"items": {"type": "string"},
|
|
83
|
+
"default": ["fire", "smoke"],
|
|
84
|
+
"description": "Target categories to detect"
|
|
85
|
+
},
|
|
86
|
+
"enable_analytics": {
|
|
87
|
+
"type": "boolean",
|
|
88
|
+
"default": True,
|
|
89
|
+
"description": "Enable analytics generation"
|
|
90
|
+
},
|
|
91
|
+
"alert_threshold": {
|
|
92
|
+
"type": "integer",
|
|
93
|
+
"minimum": 1,
|
|
94
|
+
"default": 5,
|
|
95
|
+
"description": "Threshold for generating alerts"
|
|
96
|
+
}
|
|
97
|
+
},
|
|
98
|
+
"required": ["confidence_threshold"],
|
|
99
|
+
"additionalProperties": False
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
def create_default_config(self, **overrides) -> TemplateUseCaseConfig:
|
|
103
|
+
"""Create default configuration with optional overrides."""
|
|
104
|
+
defaults = {
|
|
105
|
+
"category": self.category,
|
|
106
|
+
"usecase": self.name,
|
|
107
|
+
"confidence_threshold": 0.5,
|
|
108
|
+
"target_categories": ["fire", "smoke"],
|
|
109
|
+
"enable_analytics": True,
|
|
110
|
+
"alert_threshold": 5,
|
|
111
|
+
}
|
|
112
|
+
defaults.update(overrides)
|
|
113
|
+
return TemplateUseCaseConfig(**defaults)
|
|
114
|
+
|
|
115
|
+
def process(self, data: Any, config: ConfigProtocol,
|
|
116
|
+
context: Optional[ProcessingContext] = None,
|
|
117
|
+
stream_info: Optional[Any] = None) -> ProcessingResult:
|
|
118
|
+
"""
|
|
119
|
+
Process data using template use case - automatically detects single or multi-frame structure.
|
|
120
|
+
|
|
121
|
+
Args:
|
|
122
|
+
data: Raw model output (detection or tracking format)
|
|
123
|
+
config: Template use case configuration
|
|
124
|
+
context: Processing context
|
|
125
|
+
stream_info: Stream information (optional)
|
|
126
|
+
|
|
127
|
+
Returns:
|
|
128
|
+
ProcessingResult: Processing result with standardized agg_summary structure
|
|
129
|
+
"""
|
|
130
|
+
try:
|
|
131
|
+
# Ensure we have the right config type
|
|
132
|
+
if not isinstance(config, TemplateUseCaseConfig):
|
|
133
|
+
return self.create_error_result(
|
|
134
|
+
"Invalid configuration type for template use case",
|
|
135
|
+
usecase=self.name,
|
|
136
|
+
category=self.category,
|
|
137
|
+
context=context
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
# Initialize processing context if not provided
|
|
141
|
+
if context is None:
|
|
142
|
+
context = ProcessingContext()
|
|
143
|
+
|
|
144
|
+
# Detect frame structure automatically
|
|
145
|
+
is_multi_frame = self.detect_frame_structure(data)
|
|
146
|
+
|
|
147
|
+
self.logger.info(f"Processing template use case - Multi-frame: {is_multi_frame}")
|
|
148
|
+
|
|
149
|
+
# Process based on frame structure
|
|
150
|
+
if is_multi_frame:
|
|
151
|
+
agg_summary = self._process_multi_frame(data, config, stream_info)
|
|
152
|
+
else:
|
|
153
|
+
agg_summary = self._process_single_frame(data, config, stream_info)
|
|
154
|
+
|
|
155
|
+
# Mark processing as completed
|
|
156
|
+
context.mark_completed()
|
|
157
|
+
|
|
158
|
+
# Create result with standardized agg_summary
|
|
159
|
+
return self.create_result(
|
|
160
|
+
data={"agg_summary": agg_summary},
|
|
161
|
+
usecase=self.name,
|
|
162
|
+
category=self.category,
|
|
163
|
+
context=context
|
|
164
|
+
)
|
|
165
|
+
|
|
166
|
+
except Exception as e:
|
|
167
|
+
self.logger.error(f"Template use case failed: {str(e)}", exc_info=True)
|
|
168
|
+
|
|
169
|
+
if context:
|
|
170
|
+
context.mark_completed()
|
|
171
|
+
|
|
172
|
+
return self.create_error_result(
|
|
173
|
+
str(e),
|
|
174
|
+
type(e).__name__,
|
|
175
|
+
usecase=self.name,
|
|
176
|
+
category=self.category,
|
|
177
|
+
context=context
|
|
178
|
+
)
|
|
179
|
+
|
|
180
|
+
def _process_multi_frame(self, data: Dict, config: TemplateUseCaseConfig,
|
|
181
|
+
stream_info: Optional[Dict[str, Any]] = None) -> Dict[str, Any]:
|
|
182
|
+
"""Process multi-frame data to generate frame-wise agg_summary."""
|
|
183
|
+
|
|
184
|
+
frame_incidents = {}
|
|
185
|
+
frame_tracking_stats = {}
|
|
186
|
+
frame_business_analytics = {}
|
|
187
|
+
frame_human_text = {}
|
|
188
|
+
|
|
189
|
+
# Process each frame individually
|
|
190
|
+
for frame_key, frame_detections in data.items():
|
|
191
|
+
frame_id = str(frame_key)
|
|
192
|
+
|
|
193
|
+
# Process this single frame's detections
|
|
194
|
+
incidents, tracking_stats, business_analytics, summary = self._process_frame_detections(
|
|
195
|
+
frame_detections, config, frame_id, stream_info
|
|
196
|
+
)
|
|
197
|
+
|
|
198
|
+
# Store frame-wise results
|
|
199
|
+
if incidents:
|
|
200
|
+
frame_incidents[frame_id] = incidents
|
|
201
|
+
if tracking_stats:
|
|
202
|
+
frame_tracking_stats[frame_id] = tracking_stats
|
|
203
|
+
if business_analytics:
|
|
204
|
+
frame_business_analytics[frame_id] = business_analytics
|
|
205
|
+
if summary:
|
|
206
|
+
frame_human_text[frame_id] = summary
|
|
207
|
+
|
|
208
|
+
# Create frame-wise agg_summary
|
|
209
|
+
return self.create_frame_wise_agg_summary(
|
|
210
|
+
frame_incidents, frame_tracking_stats, frame_business_analytics,
|
|
211
|
+
frame_human_text=frame_human_text
|
|
212
|
+
)
|
|
213
|
+
|
|
214
|
+
def _process_single_frame(self, data: Any, config: TemplateUseCaseConfig,
|
|
215
|
+
stream_info: Optional[Dict[str, Any]] = None) -> Dict[str, Any]:
|
|
216
|
+
"""Process single frame data and return standardized agg_summary."""
|
|
217
|
+
|
|
218
|
+
# Process frame data
|
|
219
|
+
incidents, tracking_stats, business_analytics, summary = self._process_frame_detections(
|
|
220
|
+
data, config, "current_frame", stream_info
|
|
221
|
+
)
|
|
222
|
+
|
|
223
|
+
# Create single-frame agg_summary
|
|
224
|
+
return self.create_agg_summary(
|
|
225
|
+
"current_frame", incidents, tracking_stats, business_analytics, human_text=summary
|
|
226
|
+
)
|
|
227
|
+
|
|
228
|
+
def _process_frame_detections(self, frame_data: Any, config: TemplateUseCaseConfig,
|
|
229
|
+
frame_id: str, stream_info: Optional[Dict[str, Any]] = None) -> tuple:
|
|
230
|
+
"""Process detections from a single frame and return standardized components."""
|
|
231
|
+
|
|
232
|
+
# Convert frame_data to list if it's not already
|
|
233
|
+
if isinstance(frame_data, list):
|
|
234
|
+
detections = frame_data
|
|
235
|
+
else:
|
|
236
|
+
# Handle other formats as needed
|
|
237
|
+
detections = []
|
|
238
|
+
|
|
239
|
+
# Step 1: Apply confidence filtering
|
|
240
|
+
if config.confidence_threshold is not None:
|
|
241
|
+
detections = [d for d in detections if d.get("confidence", 0) >= config.confidence_threshold]
|
|
242
|
+
|
|
243
|
+
# Step 2: Apply category mapping if provided
|
|
244
|
+
if config.index_to_category:
|
|
245
|
+
detections = apply_category_mapping(detections, config.index_to_category)
|
|
246
|
+
|
|
247
|
+
# Step 3: Filter to target categories
|
|
248
|
+
if config.target_categories:
|
|
249
|
+
detections = [d for d in detections if d.get("category") in config.target_categories]
|
|
250
|
+
|
|
251
|
+
# Step 4: Update internal state
|
|
252
|
+
current_count = len(detections)
|
|
253
|
+
self._detection_count = current_count
|
|
254
|
+
self._total_detections += current_count
|
|
255
|
+
|
|
256
|
+
# Step 5: Generate standardized components
|
|
257
|
+
incidents = self._generate_incidents(detections, config, frame_id, stream_info)
|
|
258
|
+
tracking_stats = self._generate_tracking_stats(detections, config, stream_info)
|
|
259
|
+
business_analytics = self._generate_business_analytics(detections, config, stream_info) if config.enable_analytics else []
|
|
260
|
+
summary = self._generate_summary(detections, config)
|
|
261
|
+
|
|
262
|
+
return incidents, tracking_stats, business_analytics, summary
|
|
263
|
+
|
|
264
|
+
def _generate_incidents(self, detections: List[Dict], config: TemplateUseCaseConfig,
|
|
265
|
+
frame_id: str, stream_info: Optional[Dict[str, Any]] = None) -> List[Dict]:
|
|
266
|
+
"""Generate standardized incidents."""
|
|
267
|
+
incidents = []
|
|
268
|
+
|
|
269
|
+
if len(detections) > 0:
|
|
270
|
+
# Determine severity level based on detection count
|
|
271
|
+
severity_level = self.determine_severity_level(
|
|
272
|
+
len(detections), threshold_low=1, threshold_medium=3, threshold_critical=config.alert_threshold
|
|
273
|
+
)
|
|
274
|
+
|
|
275
|
+
# Get camera info
|
|
276
|
+
camera_info = self.get_camera_info_from_stream(stream_info)
|
|
277
|
+
|
|
278
|
+
# Create incident
|
|
279
|
+
incident_id = f"template_detection_{frame_id}_{int(time.time())}"
|
|
280
|
+
incident_text = f"Template detection event with {len(detections)} detections [Severity: {severity_level}]"
|
|
281
|
+
|
|
282
|
+
incident = self.create_incident(
|
|
283
|
+
incident_id, "template_detection", severity_level,
|
|
284
|
+
incident_text, camera_info
|
|
285
|
+
)
|
|
286
|
+
incidents.append(incident)
|
|
287
|
+
|
|
288
|
+
return incidents
|
|
289
|
+
|
|
290
|
+
def _generate_tracking_stats(self, detections: List[Dict], config: TemplateUseCaseConfig,
|
|
291
|
+
stream_info: Optional[Dict[str, Any]] = None) -> List[Dict]:
|
|
292
|
+
"""Generate standardized tracking stats."""
|
|
293
|
+
|
|
294
|
+
# Get camera info
|
|
295
|
+
camera_info = self.get_camera_info_from_stream(stream_info)
|
|
296
|
+
|
|
297
|
+
# Build total_counts and current_counts
|
|
298
|
+
total_counts = []
|
|
299
|
+
current_counts = []
|
|
300
|
+
|
|
301
|
+
for category in config.target_categories:
|
|
302
|
+
category_current = sum(1 for d in detections if d.get("category") == category)
|
|
303
|
+
category_total = self._total_detections # This would be category-specific in real implementation
|
|
304
|
+
|
|
305
|
+
if category_current > 0:
|
|
306
|
+
current_counts.append(self.create_count_object(category, category_current))
|
|
307
|
+
if category_total > 0:
|
|
308
|
+
total_counts.append(self.create_count_object(category, category_total))
|
|
309
|
+
|
|
310
|
+
# Prepare detections for tracking stats (without confidence and track_id)
|
|
311
|
+
tracking_detections = []
|
|
312
|
+
for detection in detections:
|
|
313
|
+
bbox = detection.get("bounding_box", {})
|
|
314
|
+
category = detection.get("category", "unknown")
|
|
315
|
+
|
|
316
|
+
detection_obj = self.create_detection_object(category, bbox)
|
|
317
|
+
tracking_detections.append(detection_obj)
|
|
318
|
+
|
|
319
|
+
# Generate human text
|
|
320
|
+
current_timestamp = self.get_high_precision_timestamp()
|
|
321
|
+
human_text = self.generate_tracking_human_text(
|
|
322
|
+
{cat: sum(1 for d in detections if d.get("category") == cat) for cat in config.target_categories},
|
|
323
|
+
{cat: self._total_detections for cat in config.target_categories}, # Simplified
|
|
324
|
+
current_timestamp, current_timestamp
|
|
325
|
+
)
|
|
326
|
+
|
|
327
|
+
# Create tracking stats
|
|
328
|
+
tracking_stat = self.create_tracking_stats(
|
|
329
|
+
total_counts, current_counts, tracking_detections, human_text, camera_info
|
|
330
|
+
)
|
|
331
|
+
|
|
332
|
+
return [tracking_stat]
|
|
333
|
+
|
|
334
|
+
def _generate_business_analytics(self, detections: List[Dict], config: TemplateUseCaseConfig,
|
|
335
|
+
stream_info: Optional[Dict[str, Any]] = None) -> List[Dict]:
|
|
336
|
+
"""Generate standardized business analytics."""
|
|
337
|
+
|
|
338
|
+
# Get camera info
|
|
339
|
+
camera_info = self.get_camera_info_from_stream(stream_info)
|
|
340
|
+
|
|
341
|
+
# Calculate analytics statistics
|
|
342
|
+
analytics_stats = {
|
|
343
|
+
"detection_count": len(detections),
|
|
344
|
+
"total_detections": self._total_detections,
|
|
345
|
+
"detection_rate": len(detections) / max(1, self._total_detections) * 100
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
# Add category breakdown
|
|
349
|
+
for category in config.target_categories:
|
|
350
|
+
category_count = sum(1 for d in detections if d.get("category") == category)
|
|
351
|
+
analytics_stats[f"{category}_count"] = category_count
|
|
352
|
+
|
|
353
|
+
# Generate human text
|
|
354
|
+
current_timestamp = self.get_high_precision_timestamp()
|
|
355
|
+
analytics_human_text = self.generate_analytics_human_text(
|
|
356
|
+
"template_analytics", analytics_stats, current_timestamp, current_timestamp
|
|
357
|
+
)
|
|
358
|
+
|
|
359
|
+
# Create business analytics
|
|
360
|
+
analytics = self.create_business_analytics(
|
|
361
|
+
"template_analytics", analytics_stats, analytics_human_text, camera_info
|
|
362
|
+
)
|
|
363
|
+
|
|
364
|
+
return [analytics]
|
|
365
|
+
|
|
366
|
+
def _generate_summary(self, detections: List[Dict], config: TemplateUseCaseConfig) -> str:
|
|
367
|
+
"""Generate human-readable summary."""
|
|
368
|
+
if len(detections) == 0:
|
|
369
|
+
return "No detections found"
|
|
370
|
+
|
|
371
|
+
category_counts = {}
|
|
372
|
+
for detection in detections:
|
|
373
|
+
category = detection.get("category", "unknown")
|
|
374
|
+
category_counts[category] = category_counts.get(category, 0) + 1
|
|
375
|
+
|
|
376
|
+
summary_parts = []
|
|
377
|
+
for category, count in category_counts.items():
|
|
378
|
+
summary_parts.append(f"{count} {category} detection{'s' if count != 1 else ''}")
|
|
379
|
+
|
|
380
|
+
return f"Template Use Case: {', '.join(summary_parts)} detected"
|