Enhance alert display and processing in camera stream
- Implemented live overlays to indicate alerting groups and their details. - Updated person box annotations to reflect alert status with color coding. - Improved saving of annotated alerts by including group-specific information and unique filenames. - Added visual indicators for alert groups, including group size and duration.main
parent
50ecbdcc50
commit
a1da64e017
|
|
@ -270,12 +270,34 @@ def _process_stream():
|
||||||
# --- Draw overlays ---
|
# --- Draw overlays ---
|
||||||
display = frame.copy()
|
display = frame.copy()
|
||||||
|
|
||||||
for x1, y1, x2, y2, conf in person_boxes:
|
pending_gid_set = {gid for gid, _, _ in pending_alerts}
|
||||||
cv2.rectangle(display, (int(x1), int(y1)), (int(x2), int(y2)), (0, 255, 0), 2)
|
alert_person_indices = set()
|
||||||
|
for gid, grp_indices, _gc in frame_group_data:
|
||||||
|
if gid in pending_gid_set:
|
||||||
|
alert_person_indices.update(grp_indices)
|
||||||
|
|
||||||
|
# Live overlay: mark any person that belongs to any alerting group.
|
||||||
|
if pending_alerts:
|
||||||
|
max_people = max(people for _gid, people, _dur in pending_alerts)
|
||||||
|
max_dur = max(dur for _gid, _people, dur in pending_alerts)
|
||||||
|
cv2.putText(
|
||||||
|
display,
|
||||||
|
f"ALERT: {len(pending_alerts)} group(s) | {max_people} people | {int(max_dur)}s",
|
||||||
|
(12, 32),
|
||||||
|
cv2.FONT_HERSHEY_SIMPLEX,
|
||||||
|
0.8,
|
||||||
|
(0, 0, 255),
|
||||||
|
3,
|
||||||
|
)
|
||||||
|
|
||||||
|
for idx, (x1, y1, x2, y2, conf) in enumerate(person_boxes):
|
||||||
|
is_alert_person = idx in alert_person_indices
|
||||||
|
box_color = (0, 0, 255) if is_alert_person else (0, 255, 0)
|
||||||
|
cv2.rectangle(display, (int(x1), int(y1)), (int(x2), int(y2)), box_color, 2)
|
||||||
cv2.putText(
|
cv2.putText(
|
||||||
display, f"{conf:.0%}",
|
display, f"{conf:.0%}",
|
||||||
(int(x1), int(y1) - 6),
|
(int(x1), int(y1) - 6),
|
||||||
cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 2,
|
cv2.FONT_HERSHEY_SIMPLEX, 0.5, box_color, 2,
|
||||||
)
|
)
|
||||||
|
|
||||||
for gid, grp_indices, gc in frame_group_data:
|
for gid, grp_indices, gc in frame_group_data:
|
||||||
|
|
@ -301,14 +323,72 @@ def _process_stream():
|
||||||
cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 0, 255), 3,
|
cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 0, 255), 3,
|
||||||
)
|
)
|
||||||
|
|
||||||
# --- Save annotated alerts ---
|
# --- Save annotated alerts (separate per group) ---
|
||||||
if pending_alerts:
|
if pending_alerts:
|
||||||
os.makedirs("alerts", exist_ok=True)
|
os.makedirs("alerts", exist_ok=True)
|
||||||
ts = datetime.now().strftime("%Y%m%d_%H%M%S")
|
ts = datetime.now().strftime("%Y%m%d_%H%M%S")
|
||||||
|
|
||||||
|
frame_group_by_id = {gid: (grp_indices, gc) for gid, grp_indices, gc in frame_group_data}
|
||||||
|
|
||||||
for gid, people, duration in pending_alerts:
|
for gid, people, duration in pending_alerts:
|
||||||
|
grp_indices, gc = frame_group_by_id.get(gid, (None, None))
|
||||||
|
if grp_indices is None:
|
||||||
|
continue
|
||||||
|
|
||||||
|
alert_display = frame.copy()
|
||||||
|
alert_person_set = set(grp_indices)
|
||||||
|
|
||||||
|
# Header annotation for this specific alert group.
|
||||||
|
cv2.putText(
|
||||||
|
alert_display,
|
||||||
|
f"ALERT GROUP {gid} | {people} people | {int(duration)}s",
|
||||||
|
(12, 32),
|
||||||
|
cv2.FONT_HERSHEY_SIMPLEX,
|
||||||
|
0.9,
|
||||||
|
(0, 0, 255),
|
||||||
|
3,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Draw only the person boxes relevant to this group.
|
||||||
|
for idx, (x1, y1, x2, y2, conf) in enumerate(person_boxes):
|
||||||
|
is_alert_person = idx in alert_person_set
|
||||||
|
box_color = (0, 0, 255) if is_alert_person else (0, 255, 0)
|
||||||
|
cv2.rectangle(alert_display, (int(x1), int(y1)), (int(x2), int(y2)), box_color, 2)
|
||||||
|
cv2.putText(
|
||||||
|
alert_display,
|
||||||
|
f"{conf:.0%}",
|
||||||
|
(int(x1), int(y1) - 6),
|
||||||
|
cv2.FONT_HERSHEY_SIMPLEX,
|
||||||
|
0.5,
|
||||||
|
box_color,
|
||||||
|
2,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Draw only the circle/label for this group.
|
||||||
|
radius = int(PROXIMITY_PX * 0.6)
|
||||||
|
cv2.circle(alert_display, (int(gc[0]), int(gc[1])), radius, (0, 0, 255), 2)
|
||||||
|
cv2.putText(
|
||||||
|
alert_display,
|
||||||
|
f"Group: {len(grp_indices)} | {duration:.0f}s",
|
||||||
|
(int(gc[0]) - 70, int(gc[1]) - radius - 10),
|
||||||
|
cv2.FONT_HERSHEY_SIMPLEX,
|
||||||
|
0.55,
|
||||||
|
(0, 0, 255),
|
||||||
|
2,
|
||||||
|
)
|
||||||
|
cv2.putText(
|
||||||
|
alert_display,
|
||||||
|
"ALERT",
|
||||||
|
(int(gc[0]) - 35, int(gc[1]) + radius + 25),
|
||||||
|
cv2.FONT_HERSHEY_SIMPLEX,
|
||||||
|
0.8,
|
||||||
|
(0, 0, 255),
|
||||||
|
3,
|
||||||
|
)
|
||||||
|
|
||||||
# Include group id to avoid collisions when multiple groups alert in one second.
|
# Include group id to avoid collisions when multiple groups alert in one second.
|
||||||
alert_path = f"alerts/alert_{ts}_gid{gid}.jpg"
|
alert_path = f"alerts/alert_{ts}_gid{gid}.jpg"
|
||||||
cv2.imwrite(alert_path, display)
|
cv2.imwrite(alert_path, alert_display)
|
||||||
|
|
||||||
alert_info = {
|
alert_info = {
|
||||||
"time": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
|
"time": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue