matrice 1.0.99143__py3-none-any.whl → 1.0.99145__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.
@@ -1,9 +1,9 @@
1
1
  from typing import Any, Dict, List, Optional
2
- from dataclasses import asdict, dataclass, field
2
+ from dataclasses import asdict
3
3
  import time
4
4
  from datetime import datetime, timezone
5
5
 
6
- from ..core.base import BaseProcessor, ProcessingContext, ProcessingResult, ConfigProtocol
6
+ from ..core.base import BaseProcessor, ProcessingContext, ProcessingResult, ConfigProtocol, ResultFormat
7
7
  from ..utils import (
8
8
  filter_by_confidence,
9
9
  filter_by_categories,
@@ -16,6 +16,7 @@ from ..utils import (
16
16
  BBoxSmoothingConfig,
17
17
  BBoxSmoothingTracker
18
18
  )
19
+ from dataclasses import dataclass, field
19
20
  from ..core.config import BaseConfig, AlertConfig, ZoneConfig
20
21
 
21
22
 
@@ -29,40 +30,39 @@ class LaneDetectionConfig(BaseConfig):
29
30
  smoothing_confidence_range_factor: float = 0.5
30
31
  confidence_threshold: float = 0.6
31
32
  usecase_categories: List[str] = field(
32
- default_factory=lambda: ['Divider-Line', 'Dotted-Line', 'Double-Line', 'Random-Line', 'Road-Sign-Line', 'Solid-Line']
33
+ default_factory=lambda: ['divider-line', 'dotted-line', 'double-line', 'random-line', 'road-sign-line', 'solid-line']
33
34
  )
34
35
  target_categories: List[str] = field(
35
- default_factory=lambda: ['Divider-Line', 'Dotted-Line', 'Double-Line', 'Random-Line', 'Road-Sign-Line', 'Solid-Line']
36
+ default_factory=lambda: ['divider-line', 'dotted-line', 'double-line', 'random-line', 'road-sign-line', 'solid-line']
36
37
  )
37
38
  alert_config: Optional[AlertConfig] = None
38
39
  index_to_category: Optional[Dict[int, str]] = field(
39
40
  default_factory=lambda: {
40
- 0: "Divider-Line",
41
- 1: "Dotted-Line",
42
- 2: "Double-Line",
43
- 3: "Random-Line",
44
- 4: "Road-Sign-Line",
45
- 5: "Solid-Line"
41
+ 0: "divider-line",
42
+ 1: "dotted-line",
43
+ 2: "double-line",
44
+ 3: "random-line",
45
+ 4: "road-sign-line",
46
+ 5: "solid-line"
46
47
  }
47
48
  )
48
49
 
49
50
 
50
51
  class LaneDetectionUseCase(BaseProcessor):
51
52
  CATEGORY_DISPLAY = {
52
- "Divider-Line": "Divider Line",
53
- "Dotted-Line": "Dotted Line",
54
- "Double-Line": "Double Line",
55
- "Random-Line": "Random Line",
56
- "Road-Sign-Line": "Road Sign Line",
57
- "Solid-Line": "Solid Line"
53
+ "divider-line": "Divider Line",
54
+ "dotted-line": "Dotted Line",
55
+ "double-line": "Double Line",
56
+ "random-line": "Random Line",
57
+ "road-sign-line": "Road Sign Line",
58
+ "solid-line": "Solid Line"
58
59
  }
59
-
60
60
  def __init__(self):
61
61
  super().__init__("lane_detection")
62
62
  self.category = "traffic"
63
63
  self.CASE_TYPE: Optional[str] = 'lane_detection'
64
64
  self.CASE_VERSION: Optional[str] = '1.0'
65
- self.target_categories = ['Divider-Line', 'Dotted-Line', 'Double-Line', 'Random-Line', 'Road-Sign-Line', 'Solid-Line']
65
+ self.target_categories = ['divider-line', 'dotted-line', 'double-line', 'random-line', 'road-sign-line', 'solid-line']
66
66
  self.smoothing_tracker = None
67
67
  self.tracker = None
68
68
  self._total_frame_counter = 0
@@ -82,7 +82,6 @@ class LaneDetectionUseCase(BaseProcessor):
82
82
  return self.create_error_result("Invalid config type", usecase=self.name, category=self.category, context=context)
83
83
  if context is None:
84
84
  context = ProcessingContext()
85
-
86
85
  input_format = match_results_structure(data)
87
86
  context.input_format = input_format
88
87
  context.confidence_threshold = config.confidence_threshold
@@ -92,7 +91,7 @@ class LaneDetectionUseCase(BaseProcessor):
92
91
  self.logger.debug(f"Applied confidence filtering with threshold {config.confidence_threshold}")
93
92
  else:
94
93
  processed_data = data
95
- self.logger.debug("Did not apply confidence filtering since no threshold provided")
94
+ self.logger.debug("Did not apply confidence filtering")
96
95
 
97
96
  if config.index_to_category:
98
97
  processed_data = apply_category_mapping(processed_data, config.index_to_category)
@@ -193,39 +192,42 @@ class LaneDetectionUseCase(BaseProcessor):
193
192
  if not config.alert_config:
194
193
  return alerts
195
194
 
195
+ total = summary.get("total_count", 0)
196
196
  if hasattr(config.alert_config, 'count_thresholds') and config.alert_config.count_thresholds:
197
197
  for category, threshold in config.alert_config.count_thresholds.items():
198
- if category == "all" and total_detections > threshold:
199
- alerts.append({
200
- "alert_type": getattr(config.alert_config, 'alert_type', ['Default']),
201
- "alert_id": f"alert_{category}_{frame_key}",
202
- "incident_category": self.CASE_TYPE,
203
- "threshold_level": threshold,
204
- "ascending": get_trend(self._ascending_alert_list, lookback=900, threshold=0.8),
205
- "settings": {t: v for t, v in zip(getattr(config.alert_config, 'alert_type', ['Default']),
206
- getattr(config.alert_config, 'alert_value', ['JSON']))}
207
- })
208
- elif category in per_category_count and per_category_count[category] > threshold:
198
+ if category == "all" and total > threshold:
209
199
  alerts.append({
210
- "alert_type": getattr(config.alert_config, 'alert_type', ['Default']),
211
- "alert_id": f"alert_{category}_{frame_key}",
200
+ "alert_type": getattr(config.alert_config, 'alert_type', ['Default']) if hasattr(config.alert_config, 'alert_type') else ['Default'],
201
+ "alert_id": "alert_" + category + '_' + frame_key,
212
202
  "incident_category": self.CASE_TYPE,
213
203
  "threshold_level": threshold,
214
204
  "ascending": get_trend(self._ascending_alert_list, lookback=900, threshold=0.8),
215
- "settings": {t: v for t, v in zip(getattr(config.alert_config, 'alert_type', ['Default']),
216
- getattr(config.alert_config, 'alert_value', ['JSON']))}
205
+ "settings": {t: v for t, v in zip(getattr(config.alert_config, 'alert_type', ['Default']) if hasattr(config.alert_config, 'alert_type') else ['Default'],
206
+ getattr(config.alert_config, 'alert_value', ['JSON']) if hasattr(config.alert_config, 'alert_value') else ['JSON'])}
217
207
  })
208
+ elif category in per_category_count:
209
+ count = per_category_count[category]
210
+ if count > threshold:
211
+ alerts.append({
212
+ "alert_type": getattr(config.alert_config, 'alert_type', ['Default']) if hasattr(config.alert_config, 'alert_type') else ['Default'],
213
+ "alert_id": "alert_" + category + '_' + frame_key,
214
+ "incident_category": self.CASE_TYPE,
215
+ "threshold_level": threshold,
216
+ "ascending": get_trend(self._ascending_alert_list, lookback=900, threshold=0.8),
217
+ "settings": {t: v for t, v in zip(getattr(config.alert_config, 'alert_type', ['Default']) if hasattr(config.alert_config, 'alert_type') else ['Default'],
218
+ getattr(config.alert_config, 'alert_value', ['JSON']) if hasattr(config.alert_config, 'alert_value') else ['JSON'])}
219
+ })
218
220
  return alerts
219
221
 
220
222
  def _generate_incidents(self, counting_summary: Dict, alerts: List, config: LaneDetectionConfig,
221
- frame_number: Optional[int] = None, stream_info: Optional[Dict[str, Any]] = None) -> List[Dict]:
223
+ frame_number: Optional[int] = None, stream_info: Optional[Dict[str, Any]] = None) -> List[Dict]:
222
224
  incidents = []
