matrice 1.0.99268__py3-none-any.whl → 1.0.99269__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.
@@ -391,6 +391,12 @@ class ProximityConfig(BaseConfig):
391
391
  enable_unique_counting: bool = True
392
392
  time_window_minutes: int = 60
393
393
 
394
+ proximity_threshold_meters: float = 1.0
395
+ proximity_threshold_pixels: float = 250.0
396
+ meters_per_pixel: float = 0.0028
397
+ scene_width_meters: float = 0.0
398
+ scene_height_meters: float = 0.0
399
+
394
400
  # Category mapping
395
401
  person_categories: List[str] = field(default_factory=lambda: ["person"])
396
402
  index_to_category: Optional[Dict[int, str]] = None
@@ -287,8 +287,8 @@ class ProximityUseCase(BaseProcessor):
287
287
  # Update tracking state BEFORE proximity calculation so we have canonical IDs
288
288
  self._update_tracking_state(counting_summary)
289
289
 
290
- # Calculate unique proximity events for this frame
291
- proximity_count = self._count_proximity_events(counting_summary["detections"])
290
+ # Calculate unique proximity events for this frame (meters-aware)
291
+ proximity_count = self._count_proximity_events(counting_summary["detections"], config, stream_info)
292
292
  counting_summary["proximity_events"] = proximity_count
293
293
  counting_summary["total_proximity_count"] = self._total_proximity_count
294
294
 
@@ -585,19 +585,24 @@ class ProximityUseCase(BaseProcessor):
585
585
  )
586
586
  return [tracking_stat]
587
587
 
588
- def _count_proximity_events(self, detections: List[Dict[str, Any]]) -> int:
588
+ def _count_proximity_events(self, detections: List[Dict[str, Any]], config: ProximityConfig, stream_info: Optional[Dict[str, Any]] = None) -> int:
589
589
  """Count UNIQUE proximity events between detections in a frame.
590
590
 
591
591
  Rules:
592
592
  - If canonical track IDs are present, deduplicate by track_id first.
593
593
  - Otherwise, deduplicate overlapping boxes using IoU to avoid duplicate detections of the same person.
594
594
  - Count each pair once (i < j) using Euclidean distance between bottom-center points.
595
+ - Distance is evaluated in meters when calibration is available. If unavailable, pixel threshold is used as a fallback.
595
596
  - Maintain a running set of unique canonical-ID pairs across frames to compute total unique proximity events.
596
597
  """
597
598
  if not detections:
598
599
  return 0
599
600
 
600
- proximity_threshold = 400.0 # pixels, screen space
601
+ # Determine threshold strategy
602
+ meters_per_pixel = self._get_meters_per_pixel(config, stream_info)
603
+ threshold_meters = getattr(config, "proximity_threshold_meters", 1.0)
604
+ threshold_pixels_fallback = getattr(config, "proximity_threshold_pixels", 400.0)
605
+
601
606
  iou_duplicate_threshold = getattr(self, "_proximity_iou_duplicate_threshold", 0.5)
602
607
 
603
608
  # Step 1: Deduplicate detections
@@ -647,8 +652,18 @@ class ProximityUseCase(BaseProcessor):
647
652
 
648
653
  dx = float(p_i[0]) - float(p_j[0])
649
654
  dy = float(p_i[1]) - float(p_j[1])
650
- distance = math.hypot(dx, dy)
651
- if distance >= proximity_threshold:
655
+ pixel_distance = math.hypot(dx, dy)
656
+
657
+ is_close = False
658
+ if meters_per_pixel:
659
+ meters_distance = pixel_distance * float(meters_per_pixel)
660
+ if meters_distance < float(threshold_meters):
661
+ is_close = True
662
+ else:
663
+ if pixel_distance < float(threshold_pixels_fallback):
664
+ is_close = True
665
+
666
+ if not is_close:
652
667
  continue
653
668
 
654
669
  frame_unique_count += 1
@@ -663,13 +678,53 @@ class ProximityUseCase(BaseProcessor):
663
678
  self._total_proximity_count += 1
664
679
 
665
680
  return frame_unique_count
