RavindranadhM's picture
Deploy manufacturing monitoring system
201b13c verified
Raw
History Blame Contribute Delete
3.07 kB
from typing import Dict, List, Optional
class DefectLifecycleManager:
"""
Tracks lifecycle of defects across frames.
A defect is:
- CREATED when first detected
- UPDATED when seen again
- FINALIZED when it disappears for a threshold
"""
def __init__(self, max_missing_frames: int = 5, match_threshold: int = 50):
self.active_defects: Dict[int, Dict] = {}
self.next_id: int = 0
self.max_missing_frames = max_missing_frames
self.match_threshold = match_threshold
def _is_match(self, bbox1, bbox2) -> bool:
"""Check if two bounding boxes belong to same defect."""
x1, y1, _, _ = bbox1
x2, y2, _, _ = bbox2
return (
abs(x1 - x2) < self.match_threshold and
abs(y1 - y2) < self.match_threshold
)
def _find_match(self, detection: Dict) -> Optional[int]:
"""Find matching defect ID for a detection."""
for defect_id, data in self.active_defects.items():
if self._is_match(detection["bbox"], data["bbox"]):
return defect_id
return None
def update(self, detections: List[Dict], frame_id: int) -> List[Dict]:
"""
Update lifecycle with new detections.
Args:
detections: List of processed defects
frame_id: Current frame number
Returns:
List of finalized defects
"""
finalized: List[Dict] = []
# Step 1: Mark all as unseen
for defect in self.active_defects.values():
defect["seen"] = False
# Step 2: Match detections
for d in detections:
matched_id = self._find_match(d)
if matched_id is not None:
data = self.active_defects[matched_id]
data["bbox"] = d["bbox"]
data["last_seen"] = frame_id
data["frames_seen"] += 1
data["seen"] = True
# Update max severity
if d["severity_score"] > data["max_severity"]:
data["max_severity"] = d["severity_score"]
data["final_defect"] = d
else:
# Create new defect
self.active_defects[self.next_id] = {
"bbox": d["bbox"],
"last_seen": frame_id,
"frames_seen": 1,
"max_severity": d.get("severity_score", 0),
"final_defect": d,
"seen": True
}
self.next_id += 1
# Step 3: Finalize disappeared defects
to_delete = []
for defect_id, data in self.active_defects.items():
if not data["seen"]:
if frame_id - data["last_seen"] > self.max_missing_frames:
finalized.append(data["final_defect"])
to_delete.append(defect_id)
# Step 4: Cleanup
for defect_id in to_delete:
del self.active_defects[defect_id]
return finalized