223
225
  total_detections = counting_summary.get("total_count", 0)
224
226
  current_timestamp = self._get_current_timestamp_str(stream_info)
225
227
  camera_info = self.get_camera_info_from_stream(stream_info)
226
-
228
+
227
229
  self._ascending_alert_list = self._ascending_alert_list[-900:] if len(self._ascending_alert_list) > 900 else self._ascending_alert_list
228
-
230
+
229
231
  if total_detections > 0:
230
232
  level = "low"
231
233
  intensity = 5.0
@@ -251,6 +253,7 @@ class LaneDetectionUseCase(BaseProcessor):
251
253
  level = "medium"
252
254
  self._ascending_alert_list.append(1)
253
255
  else:
256
+ level = "low"
254
257
  self._ascending_alert_list.append(0)
255
258
  else:
256
259
  if total_detections > 30:
@@ -258,7 +261,7 @@ class LaneDetectionUseCase(BaseProcessor):
258
261
  intensity = 10.0
259
262
  self._ascending_alert_list.append(3)
260
263
  elif total_detections > 25:
261
- level = "significant"
264
+ level = " significant"
262
265
  intensity = 9.0
263
266
  self._ascending_alert_list.append(2)
264
267
  elif total_detections > 15:
@@ -277,16 +280,16 @@ class LaneDetectionUseCase(BaseProcessor):
277
280
  alert_settings = []