681
+
682
+ def _get_meters_per_pixel(self, config: ProximityConfig, stream_info: Optional[Dict[str, Any]] = None) -> Optional[float]:
683
+ """Compute meters-per-pixel scale using config and optional stream_info.
684
+
685
+ Priority:
686
+ 1) config.meters_per_pixel (direct override)
687
+ 2) config.scene_width_meters + frame width in pixels
688
+ 3) config.scene_height_meters + frame height in pixels
689
+ Returns None if insufficient information.
690
+ """
691
+ # Direct override
692
+ if hasattr(config, "meters_per_pixel") and getattr(config, "meters_per_pixel"):
693
+ try:
694
+ return float(getattr(config, "meters_per_pixel"))
695
+ except Exception: # noqa: BLE001
696
+ pass
697
+
698
+ width_px = None
699
+ height_px = None
700
+ if stream_info and isinstance(stream_info, dict):
701
+ input_settings = stream_info.get("input_settings", {}) or {}
702
+ resolution = input_settings.get("resolution", {}) or {}
703
+ width_px = resolution.get("width") or input_settings.get("frame_width")
704
+ height_px = resolution.get("height") or input_settings.get("frame_height")
705
+
706
+ # Derive from scene real-world width
707
+ if hasattr(config, "scene_width_meters") and getattr(config, "scene_width_meters") and width_px:
708
+ try:
709
+ return float(getattr(config, "scene_width_meters")) / float(width_px)
710
+ except Exception: # noqa: BLE001
711
+ pass
712
+
713
+ # Derive from scene real-world height
714
+ if hasattr(config, "scene_height_meters") and getattr(config, "scene_height_meters") and height_px:
715
+ try:
716
+ return float(getattr(config, "scene_height_meters")) / float(height_px)
717
+ except Exception: # noqa: BLE001
718
+ pass
719
+
720
+ return None
666
721
 
667
722
  def _generate_human_text_for_tracking(
668
723
  self,
669
- _total_people: int,
724
+ total_people: int,
670
725
  detections,
671
- _total_unique_count: int,
672
- _config: ProximityConfig,
726
+ total_unique_count: int,
727
+ config: ProximityConfig,
673
728
  frame_id: str,
674
729
  alerts: Any = None,
675
730
  stream_info: Optional[Dict[str, Any]] = None) -> str:
@@ -681,8 +736,8 @@ class ProximityUseCase(BaseProcessor):
681
736
 
682
737
  human_text_lines.append(f"CURRENT FRAME @ {current_timestamp}:")
683
738
 
684
- # Add proximity count to human text
685
- proximity_count = self._count_proximity_events(detections)
739
+ # Add proximity count to human text (meters-aware)
740
+ proximity_count = self._count_proximity_events(detections, config, stream_info)
686
741
  if proximity_count > 0:
687
742
  human_text_lines.append(f"\t- Current Frame Proximity: {proximity_count}")
688
743
  else:
@@ -1592,6 +1647,33 @@ class ProximityUseCase(BaseProcessor):
1592
1647
  "default": True,
1593
1648
  "description": "Enable unique proximity detection using tracking"
1594
1649
  },
