matrice-analytics 0.1.70__py3-none-any.whl → 0.1.96__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.
Files changed (26) hide show
  1. matrice_analytics/post_processing/__init__.py +8 -2
  2. matrice_analytics/post_processing/config.py +4 -2
  3. matrice_analytics/post_processing/core/base.py +1 -1
  4. matrice_analytics/post_processing/core/config.py +40 -3
  5. matrice_analytics/post_processing/face_reg/face_recognition.py +1014 -201
  6. matrice_analytics/post_processing/face_reg/face_recognition_client.py +171 -29
  7. matrice_analytics/post_processing/face_reg/people_activity_logging.py +19 -0
  8. matrice_analytics/post_processing/post_processor.py +4 -0
  9. matrice_analytics/post_processing/usecases/__init__.py +4 -1
  10. matrice_analytics/post_processing/usecases/advanced_customer_service.py +913 -500
  11. matrice_analytics/post_processing/usecases/color_detection.py +19 -18
  12. matrice_analytics/post_processing/usecases/customer_service.py +356 -9
  13. matrice_analytics/post_processing/usecases/fire_detection.py +241 -23
  14. matrice_analytics/post_processing/usecases/footfall.py +750 -0
  15. matrice_analytics/post_processing/usecases/license_plate_monitoring.py +638 -40
  16. matrice_analytics/post_processing/usecases/people_counting.py +66 -33
  17. matrice_analytics/post_processing/usecases/vehicle_monitoring.py +35 -34
  18. matrice_analytics/post_processing/usecases/weapon_detection.py +2 -1
  19. matrice_analytics/post_processing/utils/alert_instance_utils.py +1018 -0
  20. matrice_analytics/post_processing/utils/business_metrics_manager_utils.py +1338 -0
  21. matrice_analytics/post_processing/utils/incident_manager_utils.py +1754 -0
  22. {matrice_analytics-0.1.70.dist-info → matrice_analytics-0.1.96.dist-info}/METADATA +1 -1
  23. {matrice_analytics-0.1.70.dist-info → matrice_analytics-0.1.96.dist-info}/RECORD +26 -22
  24. {matrice_analytics-0.1.70.dist-info → matrice_analytics-0.1.96.dist-info}/WHEEL +0 -0
  25. {matrice_analytics-0.1.70.dist-info → matrice_analytics-0.1.96.dist-info}/licenses/LICENSE.txt +0 -0
  26. {matrice_analytics-0.1.70.dist-info → matrice_analytics-0.1.96.dist-info}/top_level.txt +0 -0
@@ -36,7 +36,7 @@ class PeopleCountingUseCase(BaseProcessor):
36
36
  self.category = "general"
37
37
  self.CASE_TYPE: Optional[str] = 'people_counting'
38
38
  self.CASE_VERSION: Optional[str] = '1.4'
39
- self.target_categories = ['person', 'people','human','man','woman','male','female']
39
+ self.target_categories = ['person'] #['person', 'people','human','man','woman','male','female']
40
40
  self.smoothing_tracker = None
41
41
  self.tracker = None
42
42
  self._total_frame_counter = 0
@@ -50,6 +50,19 @@ class PeopleCountingUseCase(BaseProcessor):
50
50
  self.current_incident_end_timestamp: str = "N/A"
51
51
  self.start_timer = None
52
52
 
53
+ def _simple_tracker_update(self, detections: list) -> list:
54
+ """
55
+ ====== PERFORMANCE: Lightweight tracker alternative ======
56
+ Simple tracker using frame-local indexing.
57
+ Much faster than AdvancedTracker - O(n) complexity.
58
+ Does not persist track IDs across frames.
59
+ Enable via config.enable_simple_tracker = True
60
+ """
61
+ for i, det in enumerate(detections):
62
+ if det.get('track_id') is None:
63
+ det['track_id'] = f"simple_{self._total_frame_counter}_{i}"
64
+ return detections
65
+
53
66
  def process(self, data: Any, config: ConfigProtocol, context: Optional[ProcessingContext] = None,
54
67
  stream_info: Optional[Dict[str, Any]] = None) -> ProcessingResult:
55
68
  processing_start = time.time()
@@ -90,20 +103,29 @@ class PeopleCountingUseCase(BaseProcessor):
90
103
  # self.smoothing_tracker = BBoxSmoothingTracker(smoothing_config)
91
104
  # processed_data = bbox_smoothing(processed_data, self.smoothing_tracker.config, self.smoothing_tracker)
92
105
 
93
- try:
94
- from ..advanced_tracker import AdvancedTracker
95
- from ..advanced_tracker.config import TrackerConfig
96
- if self.tracker is None:
97
- tracker_config = TrackerConfig(
98
- track_high_thresh=0.4,
99
- track_low_thresh=0.05,
100
- new_track_thresh=0.3,
101
- match_thresh=0.8)
102
- self.tracker = AdvancedTracker(tracker_config)
103
- self.logger.info("Initialized AdvancedTracker for People Counting")
104
- processed_data = self.tracker.update(processed_data)
105
- except Exception as e:
106
- self.logger.warning(f"AdvancedTracker failed: {e}")
106
+ # ====== TRACKER SELECTION (both disabled by default for max performance) ======
107
+ # Set config.enable_advanced_tracker=True or config.enable_simple_tracker=True to enable
108
+ if getattr(config, 'enable_advanced_tracker', False):
109
+ # Heavy O(n³) tracker - use only when tracking quality is critical
110
+ try:
111
+ from ..advanced_tracker import AdvancedTracker
112
+ from ..advanced_tracker.config import TrackerConfig
113
+ if self.tracker is None:
114
+ tracker_config = TrackerConfig(
115
+ track_high_thresh=0.4,
116
+ track_low_thresh=0.05,
117
+ new_track_thresh=0.3,
118
+ match_thresh=0.8)
119
+ self.tracker = AdvancedTracker(tracker_config)
120
+ self.logger.info("Initialized AdvancedTracker for People Counting")
121
+ processed_data = self.tracker.update(processed_data)
122
+ except Exception as e:
123
+ self.logger.warning(f"AdvancedTracker failed: {e}")
124
+ elif getattr(config, 'enable_simple_tracker', False):
125
+ # Lightweight O(n) tracker - fast but no cross-frame persistence
126
+ processed_data = self._simple_tracker_update(processed_data)
127
+ # else: No tracking - maximum performance, just use raw detections
128
+ # ====== END TRACKER SELECTION ======
107
129
 
108
130
  self._update_tracking_state(processed_data)
109
131
  self._total_frame_counter += 1
@@ -333,20 +355,20 @@ class PeopleCountingUseCase(BaseProcessor):
333
355
  })
334
356
 
335
357
  human_text_lines = []
336
- human_text_lines.append(f"CURRENT FRAME @ {current_timestamp}")
358
+ human_text_lines.append(f"CURRENT FRAME @ {current_timestamp}:")
337
359
  for cat, count in per_category_count.items():
338
360
  human_text_lines.append(f"\t- People Detected: {count}")
339
361
  human_text_lines.append("")
340
- human_text_lines.append(f"TOTAL SINCE {start_timestamp}")
341
- for cat, count in total_counts_dict.items():
342
- if count > 0:
343
- human_text_lines.append("")
344
- human_text_lines.append(f"\t- Total unique people count: {count}")
345
- if alerts:
346
- for alert in alerts:
347
- human_text_lines.append(f"Alerts: {alert.get('settings', {})} sent @ {current_timestamp}")
348
- else:
349
- human_text_lines.append("Alerts: None")
362
+ # human_text_lines.append(f"TOTAL SINCE {start_timestamp}")
363
+ # for cat, count in total_counts_dict.items():
364
+ # if count > 0:
365
+ # human_text_lines.append("")
366
+ # human_text_lines.append(f"\t- Total unique people count: {count}")
367
+ # if alerts:
368
+ # for alert in alerts:
369
+ # human_text_lines.append(f"Alerts: {alert.get('settings', {})} sent @ {current_timestamp}")
370
+ # else:
371
+ # human_text_lines.append("Alerts: None")
350
372
  human_text = "\n".join(human_text_lines)