278
281
  if config.alert_config and hasattr(config.alert_config, 'alert_type'):
279
282
  alert_settings.append({
280
- "alert_type": getattr(config.alert_config, 'alert_type', ['Default']),
283
+ "alert_type": getattr(config.alert_config, 'alert_type', ['Default']) if hasattr(config.alert_config, 'alert_type') else ['Default'],
281
284
  "incident_category": self.CASE_TYPE,
282
285
  "threshold_level": config.alert_config.count_thresholds if hasattr(config.alert_config, 'count_thresholds') else {},
283
286
  "ascending": True,
284
- "settings": {t: v for t, v in zip(getattr(config.alert_config, 'alert_type', ['Default']),
285
- getattr(config.alert_config, 'alert_value', ['JSON']))}
287
+ "settings": {t: v for t, v in zip(getattr(config.alert_config, 'alert_type', ['Default']) if hasattr(config.alert_config, 'alert_type') else ['Default'],
288
+ getattr(config.alert_config, 'alert_value', ['JSON']) if hasattr(config.alert_config, 'alert_value') else ['JSON'])}
286
289
  })
287
290
 
288
291
  event = self.create_incident(
289
- incident_id=f"{self.CASE_TYPE}_{frame_number}",
292
+ incident_id=self.CASE_TYPE + '_' + str(frame_number),
290
293
  incident_type=self.CASE_TYPE,
291
294
  severity_level=level,
292
295
  human_text=human_text,
@@ -304,7 +307,7 @@ class LaneDetectionUseCase(BaseProcessor):
304
307
  return incidents
305
308
 
306
309
  def _generate_tracking_stats(self, counting_summary: Dict, alerts: List, config: LaneDetectionConfig,
307
- frame_number: Optional[int] = None, stream_info: Optional[Dict[str, Any]] = None) -> List[Dict]:
310
+ frame_number: Optional[int] = None, stream_info: Optional[Dict[str, Any]] = None) -> List[Dict]:
308
311
  camera_info = self.get_camera_info_from_stream(stream_info)
309
312
  tracking_stats = []
310
313
  total_detections = counting_summary.get("total_count", 0)
@@ -338,12 +341,12 @@ class LaneDetectionUseCase(BaseProcessor):
338
341
  alert_settings = []
339
342
  if config.alert_config and hasattr(config.alert_config, 'alert_type'):
340
343
  alert_settings.append({
341
- "alert_type": getattr(config.alert_config, 'alert_type', ['Default']),
344
+ "alert_type": getattr(config.alert_config, 'alert_type', ['Default']) if hasattr(config.alert_config, 'alert_type') else ['Default'],
342
345
  "incident_category": self.CASE_TYPE,
343
346
  "threshold_level": config.alert_config.count_thresholds if hasattr(config.alert_config, 'count_thresholds') else {},
344
347
  "ascending": True,
345
- "settings": {t: v for t, v in zip(getattr(config.alert_config, 'alert_type', ['Default']),
346
- getattr(config.alert_config, 'alert_value', ['JSON']))}
348
+ "settings": {t: v for t, v in zip(getattr(config.alert_config, 'alert_type', ['Default']) if hasattr(config.alert_config, 'alert_type') else ['Default'],
349
+ getattr(config.alert_config, 'alert_value', ['JSON']) if hasattr(config.alert_config, 'alert_value') else ['JSON'])}
347
350
  })
