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.
- matrice/deploy/utils/post_processing/core/config.py +6 -0
- matrice/deploy/utils/post_processing/usecases/proximity_detection.py +93 -11
- {matrice-1.0.99268.dist-info → matrice-1.0.99269.dist-info}/METADATA +1 -1
- {matrice-1.0.99268.dist-info → matrice-1.0.99269.dist-info}/RECORD +7 -7
- {matrice-1.0.99268.dist-info → matrice-1.0.99269.dist-info}/WHEEL +0 -0
- {matrice-1.0.99268.dist-info → matrice-1.0.99269.dist-info}/licenses/LICENSE.txt +0 -0
- {matrice-1.0.99268.dist-info → matrice-1.0.99269.dist-info}/top_level.txt +0 -0
@@ -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
|
-
|
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
|
-
|
651
|
-
|
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
|
-
|
724
|
+
total_people: int,
|
670
725
|
detections,
|
671
|
-
|
672
|
-
|
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,
|
@@ -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=
|
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=
|
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.
|
247
|
-
matrice-1.0.
|
248
|
-
matrice-1.0.
|
249
|
-
matrice-1.0.
|
250
|
-
matrice-1.0.
|
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,,
|
File without changes
|
File without changes
|
File without changes
|