1650
+ "proximity_threshold_meters": {
1651
+ "type": "number",
1652
+ "minimum": 0.1,
1653
+ "default": 1.0,
1654
+ "description": "Distance threshold in meters to consider two people in proximity"
1655
+ },
1656
+ "meters_per_pixel": {
1657
+ "type": "number",
1658
+ "minimum": 0,
1659
+ "description": "Direct meters-per-pixel calibration override. If set, used for distance conversion."
1660
+ },
1661
+ "scene_width_meters": {
1662
+ "type": "number",
1663
+ "minimum": 0,
1664
+ "description": "Real-world width of the scene captured by the frame (meters). Used to derive meters-per-pixel with frame width."
1665
+ },
1666
+ "scene_height_meters": {
1667
+ "type": "number",
1668
+ "minimum": 0,
1669
+ "description": "Real-world height of the scene captured by the frame (meters). Used to derive meters-per-pixel with frame height."
1670
+ },
1671
+ "proximity_threshold_pixels": {
1672
+ "type": "number",
1673
+ "minimum": 1,
1674
+ "default": 400,
1675
+ "description": "Fallback pixel threshold if no calibration is available"
1676
+ },
1595
1677
  "time_window_minutes": {
1596
1678
  "type": "integer",
1597
1679
  "minimum": 1,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: matrice
3
- Version: 1.0.99268
3
+ Version: 1.0.99269
4
4
  Summary: SDK for connecting to matrice.ai services
5
5
  Home-page: https://github.com/matrice-ai/python-sdk
6
6
  Author: Matrice.ai
@@ -140,7 +140,7 @@ matrice/deploy/utils/post_processing/advanced_tracker/strack.py,sha256=rVH2xOysZ
140
140
  matrice/deploy/utils/post_processing/advanced_tracker/tracker.py,sha256=D-PKZ2Pxutmlu--icyxuxjvnWBrzrmZcEChYS0nx00M,14328
141
141
  matrice/deploy/utils/post_processing/core/__init__.py,sha256=MPMj_iRv--PfKBpYN12IjReAzSU7aRMVD6VW-LC95-M,1379
142
142
  matrice/deploy/utils/post_processing/core/base.py,sha256=V_DmaMLtrIunrN8Aq9iLeMIQPlkbCE-9d7n0Yz-nKQg,28228
143
- matrice/deploy/utils/post_processing/core/config.py,sha256=rU6EWou2HOA_4Ks0LUTSczQbT04jhN1FofuAQ7dtrZ4,102355
143
+ matrice/deploy/utils/post_processing/core/config.py,sha256=ogmNUbfOoC4SE-SmUEkqIKBeR0p0j3M0hF2_KvzpNp0,102560
144
144
  matrice/deploy/utils/post_processing/core/config_utils.py,sha256=Y_Czm9RmtHuxzBZzGUBA57JRyx5r6tzrM5l89Dbdf_w,28871
145
145
  matrice/deploy/utils/post_processing/test_cases/__init__.py,sha256=zUU2kKrIcCl8WeyjjQViwp7PWTZlKPuF8M2pZkxoNNQ,42
146
146
  matrice/deploy/utils/post_processing/test_cases/run_tests.py,sha256=RBFGvxFR-gozxnQFzkWLrs90vLlp8Bsn-Z7MLQrNw4o,4731
@@ -204,7 +204,7 @@ matrice/deploy/utils/post_processing/usecases/plaque_segmentation_img.py,sha256=
204
204
  matrice/deploy/utils/post_processing/usecases/pothole_segmentation.py,sha256=jXTb8ZqInp5xJ-O3Zp3zQBiryFVD0-WBbhW6Kux_NDo,44905
205
205
  matrice/deploy/utils/post_processing/usecases/ppe_compliance.py,sha256=G9P9j9E9nfNJInHJxmK1Lb4daFBlG5hq0aqotTLvFFE,30146
206
206
  matrice/deploy/utils/post_processing/usecases/price_tag_detection.py,sha256=09Tp6MGAHh95s-NSAp-4WC9iCc20sajWApuUBAvgXiQ,39880
207
- matrice/deploy/utils/post_processing/usecases/proximity_detection.py,sha256=HjUZMKZHAgpD_YiyTXFAoaO4awF_QkY9oflCIVFlsiM,81157
207
+ matrice/deploy/utils/post_processing/usecases/proximity_detection.py,sha256=QyknlaCyvzRg0j9Vndi1prYNW1elz0ARNBimHRyBak4,85207
208
208
  matrice/deploy/utils/post_processing/usecases/road_lane_detection.py,sha256=V_KxwBtAHSNkyoH8sXw-U-P3J8ToXtX3ncc69gn6Tds,31591
209
209
  matrice/deploy/utils/post_processing/usecases/road_traffic_density.py,sha256=YiHQ0kKhXglagHPvygywxMqZAw8s0WharrBQqLQj2q4,40311
210
210
  matrice/deploy/utils/post_processing/usecases/road_view_segmentation.py,sha256=BcBbOOg5622KuvzKrzs9cJW1wkRoIIcOab0N7BONQKQ,44986
@@ -243,8 +243,8 @@ matrice/deployment/camera_manager.py,sha256=e1Lc81RJP5wUWRdTgHO6tMWF9BkBdHOSVyx3
243
243
  matrice/deployment/deployment.py,sha256=HFt151eWq6iqIAMsQvurpV2WNxW6Cx_gIUVfnVy5SWE,48093
244
244
  matrice/deployment/inference_pipeline.py,sha256=6b4Mm3-qt-Zy0BeiJfFQdImOn3FzdNCY-7ET7Rp8PMk,37911
245
245
  matrice/deployment/streaming_gateway_manager.py,sha256=ifYGl3g25wyU39HwhPQyI2OgF3M6oIqKMWt8RXtMxY8,21401
246
- matrice-1.0.99268.dist-info/licenses/LICENSE.txt,sha256=2bm9uFabQZ3Ykb_SaSU_uUbAj2-htc6WJQmS_65qD00,1073
247
- matrice-1.0.99268.dist-info/METADATA,sha256=aU45pkw_HtMNp9C-mI1pSRKXVAI9djwHr1UCaRvpbCA,14624
248
- matrice-1.0.99268.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
249
- matrice-1.0.99268.dist-info/top_level.txt,sha256=P97js8ur6o5ClRqMH3Cjoab_NqbJ6sOQ3rJmVzKBvMc,8
250
- matrice-1.0.99268.dist-info/RECORD,,
246
+ matrice-1.0.99269.dist-info/licenses/LICENSE.txt,sha256=2bm9uFabQZ3Ykb_SaSU_uUbAj2-htc6WJQmS_65qD00,1073
247
+ matrice-1.0.99269.dist-info/METADATA,sha256=y9DrDgXE7DfQ8kc1rALCkIrPanFK1zTR3Eoc8DxVVyo,14624
248
+ matrice-1.0.99269.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
249
+ matrice-1.0.99269.dist-info/top_level.txt,sha256=P97js8ur6o5ClRqMH3Cjoab_NqbJ6sOQ3rJmVzKBvMc,8
250
+ matrice-1.0.99269.dist-info/RECORD,,