348
351
 
349
352
  human_text_lines = [f"Tracking Statistics:"]
@@ -362,6 +365,7 @@ class LaneDetectionUseCase(BaseProcessor):
362
365
  human_text = "\n".join(human_text_lines)
363
366
 
364
367
  reset_settings = [{"interval_type": "daily", "reset_time": {"value": 9, "time_unit": "hour"}}]
368
+
365
369
  tracking_stat = self.create_tracking_stats(
366
370
  total_counts=total_counts,
367
371
  current_counts=current_counts,
@@ -378,7 +382,7 @@ class LaneDetectionUseCase(BaseProcessor):
378
382
  return tracking_stats
379
383
 
380
384
  def _generate_business_analytics(self, counting_summary: Dict, alerts: Any, config: LaneDetectionConfig,
381
- stream_info: Optional[Dict[str, Any]] = None, is_empty=False) -> List[Dict]:
385
+ stream_info: Optional[Dict[str, Any]] = None, is_empty=False) -> List[Dict]:
382
386
  if is_empty:
383
387
  return []
384
388
 
@@ -443,33 +447,42 @@ class LaneDetectionUseCase(BaseProcessor):
443
447
  seconds = round(float(timestamp % 60), 2)
444
448
  return f"{hours:02d}:{minutes:02d}:{seconds:.1f}"
445
449
 
446
- def _get_current_timestamp_str(self, stream_info: Optional[Dict[str, Any]], precision=False, frame_id: Optional[str] = None) -> str:
450
+ def _get_current_timestamp_str(self, stream_info: Optional[Dict[str, Any]], precision=False, frame_id: Optional[str]=None) -> str:
451
+ """Get formatted current timestamp based on stream type."""
447
452
  if not stream_info:
448
453
  return "00:00:00.00"
454
+ # is_video_chunk = stream_info.get("input_settings", {}).get("is_video_chunk", False)
449
455
  if precision:
450
456
  if stream_info.get("input_settings", {}).get("start_frame", "na") != "na":
451
457
  if frame_id:
452
- start_time = int(frame_id) / stream_info.get("input_settings", {}).get("original_fps", 30)
458
+ start_time = int(frame_id)/stream_info.get("input_settings", {}).get("original_fps", 30)
453
459
  else:
454
- start_time = stream_info.get("input_settings", {}).get("start_frame", 30) / stream_info.get("input_settings", {}).get("original_fps", 30)
455
- return self._format_timestamp_for_video(start_time)
460
+ start_time = stream_info.get("input_settings", {}).get("start_frame", 30)/stream_info.get("input_settings", {}).get("original_fps", 30)
461
+ stream_time_str = self._format_timestamp_for_video(start_time)
462
+ return stream_time_str
456
463
  else:
457
464
  return datetime.now(timezone.utc).strftime("%Y-%m-%d-%H:%M:%S.%f UTC")
465
+
458
466
  if stream_info.get("input_settings", {}).get("start_frame", "na") != "na":
459
- if frame_id:
460
- start_time = int(frame_id) / stream_info.get("input_settings", {}).get("original_fps", 30)
461
- else:
462
- start_time = stream_info.get("input_settings", {}).get("start_frame", 30) / stream_info.get("input_settings", {}).get("original_fps", 30)
463
- return self._format_timestamp_for_video(start_time)
467
+ if frame_id:
468
+ start_time = int(frame_id)/stream_info.get("input_settings", {}).get("original_fps", 30)
469
+ else:
470
+ start_time = stream_info.get("input_settings", {}).get("start_frame", 30)/stream_info.get("input_settings", {}).get("original_fps", 30)
471
+ stream_time_str = self._format_timestamp_for_video(start_time)
472
+ return stream_time_str
464
473
  else:
474
+ # For streams, use stream_time from stream_info
465
475
  stream_time_str = stream_info.get("input_settings", {}).get("stream_info", {}).get("stream_time", "")
466
476
  if stream_time_str:
477
+ # Parse the high precision timestamp string to get timestamp
467
478
  try:
479
+ # Remove " UTC" suffix and parse
468
480
  timestamp_str = stream_time_str.replace(" UTC", "")
469
481
  dt = datetime.strptime(timestamp_str, "%Y-%m-%d-%H:%M:%S.%f")