351
373
 
352
374
  reset_settings = [{"interval_type": "daily", "reset_time": {"value": 9, "time_unit": "hour"}}]
@@ -362,6 +384,7 @@ class PeopleCountingUseCase(BaseProcessor):
362
384
  start_time=high_precision_start_timestamp,
363
385
  reset_time=high_precision_reset_timestamp
364
386
  )
387
+ tracking_stat['target_categories'] = self.target_categories
365
388
  tracking_stats.append(tracking_stat)
366
389
  return tracking_stats
367
390
 
@@ -414,14 +437,24 @@ class PeopleCountingUseCase(BaseProcessor):
414
437
 
415
438
  for det in detections:
416
439
  cat = det.get("category")
417
- raw_track_id = det.get("track_id")
418
- if cat not in self.target_categories or raw_track_id is None:
440
+ track_id = det.get("track_id")
441
+ if cat not in self.target_categories:
419
442
  continue
420
- bbox = det.get("bounding_box", det.get("bbox"))
421
- canonical_id = self._merge_or_register_track(raw_track_id, bbox)
422
- det["track_id"] = canonical_id
423
- self._per_category_total_track_ids.setdefault(cat, set()).add(canonical_id)
424
- self._current_frame_track_ids[cat].add(canonical_id)
443
+
444
+ # ====== PERFORMANCE: Skip heavy track merging O(n*m) ======
445
+ # To enable track merging, uncomment below and comment the simple counting section
446
+ # bbox = det.get("bounding_box", det.get("bbox"))
447
+ # canonical_id = self._merge_or_register_track(track_id, bbox)
448
+ # det["track_id"] = canonical_id
449
+ # self._per_category_total_track_ids.setdefault(cat, set()).add(canonical_id)
450
+ # self._current_frame_track_ids[cat].add(canonical_id)
451
+ # ====== END HEAVY TRACK MERGING ======
452
+
453
+ # ====== SIMPLE COUNTING (default - no track merging overhead) ======
454
+ if track_id is not None:
455
+ self._per_category_total_track_ids.setdefault(cat, set()).add(track_id)
456
+ self._current_frame_track_ids[cat].add(track_id)
457
+ # ====== END SIMPLE COUNTING ======
425
458
 
426
459
  def get_total_counts(self):
427
460
  return {cat: len(ids) for cat, ids in getattr(self, '_per_category_total_track_ids', {}).items()}
@@ -633,40 +633,40 @@ class VehicleMonitoringUseCase(BaseProcessor):
633
633
  human_text_lines.append(f"\t\t- {cat}: {count}")
634
634
 
635
635
  human_text_lines.append("")
