matrice 1.0.99139__py3-none-any.whl → 1.0.99141__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/usecases/concrete_crack_detection.py +60 -61
- {matrice-1.0.99139.dist-info → matrice-1.0.99141.dist-info}/METADATA +1 -1
- {matrice-1.0.99139.dist-info → matrice-1.0.99141.dist-info}/RECORD +6 -6
- {matrice-1.0.99139.dist-info → matrice-1.0.99141.dist-info}/WHEEL +0 -0
- {matrice-1.0.99139.dist-info → matrice-1.0.99141.dist-info}/licenses/LICENSE.txt +0 -0
- {matrice-1.0.99139.dist-info → matrice-1.0.99141.dist-info}/top_level.txt +0 -0
@@ -22,7 +22,7 @@ from ..core.config import BaseConfig, AlertConfig, ZoneConfig
|
|
22
22
|
|
23
23
|
@dataclass
|
24
24
|
class ConcreteCrackConfig(BaseConfig):
|
25
|
-
"""Configuration for
|
25
|
+
"""Configuration for Concrete Crack detection use case."""
|
26
26
|
# Smoothing configuration
|
27
27
|
enable_smoothing: bool = True
|
28
28
|
smoothing_algorithm: str = "observability" # "window" or "observability"
|
@@ -31,14 +31,14 @@ class ConcreteCrackConfig(BaseConfig):
|
|
31
31
|
smoothing_confidence_range_factor: float = 0.5
|
32
32
|
|
33
33
|
#confidence thresholds
|
34
|
-
confidence_threshold: float = 0.
|
34
|
+
confidence_threshold: float = 0.6
|
35
35
|
|
36
36
|
usecase_categories: List[str] = field(
|
37
|
-
default_factory=lambda:
|
37
|
+
default_factory=lambda: ["Cracks"]
|
38
38
|
)
|
39
39
|
|
40
40
|
target_categories: List[str] = field(
|
41
|
-
default_factory=lambda: [
|
41
|
+
default_factory=lambda: ["Cracks"]
|
42
42
|
)
|
43
43
|
|
44
44
|
alert_config: Optional[AlertConfig] = None
|
@@ -55,23 +55,23 @@ class ConcreteCrackUseCase(BaseProcessor):
|
|
55
55
|
CATEGORY_DISPLAY = {
|
56
56
|
"Cracks": "Cracks",
|
57
57
|
}
|
58
|
-
|
58
|
+
|
59
|
+
|
59
60
|
def __init__(self):
|
60
61
|
super().__init__("concrete_crack_detection")
|
61
62
|
self.category = "general"
|
62
63
|
|
63
64
|
self.CASE_TYPE: Optional[str] = 'concrete_crack_detection'
|
64
|
-
self.CASE_VERSION: Optional[str] = '1.
|
65
|
-
|
65
|
+
self.CASE_VERSION: Optional[str] = '1.2'
|
66
66
|
# List of categories to track
|
67
|
-
self.target_categories =
|
67
|
+
self.target_categories = ["Cracks"]
|
68
|
+
|
68
69
|
|
69
70
|
# Initialize smoothing tracker
|
70
71
|
self.smoothing_tracker = None
|
71
72
|
|
72
73
|
# Initialize advanced tracker (will be created on first use)
|
73
74
|
self.tracker = None
|
74
|
-
|
75
75
|
# Initialize tracking state variables
|
76
76
|
self._total_frame_counter = 0
|
77
77
|
self._global_frame_offset = 0
|
@@ -88,6 +88,7 @@ class ConcreteCrackUseCase(BaseProcessor):
|
|
88
88
|
self._ascending_alert_list: List[int] = []
|
89
89
|
self.current_incident_end_timestamp: str = "N/A"
|
90
90
|
|
91
|
+
|
91
92
|
def process(self, data: Any, config: ConfigProtocol, context: Optional[ProcessingContext] = None,
|
92
93
|
stream_info: Optional[Dict[str, Any]] = None) -> ProcessingResult:
|
93
94
|
"""
|
@@ -107,8 +108,6 @@ class ConcreteCrackUseCase(BaseProcessor):
|
|
107
108
|
input_format = match_results_structure(data)
|
108
109
|
context.input_format = input_format
|
109
110
|
context.confidence_threshold = config.confidence_threshold
|
110
|
-
|
111
|
-
|
112
111
|
|
113
112
|
if config.confidence_threshold is not None:
|
114
113
|
processed_data = filter_by_confidence(data, config.confidence_threshold)
|
@@ -117,19 +116,15 @@ class ConcreteCrackUseCase(BaseProcessor):
|
|
117
116
|
processed_data = data
|
118
117
|
|
119
118
|
self.logger.debug(f"Did not apply confidence filtering with threshold since nothing was provided")
|
120
|
-
|
121
|
-
print(processed_data)
|
119
|
+
|
122
120
|
# Step 2: Apply category mapping if provided
|
123
121
|
if config.index_to_category:
|
124
122
|
processed_data = apply_category_mapping(processed_data, config.index_to_category)
|
125
123
|
self.logger.debug("Applied category mapping")
|
126
|
-
|
127
|
-
print(processed_data)
|
124
|
+
|
128
125
|
if config.target_categories:
|
129
126
|
processed_data = [d for d in processed_data if d.get('category') in self.target_categories]
|
130
127
|
self.logger.debug(f"Applied category filtering")
|
131
|
-
print("---------------------processed_3-----------------------------------")
|
132
|
-
print(processed_data)
|
133
128
|
|
134
129
|
# Apply bbox smoothing if enabled
|
135
130
|
if config.enable_smoothing:
|
@@ -143,9 +138,8 @@ class ConcreteCrackUseCase(BaseProcessor):
|
|
143
138
|
enable_smoothing=True
|
144
139
|
)
|
145
140
|
self.smoothing_tracker = BBoxSmoothingTracker(smoothing_config)
|
146
|
-
print("---------------------processed_4-----------------------------------")
|
147
141
|
processed_data = bbox_smoothing(processed_data, self.smoothing_tracker.config, self.smoothing_tracker)
|
148
|
-
|
142
|
+
|
149
143
|
# Advanced tracking (BYTETracker-like)
|
150
144
|
try:
|
151
145
|
from ..advanced_tracker import AdvancedTracker
|
@@ -153,15 +147,29 @@ class ConcreteCrackUseCase(BaseProcessor):
|
|
153
147
|
|
154
148
|
# Create tracker instance if it doesn't exist (preserves state across frames)
|
155
149
|
if self.tracker is None:
|
156
|
-
|
150
|
+
# Configure tracker thresholds based on the use-case confidence threshold so that
|
151
|
+
# low-confidence detections (e.g. < 0.7) can still be initialised as tracks when
|
152
|
+
# the user passes a lower `confidence_threshold` in the post-processing config.
|
153
|
+
if config.confidence_threshold is not None:
|
154
|
+
tracker_config = TrackerConfig(
|
155
|
+
track_high_thresh=float(config.confidence_threshold),
|
156
|
+
# Allow even lower detections to participate in secondary association
|
157
|
+
track_low_thresh=max(0.05, float(config.confidence_threshold) / 2),
|
158
|
+
new_track_thresh=float(config.confidence_threshold)
|
159
|
+
)
|
160
|
+
else:
|
161
|
+
tracker_config = TrackerConfig()
|
157
162
|
self.tracker = AdvancedTracker(tracker_config)
|
158
|
-
self.logger.info(
|
163
|
+
self.logger.info(
|
164
|
+
"Initialized AdvancedTracker for Monitoring and tracking with thresholds: "
|
165
|
+
f"high={tracker_config.track_high_thresh}, "
|
166
|
+
f"low={tracker_config.track_low_thresh}, "
|
167
|
+
f"new={tracker_config.new_track_thresh}"
|
168
|
+
)
|
159
169
|
|
160
170
|
# The tracker expects the data in the same format as input
|
161
171
|
# It will add track_id and frame_id to each detection
|
162
172
|
processed_data = self.tracker.update(processed_data)
|
163
|
-
print("---------------------processed_4-----------------------------------")
|
164
|
-
print(processed_data)
|
165
173
|
|
166
174
|
except Exception as e:
|
167
175
|
# If advanced tracker fails, fallback to unsmoothed detections
|
@@ -189,16 +197,14 @@ class ConcreteCrackUseCase(BaseProcessor):
|
|
189
197
|
# Add total unique counts after tracking using only local state
|
190
198
|
total_counts = self.get_total_counts()
|
191
199
|
counting_summary['total_counts'] = total_counts
|
192
|
-
|
193
|
-
print(counting_summary)
|
200
|
+
|
194
201
|
alerts = self._check_alerts(counting_summary, frame_number, config)
|
195
202
|
predictions = self._extract_predictions(processed_data)
|
196
203
|
|
197
204
|
# Step: Generate structured incidents, tracking stats and business analytics with frame-based keys
|
198
205
|
incidents_list = self._generate_incidents(counting_summary, alerts, config, frame_number, stream_info)
|
199
206
|
tracking_stats_list = self._generate_tracking_stats(counting_summary, alerts, config, frame_number, stream_info)
|
200
|
-
|
201
|
-
business_analytics_list = []
|
207
|
+
business_analytics_list = self._generate_business_analytics(counting_summary, alerts, config, stream_info, is_empty=True)
|
202
208
|
summary_list = self._generate_summary(counting_summary, incidents_list, tracking_stats_list, business_analytics_list, alerts)
|
203
209
|
|
204
210
|
# Extract frame-based dictionaries from the lists
|
@@ -213,8 +219,8 @@ class ConcreteCrackUseCase(BaseProcessor):
|
|
213
219
|
"alerts": alerts,
|
214
220
|
"human_text": summary}
|
215
221
|
}
|
216
|
-
|
217
|
-
|
222
|
+
|
223
|
+
|
218
224
|
context.mark_completed()
|
219
225
|
|
220
226
|
# Build result object following the new pattern
|
@@ -276,8 +282,8 @@ class ConcreteCrackUseCase(BaseProcessor):
|
|
276
282
|
"threshold_level": threshold,
|
277
283
|
"ascending": get_trend(self._ascending_alert_list, lookback=900, threshold=0.8),
|
278
284
|
"settings": {t: v for t, v in zip(getattr(config.alert_config, 'alert_type', ['Default']) if hasattr(config.alert_config, 'alert_type') else ['Default'],
|
279
|
-
|
280
|
-
|
285
|
+
getattr(config.alert_config, 'alert_value', ['JSON']) if hasattr(config.alert_config, 'alert_value') else ['JSON'])
|
286
|
+
}
|
281
287
|
})
|
282
288
|
elif category in summary.get("per_category_count", {}):
|
283
289
|
count = summary.get("per_category_count", {})[category]
|
@@ -289,15 +295,15 @@ class ConcreteCrackUseCase(BaseProcessor):
|
|
289
295
|
"threshold_level": threshold,
|
290
296
|
"ascending": get_trend(self._ascending_alert_list, lookback=900, threshold=0.8),
|
291
297
|
"settings": {t: v for t, v in zip(getattr(config.alert_config, 'alert_type', ['Default']) if hasattr(config.alert_config, 'alert_type') else ['Default'],
|
292
|
-
|
293
|
-
|
298
|
+
getattr(config.alert_config, 'alert_value', ['JSON']) if hasattr(config.alert_config, 'alert_value') else ['JSON'])
|
299
|
+
}
|
294
300
|
})
|
295
301
|
else:
|
296
302
|
pass
|
297
303
|
return alerts
|
298
304
|
|
299
305
|
def _generate_incidents(self, counting_summary: Dict, alerts: List, config: ConcreteCrackConfig,
|
300
|
-
|
306
|
+
frame_number: Optional[int] = None, stream_info: Optional[Dict[str, Any]] = None) -> List[
|
301
307
|
Dict]:
|
302
308
|
"""Generate structured incidents for the output format with frame-based keys."""
|
303
309
|
|
@@ -355,12 +361,12 @@ class ConcreteCrackUseCase(BaseProcessor):
|
|
355
361
|
intensity = min(10.0, total_detections / 3.0)
|
356
362
|
self._ascending_alert_list.append(0)
|
357
363
|
|
358
|
-
|
364
|
+
# Generate human text in new format
|
359
365
|
human_text_lines = [f"INCIDENTS DETECTED @ {current_timestamp}:"]
|
360
366
|
human_text_lines.append(f"\tSeverity Level: {(self.CASE_TYPE,level)}")
|
361
367
|
human_text = "\n".join(human_text_lines)
|
362
368
|
|
363
|
-
alert_settings
|
369
|
+
alert_settings=[]
|
364
370
|
if config.alert_config and hasattr(config.alert_config, 'alert_type'):
|
365
371
|
alert_settings.append({
|
366
372
|
"alert_type": getattr(config.alert_config, 'alert_type', ['Default']) if hasattr(config.alert_config, 'alert_type') else ['Default'],
|
@@ -373,17 +379,16 @@ class ConcreteCrackUseCase(BaseProcessor):
|
|
373
379
|
})
|
374
380
|
|
375
381
|
event= self.create_incident(incident_id=self.CASE_TYPE+'_'+str(frame_number), incident_type=self.CASE_TYPE,
|
376
|
-
|
377
|
-
|
378
|
-
|
382
|
+
severity_level=level, human_text=human_text, camera_info=camera_info, alerts=alerts, alert_settings=alert_settings,
|
383
|
+
start_time=start_timestamp, end_time=self.current_incident_end_timestamp,
|
384
|
+
level_settings= {"low": 1, "medium": 3, "significant":4, "critical": 7})
|
379
385
|
incidents.append(event)
|
380
386
|
|
381
387
|
else:
|
382
388
|
self._ascending_alert_list.append(0)
|
383
389
|
incidents.append({})
|
384
|
-
|
390
|
+
|
385
391
|
return incidents
|
386
|
-
|
387
392
|
def _generate_tracking_stats(
|
388
393
|
self,
|
389
394
|
counting_summary: Dict,
|
@@ -421,8 +426,7 @@ class ConcreteCrackUseCase(BaseProcessor):
|
|
421
426
|
"category": cat,
|
422
427
|
"count": count
|
423
428
|
})
|
424
|
-
|
425
|
-
print(total_counts)
|
429
|
+
|
426
430
|
# Build current_counts array in expected format
|
427
431
|
current_counts = []
|
428
432
|
for cat, count in per_category_count.items():
|
@@ -431,8 +435,7 @@ class ConcreteCrackUseCase(BaseProcessor):
|
|
431
435
|
"category": cat,
|
432
436
|
"count": count
|
433
437
|
})
|
434
|
-
|
435
|
-
print(current_counts)
|
438
|
+
|
436
439
|
# Prepare detections without confidence scores (as per eg.json)
|
437
440
|
detections = []
|
438
441
|
for detection in counting_summary.get("detections", []):
|
@@ -484,9 +487,7 @@ class ConcreteCrackUseCase(BaseProcessor):
|
|
484
487
|
human_text_lines.append("Alerts: None")
|
485
488
|
|
486
489
|
human_text = "\n".join(human_text_lines)
|
487
|
-
|
488
|
-
print(human_text)
|
489
|
-
reset_settings = [
|
490
|
+
reset_settings=[
|
490
491
|
{
|
491
492
|
"interval_type": "daily",
|
492
493
|
"reset_time": {
|
@@ -497,14 +498,14 @@ class ConcreteCrackUseCase(BaseProcessor):
|
|
497
498
|
]
|
498
499
|
|
499
500
|
tracking_stat=self.create_tracking_stats(total_counts=total_counts, current_counts=current_counts,
|
500
|
-
|
501
|
-
|
502
|
-
|
501
|
+
detections=detections, human_text=human_text, camera_info=camera_info, alerts=alerts, alert_settings=alert_settings,
|
502
|
+
reset_settings=reset_settings, start_time=high_precision_start_timestamp ,
|
503
|
+
reset_time=high_precision_reset_timestamp)
|
503
504
|
|
504
505
|
tracking_stats.append(tracking_stat)
|
505
506
|
return tracking_stats
|
506
507
|
|
507
|
-
def _generate_business_analytics(self, counting_summary: Dict,
|
508
|
+
def _generate_business_analytics(self, counting_summary: Dict, alerts:Any, config: ConcreteCrackConfig, stream_info: Optional[Dict[str, Any]] = None, is_empty=False) -> List[Dict]:
|
508
509
|
"""Generate standardized business analytics for the agg_summary structure."""
|
509
510
|
if is_empty:
|
510
511
|
return []
|
@@ -587,6 +588,12 @@ class ConcreteCrackUseCase(BaseProcessor):
|
|
587
588
|
Return total unique track_id count for each category.
|
588
589
|
"""
|
589
590
|
return {cat: len(ids) for cat, ids in getattr(self, '_per_category_total_track_ids', {}).items()}
|
591
|
+
|
592
|
+
|
593
|
+
def _format_timestamp_for_stream(self, timestamp: float) -> str:
|
594
|
+
"""Format timestamp for streams (YYYY:MM:DD HH:MM:SS format)."""
|
595
|
+
dt = datetime.fromtimestamp(timestamp, tz=timezone.utc)
|
596
|
+
return dt.strftime('%Y:%m:%d %H:%M:%S')
|
590
597
|
|
591
598
|
def _format_timestamp_for_video(self, timestamp: float) -> str:
|
592
599
|
"""Format timestamp for video chunks (HH:MM:SS.ms format)."""
|
@@ -595,11 +602,6 @@ class ConcreteCrackUseCase(BaseProcessor):
|
|
595
602
|
seconds = round(float(timestamp % 60),2)
|
596
603
|
return f"{hours:02d}:{minutes:02d}:{seconds:.1f}"
|
597
604
|
|
598
|
-
def _format_timestamp_for_stream(self, timestamp: float) -> str:
|
599
|
-
"""Format timestamp for streams (YYYY:MM:DD HH:MM:SS format)."""
|
600
|
-
dt = datetime.fromtimestamp(timestamp, tz=timezone.utc)
|
601
|
-
return dt.strftime('%Y:%m:%d %H:%M:%S')
|
602
|
-
|
603
605
|
def _get_current_timestamp_str(self, stream_info: Optional[Dict[str, Any]], precision=False, frame_id: Optional[str]=None) -> str:
|
604
606
|
"""Get formatted current timestamp based on stream type."""
|
605
607
|
if not stream_info:
|
@@ -675,6 +677,7 @@ class ConcreteCrackUseCase(BaseProcessor):
|
|
675
677
|
dt = dt.replace(minute=0, second=0, microsecond=0)
|
676
678
|
return dt.strftime('%Y:%m:%d %H:%M:%S')
|
677
679
|
|
680
|
+
|
678
681
|
def _count_categories(self, detections: list, config: ConcreteCrackConfig) -> dict:
|
679
682
|
"""
|
680
683
|
Count the number of detections per category and return a summary dict.
|
@@ -686,10 +689,6 @@ class ConcreteCrackUseCase(BaseProcessor):
|
|
686
689
|
cat = det.get('category', 'unknown')
|
687
690
|
counts[cat] = counts.get(cat, 0) + 1
|
688
691
|
# Each detection dict will now include 'track_id' (and possibly 'frame_id')
|
689
|
-
print("---------------------------------COUNTS-------------------------------------")
|
690
|
-
print(counts)
|
691
|
-
print("---------------------------------Detections-------------------------------------")
|
692
|
-
print(detections)
|
693
692
|
return {
|
694
693
|
"total_count": sum(counts.values()),
|
695
694
|
"per_category_count": counts,
|
@@ -166,7 +166,7 @@ matrice/deploy/utils/post_processing/usecases/chicken_pose_detection.py,sha256=-
|
|
166
166
|
matrice/deploy/utils/post_processing/usecases/child_monitoring.py,sha256=z3oymoqq4hDGwA8MkdEONZW_Vx5CAZmvzZaNLsqmCfw,39380
|
167
167
|
matrice/deploy/utils/post_processing/usecases/color_detection.py,sha256=Z8-akjy8a7f8YyiOzXu_Zi1Km30v-TRrymDqQOPpJ_8,43277
|
168
168
|
matrice/deploy/utils/post_processing/usecases/color_map_utils.py,sha256=SP-AEVcjLmL8rxblu-ixqUJC2fqlcr7ab4hWo4Fcr_k,2677
|
169
|
-
matrice/deploy/utils/post_processing/usecases/concrete_crack_detection.py,sha256=
|
169
|
+
matrice/deploy/utils/post_processing/usecases/concrete_crack_detection.py,sha256=pxhOH_hG4hq9yytNepbGMdk2W_lTG8D1_2RAagaPBkg,40252
|
170
170
|
matrice/deploy/utils/post_processing/usecases/crop_weed_detection.py,sha256=i7BWhC-D7liOg9fzFHFg_upd1fdvXlVHYzDRyHL-AdM,40322
|
171
171
|
matrice/deploy/utils/post_processing/usecases/customer_service.py,sha256=UWS83qxguyAyhh8a0JF5QH9DtKxO8I-gI2BPOjLPxBw,44642
|
172
172
|
matrice/deploy/utils/post_processing/usecases/defect_detection_products.py,sha256=flvTWv6vxa3q4zXD8_e8TW0pqNE5z3LIuvU9ceVKuXg,34481
|
@@ -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.
|
229
|
-
matrice-1.0.
|
230
|
-
matrice-1.0.
|
231
|
-
matrice-1.0.
|
232
|
-
matrice-1.0.
|
228
|
+
matrice-1.0.99141.dist-info/licenses/LICENSE.txt,sha256=2bm9uFabQZ3Ykb_SaSU_uUbAj2-htc6WJQmS_65qD00,1073
|
229
|
+
matrice-1.0.99141.dist-info/METADATA,sha256=7aK3PJ9ODjlD7ASl79Bf8RxjOtZd474MsY2WvUoBAlA,14624
|
230
|
+
matrice-1.0.99141.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
231
|
+
matrice-1.0.99141.dist-info/top_level.txt,sha256=P97js8ur6o5ClRqMH3Cjoab_NqbJ6sOQ3rJmVzKBvMc,8
|
232
|
+
matrice-1.0.99141.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|