470
482
  timestamp = dt.replace(tzinfo=timezone.utc).timestamp()
471
483
  return self._format_timestamp_for_stream(timestamp)
472
484
  except:
485
+ # Fallback to current time if parsing fails
473
486
  return self._format_timestamp_for_stream(time.time())
474
487
  else:
475
488
  return self._format_timestamp_for_stream(time.time())
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: matrice
3
- Version: 1.0.99143
3
+ Version: 1.0.99145
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
@@ -191,7 +191,7 @@ matrice/deploy/utils/post_processing/usecases/plaque_segmentation_img.py,sha256=
191
191
  matrice/deploy/utils/post_processing/usecases/pothole_segmentation.py,sha256=6Mv8SoEE5CGItY7S0g-SY5Lb3DV-WWVMlpEp04a86a8,43197
192
192
  matrice/deploy/utils/post_processing/usecases/ppe_compliance.py,sha256=G9P9j9E9nfNJInHJxmK1Lb4daFBlG5hq0aqotTLvFFE,30146
193
193
  matrice/deploy/utils/post_processing/usecases/price_tag_detection.py,sha256=Sn_Dvwf5f_dcfaiPIl-pqckgP8z96CeNIJ4hfeab3FM,39880
194
- matrice/deploy/utils/post_processing/usecases/road_lane_detection.py,sha256=VTPGU1Z2dnOo5x_bwsLY5VczJc_tLApptahxBcEASyo,30186
194
+ matrice/deploy/utils/post_processing/usecases/road_lane_detection.py,sha256=V_KxwBtAHSNkyoH8sXw-U-P3J8ToXtX3ncc69gn6Tds,31591
195
195
  matrice/deploy/utils/post_processing/usecases/shelf_inventory_detection.py,sha256=1juloltHnCj3U499Aps0ggE0nEI37x3iKe4DgfP4RCw,29140
196
196
  matrice/deploy/utils/post_processing/usecases/shoplifting_detection.py,sha256=zqeV_ARV5gJqMY2sJGBjlU6UOb0SthGGbC8UNj_mycs,34701
197
197
  matrice/deploy/utils/post_processing/usecases/shopping_cart_analysis.py,sha256=9Ej2xiZM7yq5sOBcSXIllou_z0rSZDJ_QHyYz6HxZSY,43957
@@ -225,8 +225,8 @@ matrice/deployment/camera_manager.py,sha256=ReBZqm1CNXRImKcbcZ4uWAT3TUWkof1D28oB
225
225
  matrice/deployment/deployment.py,sha256=PLIUD-PxTaC2Zxb3Y12wUddsryV-OJetjCjLoSUh7S4,48103
226
226
  matrice/deployment/inference_pipeline.py,sha256=bXLgd29ViA7o0c7YWLFJl1otBUQfTPb61jS6VawQB0Y,37918
227
227
  matrice/deployment/streaming_gateway_manager.py,sha256=w5swGsuFVfZIdOm2ZuBHRHlRdYYJMLopLsf2gb91lQ8,20946
228
- matrice-1.0.99143.dist-info/licenses/LICENSE.txt,sha256=2bm9uFabQZ3Ykb_SaSU_uUbAj2-htc6WJQmS_65qD00,1073
229
- matrice-1.0.99143.dist-info/METADATA,sha256=PIYKGvaWzfWG2FSrUkwNmHpR4gNBQtlUg13zcFGtgN0,14624
230
- matrice-1.0.99143.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
231
- matrice-1.0.99143.dist-info/top_level.txt,sha256=P97js8ur6o5ClRqMH3Cjoab_NqbJ6sOQ3rJmVzKBvMc,8
232
- matrice-1.0.99143.dist-info/RECORD,,
228
+ matrice-1.0.99145.dist-info/licenses/LICENSE.txt,sha256=2bm9uFabQZ3Ykb_SaSU_uUbAj2-htc6WJQmS_65qD00,1073
229
+ matrice-1.0.99145.dist-info/METADATA,sha256=SZvAGseewa2r30bvP0UDZ6hMk3qOQVPIGonmT3kTSRc,14624
230
+ matrice-1.0.99145.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
231
+ matrice-1.0.99145.dist-info/top_level.txt,sha256=P97js8ur6o5ClRqMH3Cjoab_NqbJ6sOQ3rJmVzKBvMc,8
232
+ matrice-1.0.99145.dist-info/RECORD,,