636
- human_text_lines.append(f"TOTAL SINCE @ {start_timestamp}:")
637
-
638
- # Display total counts - zone-wise or category-wise
639
- if zone_analysis:
640
- human_text_lines.append("\t- Total Vehicles by Zone:")
641
- for zone_name, zone_data in zone_analysis.items():
642
- total_count = 0
643
- if isinstance(zone_data, dict):
644
- # Prefer the numeric cumulative total if available
645
- if "total_count" in zone_data and isinstance(zone_data.get("total_count"), (int, float)):
646
- total_count = zone_data.get("total_count", 0)
647
- # Fallback: compute from list of total_track_ids if present
648
- elif "total_track_ids" in zone_data and isinstance(zone_data.get("total_track_ids"), list):
649
- total_count = len(zone_data.get("total_track_ids", []))
650
- else:
651
- # Last resort: try to sum numeric values present
652
- counts_dict = zone_data if isinstance(zone_data, dict) else {}
653
- total_count = sum(v for v in counts_dict.values() if isinstance(v, (int, float)))
654
- human_text_lines.append(f"\t\t- {zone_name}: {int(total_count)}")
655
- else:
656
- if total_counts_dict:
657
- human_text_lines.append("\t- Total Unique Vehicles:")
658
- for cat, count in total_counts_dict.items():
659
- if count > 0:
660
- human_text_lines.append(f"\t\t- {cat}: {count}")
661
-
662
- # Display alerts
663
- if alerts:
664
- human_text_lines.append("")
665
- for alert in alerts:
666
- human_text_lines.append(f"Alerts: {alert.get('settings', {})} sent @ {current_timestamp}")
667
- else:
668
- human_text_lines.append("")
669
- human_text_lines.append("Alerts: None")
636
+ # human_text_lines.append(f"TOTAL SINCE @ {start_timestamp}:")
637
+
638
+ # # Display total counts - zone-wise or category-wise
639
+ # if zone_analysis:
640
+ # human_text_lines.append("\t- Total Vehicles by Zone:")
641
+ # for zone_name, zone_data in zone_analysis.items():
642
+ # total_count = 0
643
+ # if isinstance(zone_data, dict):
644
+ # # Prefer the numeric cumulative total if available
645
+ # if "total_count" in zone_data and isinstance(zone_data.get("total_count"), (int, float)):
646
+ # total_count = zone_data.get("total_count", 0)
647
+ # # Fallback: compute from list of total_track_ids if present
648
+ # elif "total_track_ids" in zone_data and isinstance(zone_data.get("total_track_ids"), list):
649
+ # total_count = len(zone_data.get("total_track_ids", []))
650
+ # else:
651
+ # # Last resort: try to sum numeric values present
652
+ # counts_dict = zone_data if isinstance(zone_data, dict) else {}
653
+ # total_count = sum(v for v in counts_dict.values() if isinstance(v, (int, float)))
654
+ # human_text_lines.append(f"\t\t- {zone_name}: {int(total_count)}")
655
+ # else:
656
+ # if total_counts_dict:
657
+ # human_text_lines.append("\t- Total Unique Vehicles:")
658
+ # for cat, count in total_counts_dict.items():
659
+ # if count > 0:
660
+ # human_text_lines.append(f"\t\t- {cat}: {count}")
661
+
662
+ # # Display alerts
663
+ # if alerts:
664
+ # human_text_lines.append("")
665
+ # for alert in alerts:
666
+ # human_text_lines.append(f"Alerts: {alert.get('settings', {})} sent @ {current_timestamp}")
667
+ # else:
668
+ # human_text_lines.append("")
669
+ # human_text_lines.append("Alerts: None")
670
670
 
671
671
  human_text = "\n".join(human_text_lines)
672
672
 
@@ -683,6 +683,7 @@ class VehicleMonitoringUseCase(BaseProcessor):
683
683
  start_time=high_precision_start_timestamp,
684
684
  reset_time=high_precision_reset_timestamp
685
685
  )
686
+ tracking_stat['target_categories'] = self.target_categories
686
687
  tracking_stats.append(tracking_stat)
687
688
  return tracking_stats
688
689
 
@@ -317,7 +317,7 @@ class WeaponDetectionUseCase(BaseProcessor):
317
317
  total_counts = [{"category": cat, "count": count} for cat, count in total_counts_dict.items() if count > 0]
318
318
 
319
319
  # Build current_counts
320
- current_counts = [{"category": cat, "count": count} for cat, count in per_category_count.items() if count > 0]
320
+ current_counts = [{"category": 'Weapon', "count": count} for cat, count in per_category_count.items() if count > 0]
321
321
 
322
322
  # Prepare detections
323
323
  detections = []
@@ -377,6 +377,7 @@ class WeaponDetectionUseCase(BaseProcessor):
377
377
  start_time=high_precision_start_timestamp,
378
378
  reset_time=high_precision_reset_timestamp
379
379
  )
380
+ tracking_stat['target_categories'] = ['Weapon']
380
381
  tracking_stats.append(tracking_stat)
381
382
  return tracking_stats
382
383