matrice 1.0.99147__py3-none-any.whl → 1.0.99149__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.
@@ -28,14 +28,14 @@ from ..utils import (
28
28
 
29
29
 
30
30
  # ======================
31
- # 🔧 Config Definition
31
+ # Config Definition
32
32
  # ======================
33
33
 
34
34
 
35
35
 
36
36
  @dataclass
37
37
  class FireSmokeConfig(BaseConfig):
38
- confidence_threshold: float = 0.5
38
+ confidence_threshold: float = 0.3
39
39
 
40
40
  # Only fire and smoke categories included here (exclude normal)
41
41
  fire_smoke_categories: List[str] = field(
@@ -61,6 +61,7 @@ class FireSmokeConfig(BaseConfig):
61
61
  smoothing_window_size: int = 5
62
62
  smoothing_cooldown_frames: int = 10
63
63
  smoothing_confidence_range_factor: float = 0.2
64
+ threshold_area: Optional[float] = 307200.0
64
65
 
65
66
  def __post_init__(self):
66
67
  if not (0.0 <= self.confidence_threshold <= 1.0):
@@ -80,57 +81,14 @@ class FireSmokeUseCase(BaseProcessor):
80
81
  def __init__(self):
81
82
  super().__init__("fire_smoke_detection")
82
83
  self.category = "hazard"
84
+ self.CASE_TYPE: Optional[str] = 'fire_smoke_detection'
85
+ self.CASE_VERSION: Optional[str] = '1.3'
86
+
83
87
  self.smoothing_tracker = None # Required for bbox smoothing
84
88
  self._fire_smoke_recent_history = []
85
89
 
86
- def get_config_schema(self) -> Dict[str, Any]:
87
- """Get configuration schema for fire and smoke detection."""
88
- return {
89
- "type": "object",
90
- "properties": {
91
- "confidence_threshold": {
92
- "type": "number",
93
- "minimum": 0.0,
94
- "maximum": 1.0,
95
- "default": 0.5,
96
- "description": "Minimum confidence threshold for detections",
97
- },
98
- "fire_smoke_categories": {
99
- "type": "array",
100
- "items": {"type": "string"},
101
- "default": ["Fire", "Smoke"],
102
- "description": "Category names that represent fire and smoke",
103
- },
104
- "index_to_category": {
105
- "type": "object",
106
- "additionalProperties": {"type": "string"},
107
- "description": "Mapping from category indices to names",
108
- },
109
- "alert_config": {
110
- "type": "object",
111
- "properties": {
112
- "count_thresholds": {
113
- "type": "object",
114
- "additionalProperties": {"type": "integer", "minimum": 1},
115
- "description": "Count thresholds for alerts",
116
- }
117
- },
118
- },
119
- },
120
- "required": ["confidence_threshold"],
121
- "additionalProperties": False,
122
- }
123
-
124
- def create_default_config(self, **overrides) -> FireSmokeConfig:
125
- """Create default configuration with optional overrides."""
126
- defaults = {
127
- "category": self.category,
128
- "usecase": self.name,
129
- "confidence_threshold": 0.5,
130
- "fire_smoke_categories": ["Fire", "Smoke"],
131
- }
132
- defaults.update(overrides)
133
- return FireSmokeConfig(**defaults)
90
+ self._ascending_alert_list: List[int] = []
91
+ self.current_incident_end_timestamp: str = "N/A"
134
92
 
135
93
  def process(
136
94
  self,
@@ -203,20 +161,10 @@ class FireSmokeUseCase(BaseProcessor):
203
161
  fire_smoke_summary = self._calculate_fire_smoke_summary(processed_data, config)
204
162
  general_summary = calculate_counting_summary(processed_data)
205
163
 
206
- # Step 5: Insights & alerts
207
- insights = self._generate_insights(fire_smoke_summary, config)
208
- alerts = self._check_alerts(fire_smoke_summary, config)
209
-
210
- # Step 6: Metrics
211
- metrics = self._calculate_metrics(fire_smoke_summary, config, context)
212
-
213
- # Step 7: Predictions
164
+ # Step 5: Predictions
214
165
  predictions = self._extract_predictions(processed_data, config)
215
166
 
216
- # Step 8: Human-readable summary
217
- summary_text = self._generate_summary(fire_smoke_summary, general_summary, alerts)
218
-
219
- # Step 9: Frame number extraction
167
+ # Step 6: Frame number extraction
220
168
  frame_number = None
221
169
  if stream_info:
222
170
  input_settings = stream_info.get("input_settings", {})
@@ -227,38 +175,45 @@ class FireSmokeUseCase(BaseProcessor):
227
175
  elif start_frame is not None:
228
176
  frame_number = start_frame
229
177
 
230
- # Step 10: Events and tracking stats
231
- events_dict = self._generate_events(fire_smoke_summary, alerts, config, frame_number=frame_number)
232
- tracking_stats_dict = self._generate_tracking_stats(
233
- fire_smoke_summary, insights, summary_text, config,
178
+ # Step 7: alerts
179
+ alerts = self._check_alerts(fire_smoke_summary, frame_number, config, stream_info)
180
+
181
+
182
+ # Step 8: Incidents and tracking stats
183
+ incidents_list = self._generate_incidents(fire_smoke_summary, alerts, config, frame_number=frame_number, stream_info=stream_info)
184
+ tracking_stats_list = self._generate_tracking_stats(
185
+ fire_smoke_summary, alerts, config,
234
186
  frame_number=frame_number,
235
187
  stream_info=stream_info
236
188
  )
189
+ business_analytics_list = self._generate_business_analytics(fire_smoke_summary, alerts, config, stream_info, is_empty=True)
190
+
191
+ # Step 9: Human-readable summary
192
+ summary_list = self._generate_summary(fire_smoke_summary, general_summary, incidents_list, tracking_stats_list, business_analytics_list, alerts)
237
193
 
238
194
  # Finalize context and return result
239
195
  context.processing_time = time.time() - start_time
196
+ # Extract frame-based dictionaries from the lists
197
+ incidents = incidents_list[0] if incidents_list else {}
198
+ tracking_stats = tracking_stats_list[0] if tracking_stats_list else {}
199
+ business_analytics = business_analytics_list[0] if business_analytics_list else {}
200
+ summary = summary_list[0] if summary_list else {}
201
+ agg_summary = {str(frame_number): {
202
+ "incidents": incidents,
203
+ "tracking_stats": tracking_stats,
204
+ "business_analytics": business_analytics,
205
+ "alerts": alerts,
206
+ "human_text": summary}
207
+ }
208
+
240
209
  context.mark_completed()
241
210
 
242
211
  result = self.create_result(
243
- data={
244
- "fire_smoke_summary": fire_smoke_summary,
245
- "general_counting_summary": general_summary,
246
- "alerts": alerts,
247
- "total_fire_smoke_detections": fire_smoke_summary.get("total_objects", 0),
248
- "total_fire_detections": fire_smoke_summary.get("by_category", {}).get("fire", 0),
249
- "total_smoke_detections": fire_smoke_summary.get("by_category", {}).get("smoke", 0),
250
- "events": events_dict,
251
- "tracking_stats": tracking_stats_dict,
252
- },
253
- usecase=self.name,
254
- category=self.category,
255
- context=context,
256
- )
212
+ data={"agg_summary": agg_summary},
213
+ usecase=self.name,
214
+ category=self.category,
215
+ context=context)
257
216
 
258
- result.summary = summary_text
259
- result.insights = insights
260
- result.predictions = predictions
261
- result.metrics = metrics
262
217
  return result
263
218
 
264
219
 
@@ -272,7 +227,340 @@ class FireSmokeUseCase(BaseProcessor):
272
227
  context=context,
273
228
  )
274
229
 
275
- # ==== 🔍 Internal Utilities ====
230
+ # ==== Internal Utilities ====
231
+ def _check_alerts(
232
+ self, summary: Dict, frame_number:Any, config: FireSmokeConfig, stream_info: Optional[Dict[str, Any]] = None
233
+ ) -> List[Dict]:
234
+ """Raise alerts if fire or smoke detected with severity based on intensity."""
235
+ def get_trend(data, lookback=900, threshold=0.6):
236
+ '''
237
+ Determine if the trend is ascending or descending based on actual value progression.
238
+ Now works with values 0,1,2,3 (not just binary).
239
+ '''
240
+ window = data[-lookback:] if len(data) >= lookback else data
241
+ if len(window) < 2:
242
+ return True # not enough data to determine trend
243
+ increasing = 0
244
+ total = 0
245
+ for i in range(1, len(window)):
246
+ if window[i] >= window[i - 1]:
247
+ increasing += 1
248
+ total += 1
249
+ ratio = increasing / total
250
+ if ratio >= threshold:
251
+ return True
252
+ elif ratio <= (1 - threshold):
253
+ return False
254
+
255
+ alerts = []
256
+ total = summary.get("total_objects", 0)
257
+ by_category = summary.get("by_category", {})
258
+ detections = summary.get("detections", [])
259
+ frame_key = str(frame_number) if frame_number is not None else "current_frame"
260
+
261
+ if total == 0:
262
+ return []
263
+ if not config.alert_config:
264
+ return alerts
265
+
266
+ if hasattr(config.alert_config, 'count_thresholds') and config.alert_config.count_thresholds:
267
+
268
+ for category, threshold in config.alert_config.count_thresholds.items():
269
+ if category == "all" and total > threshold:
270
+
271
+ alerts.append({
272
+ "alert_type": getattr(config.alert_config, 'alert_type', ['Default']) if hasattr(config.alert_config, 'alert_type') else ['Default'],
273
+ "alert_id": "alert_"+category+'_'+frame_key,
274
+ "incident_category": self.CASE_TYPE,
275
+ "threshold_level": threshold,
276
+ "ascending": get_trend(self._ascending_alert_list, lookback=900, threshold=0.8),
277
+ "settings": {t: v for t, v in zip(getattr(config.alert_config, 'alert_type', ['Default']) if hasattr(config.alert_config, 'alert_type') else ['Default'],
278
+ getattr(config.alert_config, 'alert_value', ['JSON']) if hasattr(config.alert_config, 'alert_value') else ['JSON'])
279
+ }
280
+ })
281
+ elif category in summary.get("per_category_count", {}):
282
+ count = summary.get("per_category_count", {})[category]
283
+ if count > threshold: # Fixed logic: alert when EXCEEDING threshold
284
+ alerts.append({
285
+ "alert_type": getattr(config.alert_config, 'alert_type', ['Default']) if hasattr(config.alert_config, 'alert_type') else ['Default'],
286
+ "alert_id": "alert_"+category+'_'+frame_key,
287
+ "incident_category": self.CASE_TYPE,
288
+ "threshold_level": threshold,
289
+ "ascending": get_trend(self._ascending_alert_list, lookback=900, threshold=0.8),
290
+ "settings": {t: v for t, v in zip(getattr(config.alert_config, 'alert_type', ['Default']) if hasattr(config.alert_config, 'alert_type') else ['Default'],
291
+ getattr(config.alert_config, 'alert_value', ['JSON']) if hasattr(config.alert_config, 'alert_value') else ['JSON'])
292
+ }
293
+ })
294
+ else:
295
+ pass
296
+
297
+ return alerts
298
+
299
+ def _generate_incidents(
300
+ self,
301
+ summary: Dict,
302
+ alerts: List[Dict],
303
+ config: FireSmokeConfig,
304
+ frame_number: Optional[int] = None,
305
+ stream_info: Optional[Dict[str, Any]] = None
306
+ ) -> Dict:
307
+ """Generate structured events for fire and smoke detection output with frame-aware keys."""
308
+
309
+ frame_key = str(frame_number) if frame_number is not None else "current_frame"
310
+ incidents = []
311
+
312
+ total = summary.get("total_objects", 0)
313
+ by_category = summary.get("by_category", {})
314
+ detections = summary.get("detections", [])
315
+
316
+ total_fire = by_category.get("fire", 0)
317
+ total_smoke = by_category.get("smoke", 0)
318
+ current_timestamp = self._get_current_timestamp_str(stream_info)
319
+ camera_info = self.get_camera_info_from_stream(stream_info)
320
+ self._ascending_alert_list = self._ascending_alert_list[-900:] if len(self._ascending_alert_list) > 900 else self._ascending_alert_list
321
+
322
+ if total > 0:
323
+ # Calculate total bbox area
324
+ total_area = 0.0
325
+
326
+ for category, threshold in config.alert_config.count_thresholds.items():
327
+ if category in summary.get("per_category_count", {}):
328
+ #count = summary.get("per_category_count", {})[category]
329
+ start_timestamp = self._get_start_timestamp_str(stream_info)
330
+ if start_timestamp and self.current_incident_end_timestamp=='N/A':
331
+ self.current_incident_end_timestamp = 'Incident still active'
332
+ elif start_timestamp and self.current_incident_end_timestamp=='Incident still active':
333
+ if len(self._ascending_alert_list) >= 15 and sum(self._ascending_alert_list[-15:]) / 15 < 1.5:
334
+ self.current_incident_end_timestamp = current_timestamp
335
+ elif self.current_incident_end_timestamp!='Incident still active' and self.current_incident_end_timestamp!='N/A':
336
+ self.current_incident_end_timestamp = 'N/A'
337
+
338
+ for det in detections:
339
+ bbox = det.get("bounding_box") or det.get("bbox")
340
+ if bbox:
341
+ xmin = bbox.get("xmin")
342
+ ymin = bbox.get("ymin")
343
+ xmax = bbox.get("xmax")
344
+ ymax = bbox.get("ymax")
345
+ if None not in (xmin, ymin, xmax, ymax):
346
+ width = xmax - xmin
347
+ height = ymax - ymin
348
+ if width > 0 and height > 0:
349
+ total_area += width * height
350
+
351
+ threshold_area = config.threshold_area # 307200.0 | Same threshold as insights
352
+
353
+ intensity_pct = min(100.0, (total_area / threshold_area) * 100)
354
+
355
+ if config.alert_config and config.alert_config.count_thresholds:
356
+ if intensity_pct >= 60:
357
+ level = "critical"
358
+ self._ascending_alert_list.append(3)
359
+ elif intensity_pct >= 40:
360
+ level = "significant"
361
+ self._ascending_alert_list.append(2)
362
+ elif intensity_pct >= 5:
363
+ level = "medium"
364
+ self._ascending_alert_list.append(1)
365
+ else:
366
+ level = "low"
367
+ self._ascending_alert_list.append(0)
368
+ else:
369
+ if intensity_pct > 60:
370
+ level = "critical"
371
+ intensity = 10.0
372
+ self._ascending_alert_list.append(3)
373
+ elif intensity_pct > 40:
374
+ level = "significant"
375
+ intensity = 9.0
376
+ self._ascending_alert_list.append(2)
377
+ elif intensity_pct > 4:
378
+ level = "medium"
379
+ intensity = 7.0
380
+ self._ascending_alert_list.append(1)
381
+ else:
382
+ level = "low"
383
+ intensity = min(10.0, intensity_pct / 3.0)
384
+ self._ascending_alert_list.append(0)
385
+
386
+ # Generate human text in new format
387
+ human_text_lines = [f"INCIDENTS DETECTED @ {current_timestamp}:"]
388
+ human_text_lines.append(f"\tSeverity Level: {(self.CASE_TYPE,level)}")
389
+ human_text = "\n".join(human_text_lines)
390
+
391
+ alert_settings=[]
392
+ if config.alert_config and hasattr(config.alert_config, 'alert_type'):
393
+ alert_settings.append({
394
+ "alert_type": getattr(config.alert_config, 'alert_type', ['Default']) if hasattr(config.alert_config, 'alert_type') else ['Default'],
395
+ "incident_category": self.CASE_TYPE,
396
+ "threshold_level": config.alert_config.count_thresholds if hasattr(config.alert_config, 'count_thresholds') else {},
397
+ "ascending": True,
398
+ "settings": {t: v for t, v in zip(getattr(config.alert_config, 'alert_type', ['Default']) if hasattr(config.alert_config, 'alert_type') else ['Default'],
399
+ getattr(config.alert_config, 'alert_value', ['JSON']) if hasattr(config.alert_config, 'alert_value') else ['JSON'])
400
+ }
401
+ })
402
+
403
+ event= self.create_incident(incident_id=self.CASE_TYPE+'_'+str(frame_number), incident_type=self.CASE_TYPE,
404
+ severity_level=level, human_text=human_text, camera_info=camera_info, alerts=alerts, alert_settings=alert_settings,
405
+ start_time=start_timestamp, end_time=self.current_incident_end_timestamp,
406
+ level_settings= {"low": 1, "medium": 5, "significant":40, "critical": 60})
407
+ incidents.append(event)
408
+
409
+ else:
410
+ self._ascending_alert_list.append(0)
411
+ incidents.append({})
412
+ return incidents
413
+
414
+ def _generate_tracking_stats(
415
+ self,
416
+ summary: Dict,
417
+ alerts: List,
418
+ config: FireSmokeConfig,
419
+ frame_number: Optional[int] = None,
420
+ stream_info: Optional[Dict[str, Any]] = None
421
+ ) -> Dict:
422
+ """Generate structured tracking stats for fire and smoke detection with frame-based keys."""
423
+
424
+ frame_key = str(frame_number) if frame_number is not None else "current_frame"
425
+ tracking_stats = []
426
+ camera_info = self.get_camera_info_from_stream(stream_info)
427
+
428
+ total = summary.get("total_objects", 0)
429
+ by_category = summary.get("by_category", {})
430
+ detections = summary.get("detections", [])
431
+
432
+ total_fire = by_category.get("fire", 0)
433
+ total_smoke = by_category.get("smoke", 0)
434
+
435
+ # Maintain rolling detection history
436
+ if frame_number is not None:
437
+ self._fire_smoke_recent_history.append({
438
+ "frame": frame_number,
439
+ "fire": total_fire,
440
+ "smoke": total_smoke,
441
+ })
442
+ if len(self._fire_smoke_recent_history) > 150:
443
+ self._fire_smoke_recent_history.pop(0)
444
+
445
+ # Generate human-readable tracking text (people-style format)
446
+ current_timestamp = self._get_current_timestamp_str(stream_info)
447
+ start_timestamp = self._get_start_timestamp_str(stream_info)
448
+ # Create high precision timestamps for input_timestamp and reset_timestamp
449
+ high_precision_start_timestamp = self._get_current_timestamp_str(stream_info, precision=True)
450
+ high_precision_reset_timestamp = self._get_start_timestamp_str(stream_info, precision=True)
451
+
452
+
453
+ # Build total_counts array in expected format
454
+ total_counts = []
455
+ if total > 0:
456
+ total_counts.append({
457
+ "category": 'Fire/Smoke', #TODO: Discuss and fix what to do with this
458
+ "count": 1
459
+ })
460
+
461
+ # Build current_counts array in expected format
462
+ current_counts = []
463
+ if total > 0: # Include even if 0 when there are detections
464
+ current_counts.append({
465
+ "category": 'Fire/Smoke', #TODO: Discuss and fix what to do with this
466
+ "count": 1
467
+ })
468
+
469
+ human_lines = [f"CURRENT FRAME @ {current_timestamp}:"]
470
+ if total_fire > 0:
471
+ human_lines.append(f"\t- Fire regions detected: {total_fire}")
472
+ if total_smoke > 0:
473
+ human_lines.append(f"\t- Smoke clouds detected: {total_smoke}")
474
+ if total_fire == 0 and total_smoke == 0:
475
+ human_lines.append(f"\t- No fire or smoke detected")
476
+
477
+ human_lines.append("")
478
+ human_lines.append(f"ALERTS SINCE @ {start_timestamp}:")
479
+
480
+ recent_fire_detected = any(entry.get("fire", 0) > 0 for entry in self._fire_smoke_recent_history)
481
+ recent_smoke_detected = any(entry.get("smoke", 0) > 0 for entry in self._fire_smoke_recent_history)
482
+
483
+ if recent_fire_detected:
484
+ human_lines.append(f"\t- Fire alert")
485
+ if recent_smoke_detected:
486
+ human_lines.append(f"\t- Smoke alert")
487
+ if not recent_fire_detected and not recent_smoke_detected:
488
+ human_lines.append(f"\t- No fire or smoke detected in recent frames")
489
+
490
+ human_text = "\n".join(human_lines)
491
+
492
+ # Prepare detections without confidence scores (as per eg.json)
493
+ detections = []
494
+ for detection in summary.get("detections", []):
495
+ bbox = detection.get("bounding_box", {})
496
+ category = detection.get("category", "Fire/Smoke")
497
+ # Include segmentation if available (like in eg.json)
498
+ if detection.get("masks"):
499
+ segmentation= detection.get("masks", [])
500
+ detection_obj = self.create_detection_object(category, bbox, segmentation=segmentation)
501
+ elif detection.get("segmentation"):
502
+ segmentation= detection.get("segmentation")
503
+ detection_obj = self.create_detection_object(category, bbox, segmentation=segmentation)
504
+ elif detection.get("mask"):
505
+ segmentation= detection.get("mask")
506
+ detection_obj = self.create_detection_object(category, bbox, segmentation=segmentation)
507
+ else:
508
+ detection_obj = self.create_detection_object(category, bbox)
509
+ detections.append(detection_obj)
510
+
511
+ # Build alert_settings array in expected format
512
+ alert_settings = []
513
+ if config.alert_config and hasattr(config.alert_config, 'alert_type'):
514
+ alert_settings.append({
515
+ "alert_type": getattr(config.alert_config, 'alert_type', ['Default']) if hasattr(config.alert_config, 'alert_type') else ['Default'],
516
+ "incident_category": self.CASE_TYPE,
517
+ "threshold_level": config.alert_config.count_thresholds if hasattr(config.alert_config, 'count_thresholds') else {},
518
+ "ascending": True,
519
+ "settings": {t: v for t, v in zip(getattr(config.alert_config, 'alert_type', ['Default']) if hasattr(config.alert_config, 'alert_type') else ['Default'],
520
+ getattr(config.alert_config, 'alert_value', ['JSON']) if hasattr(config.alert_config, 'alert_value') else ['JSON'])
521
+ }
522
+ })
523
+
524
+ reset_settings=[
525
+ {
526
+ "interval_type": "daily",
527
+ "reset_time": {
528
+ "value": 9,
529
+ "time_unit": "hour"
530
+ }
531
+ }
532
+ ]
533
+
534
+ tracking_stat=self.create_tracking_stats(total_counts=total_counts, current_counts=current_counts,
535
+ detections=detections, human_text=human_text, camera_info=camera_info, alerts=alerts, alert_settings=alert_settings,
536
+ reset_settings=reset_settings, start_time=high_precision_start_timestamp ,
537
+ reset_time=high_precision_reset_timestamp)
538
+
539
+
540
+ tracking_stats.append(tracking_stat)
541
+ return tracking_stats
542
+
543
+ def _generate_summary(
544
+ self, summary: dict, general_summary: dict, incidents: List, tracking_stats: List, business_analytics: List, alerts: List
545
+ ) -> str:
546
+ """
547
+ Generate a human_text string for the tracking_stat, incident, business analytics and alerts.
548
+ """
549
+ lines = {}
550
+ lines["Application Name"] = self.CASE_TYPE
551
+ lines["Application Version"] = self.CASE_VERSION
552
+ if len(incidents) > 0:
553
+ lines["Incidents:"]=f"\n\t{incidents[0].get('human_text', 'No incidents detected')}\n"
554
+ if len(tracking_stats) > 0:
555
+ lines["Tracking Statistics:"]=f"\t{tracking_stats[0].get('human_text', 'No tracking statistics detected')}\n"
556
+ if len(business_analytics) > 0:
557
+ lines["Business Analytics:"]=f"\t{business_analytics[0].get('human_text', 'No business analytics detected')}\n"
558
+
559
+ if len(incidents) == 0 and len(tracking_stats) == 0 and len(business_analytics) == 0:
560
+ lines["Summary"] = "No Summary Data"
561
+
562
+ return [lines]
563
+
276
564
  def _calculate_fire_smoke_summary(
277
565
  self, data: Any, config: FireSmokeConfig
278
566
  ) -> Dict[str, Any]:
@@ -304,113 +592,17 @@ class FireSmokeUseCase(BaseProcessor):
304
592
 
305
593
  return {"total_objects": 0, "by_category": {}, "detections": []}
306
594
 
307
- def _generate_insights(
308
- self, summary: Dict, config: FireSmokeConfig
309
- ) -> List[str]:
310
- """Generate insights using bbox area for intensity."""
311
-
312
- insights = []
313
-
314
- total = summary.get("total_objects", 0)
315
- by_category = summary.get("by_category", {})
316
- detections = summary.get("detections", [])
317
-
318
- total_fire = by_category.get("fire", 0)
319
- total_smoke = by_category.get("smoke", 0)
320
-
321
- if total == 0:
322
- insights.append("EVENT: No fire or smoke detected in the scene")
323
- else:
324
- if total_fire > 0:
325
- insights.append(f"EVENT: {total_fire} fire region{'s' if total_fire != 1 else ''} detected")
326
- if total_smoke > 0:
327
- insights.append(f"EVENT: {total_smoke} smoke cloud{'s' if total_smoke != 1 else ''} detected")
328
-
329
- fire_percent = (total_fire / total) * 100 if total else 0
330
- smoke_percent = (total_smoke / total) * 100 if total else 0
331
- insights.append(f"ANALYSIS: {fire_percent:.1f}% fire, {smoke_percent:.1f}% smoke in detected hazards")
332
-
333
- # Calculate total bbox area using xmin, ymin, xmax, ymax format
334
- total_area = 0.0
335
- for det in detections:
336
- bbox = det.get("bounding_box") or det.get("bbox")
337
- if bbox:
338
- xmin = bbox.get("xmin")
339
- ymin = bbox.get("ymin")
340
- xmax = bbox.get("xmax")
341
- ymax = bbox.get("ymax")
342
- if None not in (xmin, ymin, xmax, ymax):
343
- width = xmax - xmin
344
- height = ymax - ymin
345
- if width > 0 and height > 0:
346
- total_area += width * height
347
-
348
- # Threshold area (configurable if you want)
349
- threshold_area = 10000.0
350
-
351
- intensity_pct = min(100.0, (total_area / threshold_area) * 100)
352
-
353
- if intensity_pct < 20:
354
- insights.append(f"INTENSITY: Low fire/smoke activity ({intensity_pct:.1f}% area coverage)")
355
- elif intensity_pct <= 50:
356
- insights.append(f"INTENSITY: Moderate fire/smoke activity ({intensity_pct:.1f}%)")
357
- elif intensity_pct <= 80:
358
- insights.append(f"INTENSITY: High fire/smoke activity ({intensity_pct:.1f}%)")
359
- else:
360
- insights.append(f"INTENSITY: Very high fire/smoke activity — critical hazard ({intensity_pct:.1f}%)")
361
-
362
- return insights
363
-
364
- def _check_alerts(
365
- self, summary: Dict, config: FireSmokeConfig
366
- ) -> List[Dict]:
367
- """Raise alerts if fire or smoke detected with severity based on intensity."""
368
-
369
- alerts = []
370
- total = summary.get("total_objects", 0)
371
- by_category = summary.get("by_category", {})
372
- detections = summary.get("detections", [])
373
-
374
- if total == 0:
595
+ def _generate_business_analytics(self, counting_summary: Dict, alerts:Any, config: FireSmokeConfig, stream_info: Optional[Dict[str, Any]] = None, is_empty=False) -> List[Dict]:
596
+ """Generate standardized business analytics for the agg_summary structure."""
597
+ if is_empty:
375
598
  return []
376
599
 
377
- # Calculate total bbox area
378
- total_area = 0.0
379
- for det in detections:
380
- bbox = det.get("bounding_box") or det.get("bbox")
381
- if bbox:
382
- xmin = bbox.get("xmin")
383
- ymin = bbox.get("ymin")
384
- xmax = bbox.get("xmax")
385
- ymax = bbox.get("ymax")
386
- if None not in (xmin, ymin, xmax, ymax):
387
- width = xmax - xmin
388
- height = ymax - ymin
389
- if width > 0 and height > 0:
390
- total_area += width * height
391
-
392
- threshold_area = 10000.0 # Same threshold as insights
393
-
394
- intensity_pct = min(100.0, (total_area / threshold_area) * 100)
395
-
396
- # Determine alert severity
397
- if intensity_pct > 80:
398
- severity = "critical"
399
- elif intensity_pct > 50:
400
- severity = "warning"
401
- else:
402
- severity = "info"
403
-
404
- alert = {
405
- "type": "fire_smoke_alert",
406
- "message": f"{total} fire/smoke detection{'s' if total != 1 else ''} with intensity {intensity_pct:.1f}%",
407
- "severity": severity,
408
- "detected_fire": by_category.get("fire", 0),
409
- "detected_smoke": by_category.get("smoke", 0),
410
- }
411
-
412
- alerts.append(alert)
413
- return alerts
600
+ #-----IF YOUR USECASE NEEDS BUSINESS ANALYTICS, YOU CAN USE THIS FUNCTION------#
601
+ #camera_info = self.get_camera_info_from_stream(stream_info)
602
+ # business_analytics = self.create_business_analytics(nalysis_name, statistics,
603
+ # human_text, camera_info=camera_info, alerts=alerts, alert_settings=alert_settings,
604
+ # reset_settings)
605
+ # return business_analytics
414
606
 
415
607
  def _calculate_metrics(
416
608
  self,
@@ -489,273 +681,55 @@ class FireSmokeUseCase(BaseProcessor):
489
681
  self.logger.warning(f"Failed to extract predictions: {str(e)}")
490
682
 
491
683
  return predictions
492
-
493
- def _generate_summary(
494
- self, summary: Dict, general_summary: Dict, alerts: List
495
- ) -> str:
496
- """Generate human-readable summary for fire and smoke detection."""
497
- total = summary.get("total_objects", 0)
498
- total_fire = summary.get("by_category", {}).get("fire", 0)
499
- total_smoke = summary.get("by_category", {}).get("smoke", 0)
500
-
501
- if total == 0:
502
- return "No fire or smoke detected"
503
-
504
- summary_parts = []
505
-
506
- if total_fire > 0:
507
- summary_parts.append(
508
- f"{total_fire} fire region{'s' if total_fire != 1 else ''} detected"
509
- )
510
-
511
- if total_smoke > 0:
512
- summary_parts.append(
513
- f"{total_smoke} smoke cloud{'s' if total_smoke != 1 else ''} detected"
514
- )
515
-
516
- if alerts:
517
- alert_count = len(alerts)
518
- summary_parts.append(
519
- f"{alert_count} alert{'s' if alert_count != 1 else ''}"
520
- )
521
-
522
- return ", ".join(summary_parts)
523
-
524
- def _generate_events(
525
- self,
526
- summary: Dict,
527
- alerts: List[Dict],
528
- config: FireSmokeConfig,
529
- frame_number: Optional[int] = None
530
- ) -> Dict:
531
- """Generate structured events for fire and smoke detection output with frame-aware keys."""
532
- from datetime import datetime, timezone
533
-
534
- frame_key = str(frame_number) if frame_number is not None else "current_frame"
535
- events = {frame_key: []}
536
- frame_events = events[frame_key]
537
-
538
- total = summary.get("total_objects", 0)
539
- by_category = summary.get("by_category", {})
540
- detections = summary.get("detections", [])
541
-
542
- total_fire = by_category.get("fire", 0)
543
- total_smoke = by_category.get("smoke", 0)
544
-
545
- if total > 0:
546
- # Calculate total detection area
547
- total_area = 0.0
548
- for det in detections:
549
- bbox = det.get("bounding_box") or det.get("bbox")
550
- if bbox:
551
- xmin = bbox.get("xmin")
552
- ymin = bbox.get("ymin")
553
- xmax = bbox.get("xmax")
554
- ymax = bbox.get("ymax")
555
- if None not in (xmin, ymin, xmax, ymax):
556
- width = xmax - xmin
557
- height = ymax - ymin
558
- if width > 0 and height > 0:
559
- total_area += width * height
560
-
561
- threshold_area = 10000.0
562
- intensity = min(10.0, (total_area / threshold_area) * 10)
563
-
564
- if intensity >= 7:
565
- level = "critical"
566
- elif intensity >= 5:
567
- level = "warning"
568
- else:
569
- level = "info"
570
-
571
- # Use consistent formatting for human_text
572
- human_lines = []
573
- if total_fire > 0:
574
- human_lines.append(" - fire detected")
575
- if total_smoke > 0:
576
- human_lines.append(" - smoke detected")
577
- if total_fire == 0 and total_smoke == 0:
578
- human_lines.append(" - no fire or smoke detected")
579
-
580
- fire_smoke_event = {
581
- "type": "fire_smoke_detection",
582
- "stream_time": datetime.now(timezone.utc).strftime("%Y-%m-%d-%H:%M:%S UTC"),
583
- "level": level,
584
- "intensity": round(intensity, 1),
585
- "config": {
586
- "min_value": 0,
587
- "max_value": 10,
588
- "level_settings": {"info": 2, "warning": 5, "critical": 7},
684
+
685
+ def get_config_schema(self) -> Dict[str, Any]:
686
+ """Get configuration schema for fire and smoke detection."""
687
+ return {
688
+ "type": "object",
689
+ "properties": {
690
+ "confidence_threshold": {
691
+ "type": "number",
692
+ "minimum": 0.0,
693
+ "maximum": 1.0,
694
+ "default": 0.5,
695
+ "description": "Minimum confidence threshold for detections",
589
696
  },
590
- "application_name": "Fire and Smoke Detection System",
591
- "application_version": "1.0",
592
- "location_info": None,
593
- "human_text": "\n".join(human_lines),
594
- }
595
- frame_events.append(fire_smoke_event)
596
-
597
- # Add alert events
598
- for alert in alerts:
599
- alert_lines = []
600
- if total_fire > 0:
601
- alert_lines.append(" - fire detected")
602
- if total_smoke > 0:
603
- alert_lines.append(" - smoke detected")
604
- if total_fire == 0 and total_smoke == 0:
605
- alert_lines.append(" - no fire or smoke detected")
606
-
607
- alert_text = "\n".join(alert_lines)
608
-
609
- alert_event = {
610
- "type": alert.get("type", "fire_smoke_alert"),
611
- "stream_time": datetime.now(timezone.utc).strftime("%Y-%m-%d-%H:%M:%S UTC"),
612
- "level": alert.get("severity", "warning"),
613
- "intensity": 8.0,
614
- "config": {
615
- "min_value": 0,
616
- "max_value": 10,
617
- "level_settings": {"info": 2, "warning": 5, "critical": 7},
697
+ "fire_smoke_categories": {
698
+ "type": "array",
699
+ "items": {"type": "string"},
700
+ "default": ["Fire", "Smoke"],
701
+ "description": "Category names that represent fire and smoke",
702
+ },
703
+ "index_to_category": {
704
+ "type": "object",
705
+ "additionalProperties": {"type": "string"},
706
+ "description": "Mapping from category indices to names",
707
+ },
708
+ "alert_config": {
709
+ "type": "object",
710
+ "properties": {
711
+ "count_thresholds": {
712
+ "type": "object",
713
+ "additionalProperties": {"type": "integer", "minimum": 1},
714
+ "description": "Count thresholds for alerts",
715
+ }
716
+ },
618
717
  },
619
- "application_name": "Fire and Smoke Alert System",
620
- "application_version": "1.0",
621
- "location_info": None,
622
- "human_text": alert_text,
623
- }
624
- frame_events.append(alert_event)
625
-
626
- return events
627
-
628
- def _generate_tracking_stats(
629
- self,
630
- summary: Dict,
631
- insights: List[str],
632
- summary_text: str,
633
- config: FireSmokeConfig,
634
- frame_number: Optional[int] = None,
635
- stream_info: Optional[Dict[str, Any]] = None
636
- ) -> Dict:
637
- """Generate structured tracking stats for fire and smoke detection with frame-based keys."""
638
-
639
- frame_key = str(frame_number) if frame_number is not None else "current_frame"
640
- tracking_stats = {frame_key: []}
641
- frame_tracking_stats = tracking_stats[frame_key]
642
-
643
- total = summary.get("total_objects", 0)
644
- by_category = summary.get("by_category", {})
645
- detections = summary.get("detections", [])
646
-
647
- total_fire = by_category.get("fire", 0)
648
- total_smoke = by_category.get("smoke", 0)
649
-
650
- # Maintain rolling detection history
651
- if frame_number is not None:
652
- self._fire_smoke_recent_history.append({
653
- "frame": frame_number,
654
- "fire": total_fire,
655
- "smoke": total_smoke,
656
- })
657
- if len(self._fire_smoke_recent_history) > 150:
658
- self._fire_smoke_recent_history.pop(0)
659
-
660
- # Compute total bbox area for intensity percentage
661
- total_area = 0.0
662
- for det in detections:
663
- bbox = det.get("bounding_box") or det.get("bbox")
664
- if bbox:
665
- xmin = bbox.get("xmin")
666
- ymin = bbox.get("ymin")
667
- xmax = bbox.get("xmax")
668
- ymax = bbox.get("ymax")
669
- if None not in (xmin, ymin, xmax, ymax):
670
- width = xmax - xmin
671
- height = ymax - ymin
672
- if width > 0 and height > 0:
673
- total_area += width * height
674
-
675
- threshold_area = 10000.0
676
- intensity_pct = min(100.0, (total_area / threshold_area) * 100)
677
-
678
- # Generate human-readable tracking text (people-style format)
679
- current_timestamp = self._get_current_timestamp_str(stream_info)
680
- start_timestamp = self._get_start_timestamp_str(stream_info)
681
-
682
- human_lines = [f"CURRENT FRAME @ {current_timestamp}:"]
683
- if total_fire > 0:
684
- human_lines.append(f"\t- Fire regions detected: {total_fire}")
685
- if total_smoke > 0:
686
- human_lines.append(f"\t- Smoke clouds detected: {total_smoke}")
687
- if total_fire == 0 and total_smoke == 0:
688
- human_lines.append(f"\t- No fire or smoke detected")
689
-
690
- human_lines.append("")
691
- human_lines.append(f"ALERTS SINCE @ {start_timestamp}:")
692
-
693
- recent_fire_detected = any(entry.get("fire", 0) > 0 for entry in self._fire_smoke_recent_history)
694
- recent_smoke_detected = any(entry.get("smoke", 0) > 0 for entry in self._fire_smoke_recent_history)
695
-
696
- if recent_fire_detected:
697
- human_lines.append(f"\t- Fire alert")
698
- if recent_smoke_detected:
699
- human_lines.append(f"\t- Smoke alert")
700
- if not recent_fire_detected and not recent_smoke_detected:
701
- human_lines.append(f"\t- No fire or smoke detected in recent frames")
702
-
703
- human_text = "\n".join(human_lines)
704
-
705
- tracking_stat = {
706
- "all_results_for_tracking": {
707
- "total_detections": total,
708
- "total_fire": total_fire,
709
- "total_smoke": total_smoke,
710
- "intensity_percentage": intensity_pct,
711
- "fire_smoke_summary": summary,
712
- "unique_count": self._count_unique_tracks(summary)
713
718
  },
714
- "human_text": human_text
719
+ "required": ["confidence_threshold"],
720
+ "additionalProperties": False,
715
721
  }
716
722
 
717
- frame_tracking_stats.append(tracking_stat)
718
- return tracking_stats
719
-
720
- def _generate_human_text_for_tracking(
721
- self,
722
- total_fire: int,
723
- total_smoke: int,
724
- intensity_pct: float,
725
- insights: List[str],
726
- summary_text: str,
727
- frame_number: Optional[int] = None,
728
- stream_info: Optional[Dict[str, Any]] = None,
729
- ) -> str:
730
- """Generate structured and formatted human_text for tracking stats."""
731
- current_time_str = self._get_current_timestamp_str(stream_info)
732
- start_time_str = self._get_start_timestamp_str(stream_info)
733
-
734
- human_text_lines = []
735
- human_text_lines.append(f"CURRENT FRAME @ {current_time_str}:")
736
-
737
- if total_fire > 0:
738
- human_text_lines.append("\t- fire detected")
739
- if total_smoke > 0:
740
- human_text_lines.append("\t- smoke detected")
741
- if total_fire == 0 and total_smoke == 0:
742
- human_text_lines.append("\t- no fire or smoke detected")
743
-
744
- human_text_lines.append("") # Empty line for spacing
745
- human_text_lines.append(f"ALERTS SINCE @ {start_time_str}:")
746
-
747
- # Look into 150-frame history
748
- recent_fire_detected = any(entry.get("fire", 0) > 0 for entry in self._fire_smoke_recent_history)
749
- recent_smoke_detected = any(entry.get("smoke", 0) > 0 for entry in self._fire_smoke_recent_history)
750
-
751
- if recent_fire_detected:
752
- human_text_lines.append("\t- Fire alert")
753
- if recent_smoke_detected:
754
- human_text_lines.append("\t- Smoke alert")
755
- if not recent_fire_detected and not recent_smoke_detected:
756
- human_text_lines.append("\t- No fire or smoke detected in recent frames")
757
-
758
- return "\n".join(human_text_lines)
723
+ def create_default_config(self, **overrides) -> FireSmokeConfig:
724
+ """Create default configuration with optional overrides."""
725
+ defaults = {
726
+ "category": self.category,
727
+ "usecase": self.name,
728
+ "confidence_threshold": 0.5,
729
+ "fire_smoke_categories": ["Fire", "Smoke"],
730
+ }
731
+ defaults.update(overrides)
732
+ return FireSmokeConfig(**defaults)
759
733
 
760
734
  def _count_unique_tracks(self, summary: Dict) -> Optional[int]:
761
735
  """Count unique track IDs from detections, if tracking info exists."""
@@ -771,63 +745,88 @@ class FireSmokeUseCase(BaseProcessor):
771
745
 
772
746
  return len(unique_tracks) if unique_tracks else None
773
747
 
774
- def _get_current_timestamp_str(self, stream_info: Optional[Dict[str, Any]]) -> str:
748
+ def _format_timestamp_for_video(self, timestamp: float) -> str:
749
+ """Format timestamp for video chunks (HH:MM:SS.ms format)."""
750
+ hours = int(timestamp // 3600)
751
+ minutes = int((timestamp % 3600) // 60)
752
+ seconds = round(float(timestamp % 60),2)
753
+ return f"{hours:02d}:{minutes:02d}:{seconds:.1f}"
754
+
755
+ def _get_current_timestamp_str(self, stream_info: Optional[Dict[str, Any]], precision=False, frame_id: Optional[str]=None) -> str:
775
756
  """Get formatted current timestamp based on stream type."""
776
757
  if not stream_info:
777
758
  return "00:00:00.00"
759
+ # is_video_chunk = stream_info.get("input_settings", {}).get("is_video_chunk", False)
760
+ if precision:
761
+ if stream_info.get("input_settings", {}).get("start_frame", "na") != "na":
762
+ if frame_id:
763
+ start_time = int(frame_id)/stream_info.get("input_settings", {}).get("original_fps", 30)
764
+ else:
765
+ start_time = stream_info.get("input_settings", {}).get("start_frame", 30)/stream_info.get("input_settings", {}).get("original_fps", 30)
766
+ stream_time_str = self._format_timestamp_for_video(start_time)
767
+ return stream_time_str
768
+ else:
769
+ return datetime.now(timezone.utc).strftime("%Y-%m-%d-%H:%M:%S.%f UTC")
778
770
 
779
- is_video_chunk = stream_info.get("input_settings", {}).get("is_video_chunk", False)
780
-
781
- # if is_video_chunk:
782
- # video_timestamp = stream_info.get("video_timestamp", 0.0)
783
- # return self._format_timestamp_for_video(video_timestamp)
784
- if stream_info.get("input_settings", {}).get("stream_type", "video_file") == "video_file":
785
- return stream_info.get("video_timestamp", "")[:8]
771
+ if stream_info.get("input_settings", {}).get("start_frame", "na") != "na":
772
+ if frame_id:
773
+ start_time = int(frame_id)/stream_info.get("input_settings", {}).get("original_fps", 30)
774
+ else:
775
+ start_time = stream_info.get("input_settings", {}).get("start_frame", 30)/stream_info.get("input_settings", {}).get("original_fps", 30)
776
+ stream_time_str = self._format_timestamp_for_video(start_time)
777
+ return stream_time_str
786
778
  else:
787
- stream_time_str = stream_info.get("stream_time", "")
779
+ # For streams, use stream_time from stream_info
780
+ stream_time_str = stream_info.get("input_settings", {}).get("stream_info", {}).get("stream_time", "")
788
781
  if stream_time_str:
782
+ # Parse the high precision timestamp string to get timestamp
789
783
  try:
784
+ # Remove " UTC" suffix and parse
790
785
  timestamp_str = stream_time_str.replace(" UTC", "")
791
786
  dt = datetime.strptime(timestamp_str, "%Y-%m-%d-%H:%M:%S.%f")
792
787
  timestamp = dt.replace(tzinfo=timezone.utc).timestamp()
793
788
  return self._format_timestamp_for_stream(timestamp)
794
789
  except:
790
+ # Fallback to current time if parsing fails
795
791
  return self._format_timestamp_for_stream(time.time())
796
792
  else:
797
793
  return self._format_timestamp_for_stream(time.time())
798
794
 
799
- def _get_start_timestamp_str(self, stream_info: Optional[Dict[str, Any]]) -> str:
800
- """Get formatted start timestamp for 'SINCE' block."""
795
+ def _get_start_timestamp_str(self, stream_info: Optional[Dict[str, Any]], precision=False) -> str:
796
+ """Get formatted start timestamp for 'TOTAL SINCE' based on stream type."""
801
797
  if not stream_info:
802
798
  return "00:00:00"
799
+ if precision:
800
+ if stream_info.get("input_settings", {}).get("start_frame", "na") != "na":
801
+ return "00:00:00"
802
+ else:
803
+ return datetime.now(timezone.utc).strftime("%Y-%m-%d-%H:%M:%S.%f UTC")
803
804
 
804
- is_video_chunk = stream_info.get("input_settings", {}).get("is_video_chunk", False)
805
-
806
- if is_video_chunk or stream_info.get("input_settings", {}).get("stream_type", "video_file") == "video_file":
805
+ if stream_info.get("input_settings", {}).get("start_frame", "na") != "na":
806
+ # If video format, start from 00:00:00
807
807
  return "00:00:00"
808
808
  else:
809
+ # For streams, use tracking start time or current time with minutes/seconds reset
809
810
  if self._tracking_start_time is None:
810
- stream_time_str = stream_info.get("stream_time", "")
811
+ # Try to extract timestamp from stream_time string
812
+ stream_time_str = stream_info.get("input_settings", {}).get("stream_info", {}).get("stream_time", "")
811
813
  if stream_time_str:
812
814
  try:
815
+ # Remove " UTC" suffix and parse
813
816
  timestamp_str = stream_time_str.replace(" UTC", "")
814
817
  dt = datetime.strptime(timestamp_str, "%Y-%m-%d-%H:%M:%S.%f")
815
818
  self._tracking_start_time = dt.replace(tzinfo=timezone.utc).timestamp()
816
819
  except:
820
+ # Fallback to current time if parsing fails
817
821
  self._tracking_start_time = time.time()
818
822
  else:
819
823
  self._tracking_start_time = time.time()
820
824
 
821
825
  dt = datetime.fromtimestamp(self._tracking_start_time, tz=timezone.utc)
826
+ # Reset minutes and seconds to 00:00 for "TOTAL SINCE" format
822
827
  dt = dt.replace(minute=0, second=0, microsecond=0)
823
828
  return dt.strftime('%Y:%m:%d %H:%M:%S')
824
829
 
825
- def _format_timestamp_for_video(self, timestamp: float) -> str:
826
- hours = int(timestamp // 3600)
827
- minutes = int((timestamp % 3600) // 60)
828
- seconds = timestamp % 60
829
- return f"{hours:02d}:{minutes:02d}:{seconds:06.2f}"
830
-
831
830
  def _format_timestamp_for_stream(self, timestamp: float) -> str:
832
831
  dt = datetime.fromtimestamp(timestamp, tz=timezone.utc)
833
832
  return dt.strftime('%Y:%m:%d %H:%M:%S')
@@ -60,7 +60,7 @@ class PriceTagUseCase(BaseProcessor):
60
60
  self.category = "retail"
61
61
 
62
62
  self.CASE_TYPE: Optional[str] = 'price_tag_detection'
63
- self.CASE_VERSION: Optional[str] = '1.2'
63
+ self.CASE_VERSION: Optional[str] = '1.3'
64
64
 
65
65
  # List of categories to track
66
66
  self.target_categories = ['pricetag']
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: matrice
3
- Version: 1.0.99147
3
+ Version: 1.0.99149
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
@@ -175,7 +175,7 @@ matrice/deploy/utils/post_processing/usecases/emergency_vehicle_detection.py,sha
175
175
  matrice/deploy/utils/post_processing/usecases/face_emotion.py,sha256=eRfqBdryB0uNoOlz_y-JMuZL1BhPWrI-odqgx_9LT7s,39132
176
176
  matrice/deploy/utils/post_processing/usecases/fashion_detection.py,sha256=f9gpzMDhIW-gyn46k9jgf8nY7YeoqAnTxGOzksabFbE,40457
177
177
  matrice/deploy/utils/post_processing/usecases/field_mapping.py,sha256=JDwYX8pd2W-waDvBh98Y_o_uchJu7wEYbFxOliA4Iq4,39822
178
- matrice/deploy/utils/post_processing/usecases/fire_detection.py,sha256=rLaUvU5ygvjGbOmjncEJCl_Oe52SRycS1Ar23LbRssM,32863
178
+ matrice/deploy/utils/post_processing/usecases/fire_detection.py,sha256=qPR_R-egGaagGirKuJmXIlipI7uPbawWeRxnOERuFSM,38677
179
179
  matrice/deploy/utils/post_processing/usecases/flare_analysis.py,sha256=-egmS3Hs_iGOLeCMfapbkfQ04EWtZx97QRuUcDa-jMU,45340
180
180
  matrice/deploy/utils/post_processing/usecases/flower_segmentation.py,sha256=4I7qMx9Ztxg_hy9KTVX-3qBhAN-QwDt_Yigf9fFjLus,52017
181
181
  matrice/deploy/utils/post_processing/usecases/gender_detection.py,sha256=DEnCTRew6B7DtPcBQVCTtpd_IQMvMusBcu6nadUg2oM,40107
@@ -191,7 +191,7 @@ matrice/deploy/utils/post_processing/usecases/pipeline_detection.py,sha256=VsLTX
191
191
  matrice/deploy/utils/post_processing/usecases/plaque_segmentation_img.py,sha256=d__a0PkkObYVoC-Q5-2bFVfeyKnQHtB5xVAKVOCeFyk,41925
192
192
  matrice/deploy/utils/post_processing/usecases/pothole_segmentation.py,sha256=6Mv8SoEE5CGItY7S0g-SY5Lb3DV-WWVMlpEp04a86a8,43197
193
193
  matrice/deploy/utils/post_processing/usecases/ppe_compliance.py,sha256=G9P9j9E9nfNJInHJxmK1Lb4daFBlG5hq0aqotTLvFFE,30146
194
- matrice/deploy/utils/post_processing/usecases/price_tag_detection.py,sha256=Sn_Dvwf5f_dcfaiPIl-pqckgP8z96CeNIJ4hfeab3FM,39880
194
+ matrice/deploy/utils/post_processing/usecases/price_tag_detection.py,sha256=09Tp6MGAHh95s-NSAp-4WC9iCc20sajWApuUBAvgXiQ,39880
195
195
  matrice/deploy/utils/post_processing/usecases/road_lane_detection.py,sha256=V_KxwBtAHSNkyoH8sXw-U-P3J8ToXtX3ncc69gn6Tds,31591
196
196
  matrice/deploy/utils/post_processing/usecases/shelf_inventory_detection.py,sha256=1juloltHnCj3U499Aps0ggE0nEI37x3iKe4DgfP4RCw,29140
197
197
  matrice/deploy/utils/post_processing/usecases/shoplifting_detection.py,sha256=zqeV_ARV5gJqMY2sJGBjlU6UOb0SthGGbC8UNj_mycs,34701
@@ -227,8 +227,8 @@ matrice/deployment/camera_manager.py,sha256=ReBZqm1CNXRImKcbcZ4uWAT3TUWkof1D28oB
227
227
  matrice/deployment/deployment.py,sha256=PLIUD-PxTaC2Zxb3Y12wUddsryV-OJetjCjLoSUh7S4,48103
228
228
  matrice/deployment/inference_pipeline.py,sha256=bXLgd29ViA7o0c7YWLFJl1otBUQfTPb61jS6VawQB0Y,37918
229
229
  matrice/deployment/streaming_gateway_manager.py,sha256=w5swGsuFVfZIdOm2ZuBHRHlRdYYJMLopLsf2gb91lQ8,20946
230
- matrice-1.0.99147.dist-info/licenses/LICENSE.txt,sha256=2bm9uFabQZ3Ykb_SaSU_uUbAj2-htc6WJQmS_65qD00,1073
231
- matrice-1.0.99147.dist-info/METADATA,sha256=SDF7hYFBsp9aMowGaQXXdCHIf_GsPKo2wC-PCfgLP3k,14624
232
- matrice-1.0.99147.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
233
- matrice-1.0.99147.dist-info/top_level.txt,sha256=P97js8ur6o5ClRqMH3Cjoab_NqbJ6sOQ3rJmVzKBvMc,8
234
- matrice-1.0.99147.dist-info/RECORD,,
230
+ matrice-1.0.99149.dist-info/licenses/LICENSE.txt,sha256=2bm9uFabQZ3Ykb_SaSU_uUbAj2-htc6WJQmS_65qD00,1073
231
+ matrice-1.0.99149.dist-info/METADATA,sha256=CqQqn043fZ9ylX5kYcp1esu9VLKuOZDOK58BJ77lxTY,14624
232
+ matrice-1.0.99149.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
233
+ matrice-1.0.99149.dist-info/top_level.txt,sha256=P97js8ur6o5ClRqMH3Cjoab_NqbJ6sOQ3rJmVzKBvMc,8
234
+ matrice-1.0.99149.dist-info/RECORD,,