matrice-analytics 0.1.106__py3-none-any.whl → 0.1.124__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.
- matrice_analytics/post_processing/__init__.py +22 -0
- matrice_analytics/post_processing/config.py +15 -0
- matrice_analytics/post_processing/core/config.py +107 -1
- matrice_analytics/post_processing/face_reg/face_recognition.py +2 -2
- matrice_analytics/post_processing/post_processor.py +16 -0
- matrice_analytics/post_processing/usecases/__init__.py +9 -0
- matrice_analytics/post_processing/usecases/crowdflow.py +1088 -0
- matrice_analytics/post_processing/usecases/footfall.py +103 -62
- matrice_analytics/post_processing/usecases/license_plate_monitoring.py +2 -1
- matrice_analytics/post_processing/usecases/parking_lot_analytics.py +1137 -0
- matrice_analytics/post_processing/usecases/vehicle_monitoring.py +30 -4
- matrice_analytics/post_processing/usecases/vehicle_monitoring_drone_view.py +33 -6
- matrice_analytics/post_processing/usecases/vehicle_monitoring_parking_lot.py +18 -2
- matrice_analytics/post_processing/usecases/vehicle_monitoring_wrong_way.py +1021 -0
- matrice_analytics/post_processing/utils/alert_instance_utils.py +18 -5
- matrice_analytics/post_processing/utils/business_metrics_manager_utils.py +25 -2
- matrice_analytics/post_processing/utils/incident_manager_utils.py +12 -1
- matrice_analytics/post_processing/utils/parking_analytics_tracker.py +359 -0
- matrice_analytics/post_processing/utils/wrong_way_tracker.py +670 -0
- {matrice_analytics-0.1.106.dist-info → matrice_analytics-0.1.124.dist-info}/METADATA +1 -1
- {matrice_analytics-0.1.106.dist-info → matrice_analytics-0.1.124.dist-info}/RECORD +24 -19
- {matrice_analytics-0.1.106.dist-info → matrice_analytics-0.1.124.dist-info}/WHEEL +0 -0
- {matrice_analytics-0.1.106.dist-info → matrice_analytics-0.1.124.dist-info}/licenses/LICENSE.txt +0 -0
- {matrice_analytics-0.1.106.dist-info → matrice_analytics-0.1.124.dist-info}/top_level.txt +0 -0
|
@@ -30,6 +30,10 @@ class VehicleMonitoringConfig(BaseConfig):
|
|
|
30
30
|
smoothing_confidence_range_factor: float = 0.5
|
|
31
31
|
confidence_threshold: float = 0.6
|
|
32
32
|
|
|
33
|
+
# Class Aggregation: Configuration parameters
|
|
34
|
+
enable_class_aggregation: bool = True
|
|
35
|
+
class_aggregation_window_size: int = 30 # 30 frames ≈ 1 second at 30 FPS
|
|
36
|
+
|
|
33
37
|
#JBK_720_GATE POLYGON = [[86, 328], [844, 317], [1277, 520], [1273, 707], [125, 713]]
|
|
34
38
|
zone_config: Optional[Dict[str, List[List[float]]]] = None #field(
|
|
35
39
|
# default_factory=lambda: {
|
|
@@ -107,8 +111,24 @@ class VehicleMonitoringUseCase(BaseProcessor):
|
|
|
107
111
|
def process(self, data: Any, config: ConfigProtocol, context: Optional[ProcessingContext] = None,
|
|
108
112
|
stream_info: Optional[Dict[str, Any]] = None) -> ProcessingResult:
|
|
109
113
|
processing_start = time.time()
|
|
110
|
-
|
|
111
|
-
|
|
114
|
+
# Relaxed check: Accept VehicleMonitoringConfig OR any config with matching usecase/category
|
|
115
|
+
# This handles multiprocessing module path mismatches while maintaining type safety
|
|
116
|
+
is_valid_config = (
|
|
117
|
+
isinstance(config, VehicleMonitoringConfig) or
|
|
118
|
+
(hasattr(config, 'usecase') and config.usecase == 'vehicle_monitoring' and
|
|
119
|
+
hasattr(config, 'category') and config.category == 'traffic')
|
|
120
|
+
)
|
|
121
|
+
if not is_valid_config:
|
|
122
|
+
self.logger.error(
|
|
123
|
+
f"Config validation failed in vehicle_monitoring. "
|
|
124
|
+
f"Got type={type(config).__name__}, module={type(config).__module__}, "
|
|
125
|
+
f"usecase={getattr(config, 'usecase', 'N/A')}, category={getattr(config, 'category', 'N/A')}"
|
|
126
|
+
)
|
|
127
|
+
return self.create_error_result(
|
|
128
|
+
f"Invalid config type: expected VehicleMonitoringConfig or config with usecase='vehicle_monitoring', "
|
|
129
|
+
f"got {type(config).__name__} with usecase={getattr(config, 'usecase', 'N/A')}",
|
|
130
|
+
usecase=self.name, category=self.category, context=context
|
|
131
|
+
)
|
|
112
132
|
if context is None:
|
|
113
133
|
context = ProcessingContext()
|
|
114
134
|
|
|
@@ -158,9 +178,15 @@ class VehicleMonitoringUseCase(BaseProcessor):
|
|
|
158
178
|
from ..advanced_tracker import AdvancedTracker
|
|
159
179
|
from ..advanced_tracker.config import TrackerConfig
|
|
160
180
|
if self.tracker is None:
|
|
161
|
-
tracker_config = TrackerConfig(
|
|
181
|
+
tracker_config = TrackerConfig(
|
|
182
|
+
enable_class_aggregation=config.enable_class_aggregation,
|
|
183
|
+
class_aggregation_window_size=config.class_aggregation_window_size
|
|
184
|
+
)
|
|
162
185
|
self.tracker = AdvancedTracker(tracker_config)
|
|
163
|
-
self.logger.info(
|
|
186
|
+
self.logger.info(
|
|
187
|
+
f"Initialized AdvancedTracker for Vehicle Monitoring "
|
|
188
|
+
f"(class_aggregation={config.enable_class_aggregation})"
|
|
189
|
+
)
|
|
164
190
|
processed_data = self.tracker.update(processed_data)
|
|
165
191
|
except Exception as e:
|
|
166
192
|
self.logger.warning(f"AdvancedTracker failed: {e}")
|
|
@@ -1115,18 +1115,33 @@ class VehicleMonitoringDroneViewUseCase(BaseProcessor):
|
|
|
1115
1115
|
self._tracking_start_time = time.time()
|
|
1116
1116
|
|
|
1117
1117
|
|
|
1118
|
-
def _log_detection_stats(
|
|
1118
|
+
def _log_detection_stats(
|
|
1119
|
+
self,
|
|
1120
|
+
data: Any,
|
|
1121
|
+
stage_name: str,
|
|
1122
|
+
show_samples: bool = False
|
|
1123
|
+
) -> None:
|
|
1119
1124
|
"""
|
|
1120
|
-
Log detailed detection statistics at any pipeline stage.
|
|
1125
|
+
Log detailed detection statistics at any pipeline stage with frame identification.
|
|
1121
1126
|
|
|
1122
1127
|
Args:
|
|
1123
1128
|
data: Detection data (list or dict format)
|
|
1124
1129
|
stage_name: Name of the pipeline stage for identification
|
|
1125
1130
|
show_samples: If True, show sample detection structure
|
|
1126
1131
|
"""
|
|
1132
|
+
if not getattr(self, '_debug_detection_flow', True):
|
|
1133
|
+
return
|
|
1134
|
+
|
|
1135
|
+
# Use existing frame counter
|
|
1136
|
+
frame_id = self._total_frame_counter
|
|
1137
|
+
timestamp_str = datetime.now(timezone.utc).strftime('%H:%M:%S.%f')[:-3]
|
|
1138
|
+
|
|
1139
|
+
# Create unique log identifier for grep
|
|
1140
|
+
log_id = f"FRAME_{frame_id:06d}"
|
|
1141
|
+
|
|
1127
1142
|
separator = "=" * 80
|
|
1128
1143
|
print(f"\n{separator}")
|
|
1129
|
-
print(f"[DETECTION_STATS] Stage: {stage_name}")
|
|
1144
|
+
print(f"[DETECTION_STATS] {log_id} | Time: {timestamp_str} | Stage: {stage_name}")
|
|
1130
1145
|
print(separator)
|
|
1131
1146
|
|
|
1132
1147
|
# Handle different data formats
|
|
@@ -1135,12 +1150,12 @@ class VehicleMonitoringDroneViewUseCase(BaseProcessor):
|
|
|
1135
1150
|
detections = data
|
|
1136
1151
|
elif isinstance(data, dict):
|
|
1137
1152
|
# Frame-based format
|
|
1138
|
-
for
|
|
1153
|
+
for fid, frame_dets in data.items():
|
|
1139
1154
|
if isinstance(frame_dets, list):
|
|
1140
1155
|
detections.extend(frame_dets)
|
|
1141
1156
|
|
|
1142
1157
|
if not detections:
|
|
1143
|
-
print(f" Total Detections: 0")
|
|
1158
|
+
print(f" Frame: #{frame_id} | Total Detections: 0")
|
|
1144
1159
|
print(separator)
|
|
1145
1160
|
return
|
|
1146
1161
|
|
|
@@ -1153,6 +1168,7 @@ class VehicleMonitoringDroneViewUseCase(BaseProcessor):
|
|
|
1153
1168
|
confidence_min = {}
|
|
1154
1169
|
confidence_max = {}
|
|
1155
1170
|
bbox_format_count = {"x1/y1/x2/y2": 0, "xmin/ymin/xmax/ymax": 0, "other": 0}
|
|
1171
|
+
has_track_id = 0
|
|
1156
1172
|
|
|
1157
1173
|
for det in detections:
|
|
1158
1174
|
if not isinstance(det, dict):
|
|
@@ -1181,9 +1197,17 @@ class VehicleMonitoringDroneViewUseCase(BaseProcessor):
|
|
|
1181
1197
|
bbox_format_count["xmin/ymin/xmax/ymax"] += 1
|
|
1182
1198
|
else:
|
|
1183
1199
|
bbox_format_count["other"] += 1
|
|
1200
|
+
|
|
1201
|
+
# Track ID presence
|
|
1202
|
+
if det.get('track_id') is not None:
|
|
1203
|
+
has_track_id += 1
|
|
1184
1204
|
|
|
1185
1205
|
# Print summary
|
|
1186
|
-
print(f" Total Detections: {total_count}")
|
|
1206
|
+
print(f" Frame: #{frame_id} | Total Detections: {total_count}")
|
|
1207
|
+
|
|
1208
|
+
if has_track_id > 0:
|
|
1209
|
+
print(f" Detections with Track ID: {has_track_id} ({100*has_track_id/total_count:.1f}%)")
|
|
1210
|
+
|
|
1187
1211
|
print(f"\n Category Distribution:")
|
|
1188
1212
|
|
|
1189
1213
|
# Sort categories by count (descending)
|
|
@@ -1213,6 +1237,9 @@ class VehicleMonitoringDroneViewUseCase(BaseProcessor):
|
|
|
1213
1237
|
print(f" Category: {sample.get('category')} (type: {type(sample.get('category')).__name__})")
|
|
1214
1238
|
print(f" Confidence: {sample.get('confidence')} (type: {type(sample.get('confidence')).__name__})")
|
|
1215
1239
|
|
|
1240
|
+
if sample.get('track_id') is not None:
|
|
1241
|
+
print(f" Track ID: {sample.get('track_id')} (type: {type(sample.get('track_id')).__name__})")
|
|
1242
|
+
|
|
1216
1243
|
bbox = sample.get('bounding_box', sample.get('bbox', {}))
|
|
1217
1244
|
if isinstance(bbox, dict):
|
|
1218
1245
|
print(f" BBox Keys: {list(bbox.keys())}")
|
|
@@ -110,8 +110,24 @@ class VehicleMonitoringParkingLotUseCase(BaseProcessor):
|
|
|
110
110
|
def process(self, data: Any, config: ConfigProtocol, context: Optional[ProcessingContext] = None,
|
|
111
111
|
stream_info: Optional[Dict[str, Any]] = None) -> ProcessingResult:
|
|
112
112
|
processing_start = time.time()
|
|
113
|
-
|
|
114
|
-
|
|
113
|
+
# Relaxed check: Accept VehicleMonitoringParkingLotConfig OR any config with matching usecase/category
|
|
114
|
+
# This handles multiprocessing module path mismatches while maintaining type safety
|
|
115
|
+
is_valid_config = (
|
|
116
|
+
isinstance(config, VehicleMonitoringParkingLotConfig) or
|
|
117
|
+
(hasattr(config, 'usecase') and config.usecase == 'vehicle_monitoring_parking_lot' and
|
|
118
|
+
hasattr(config, 'category') and config.category == 'traffic')
|
|
119
|
+
)
|
|
120
|
+
if not is_valid_config:
|
|
121
|
+
self.logger.error(
|
|
122
|
+
f"Config validation failed in vehicle_monitoring_parking_lot. "
|
|
123
|
+
f"Got type={type(config).__name__}, module={type(config).__module__}, "
|
|
124
|
+
f"usecase={getattr(config, 'usecase', 'N/A')}, category={getattr(config, 'category', 'N/A')}"
|
|
125
|
+
)
|
|
126
|
+
return self.create_error_result(
|
|
127
|
+
f"Invalid config type: expected VehicleMonitoringParkingLotConfig or config with usecase='vehicle_monitoring_parking_lot', "
|
|
128
|
+
f"got {type(config).__name__} with usecase={getattr(config, 'usecase', 'N/A')}",
|
|
129
|
+
usecase=self.name, category=self.category, context=context
|
|
130
|
+
)
|
|
115
131
|
if context is None:
|
|
116
132
|
context = ProcessingContext()
|
|
117
133
|
|