61 lines
3.0 KiB
Python
61 lines
3.0 KiB
Python
"""Burning the counting overlay into the frame, as an MJPEG.
|
|
|
|
Split out of `live_count.py` to keep it inside the 400-line limit. This is the
|
|
fallback preview, used for archive files; a WebRTC session draws the same
|
|
geometry on a canvas in the browser instead (REQ-177).
|
|
"""
|
|
|
|
import cv2
|
|
|
|
|
|
def render(session, frame, detections, ignored, counter):
|
|
height, width = frame.shape[:2]
|
|
|
|
# Shade what the region excludes. Without this the neighbouring truck's
|
|
# sacks simply vanish from the overlay, and "are they being ignored?"
|
|
# looks identical to "is the model missing them?".
|
|
if session.line_x_start > 0 or session.line_x_end < width:
|
|
shade = frame.copy()
|
|
if session.line_x_start > 0:
|
|
cv2.rectangle(shade, (0, 0), (session.line_x_start, height), (0, 0, 0), -1)
|
|
if session.line_x_end < width:
|
|
cv2.rectangle(shade, (session.line_x_end, 0), (width, height), (0, 0, 0), -1)
|
|
cv2.addWeighted(shade, 0.55, frame, 0.45, 0, frame)
|
|
|
|
# Ignored detections stay visible, in grey, so the region can be judged.
|
|
for det in ignored:
|
|
x1, y1, x2, y2 = (int(v) for v in det.bbox)
|
|
cv2.rectangle(frame, (x1, y1), (x2, y2), (130, 130, 130), 1)
|
|
|
|
for edge in (session.line_x_start, session.line_x_end):
|
|
if 0 < edge < width:
|
|
cv2.line(frame, (edge, 0), (edge, height), (255, 0, 255), 2)
|
|
cv2.putText(frame, "IGNORED", (max(4, session.line_x_start - 92), height - 14),
|
|
cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 0, 255), 1, cv2.LINE_AA)
|
|
cv2.putText(frame, "IGNORED", (min(width - 88, session.line_x_end + 8), height - 14),
|
|
cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 0, 255), 1, cv2.LINE_AA)
|
|
|
|
for det in detections:
|
|
x1, y1, x2, y2 = (int(v) for v in det.bbox)
|
|
counted = bool(counter.counted_tracks.get(det.track_id))
|
|
colour = (74, 222, 128) if counted else (248, 191, 113)
|
|
cv2.rectangle(frame, (x1, y1), (x2, y2), colour, 2)
|
|
cv2.putText(frame, f"#{det.track_id} {det.confidence:.2f}", (x1, max(14, y1 - 6)),
|
|
cv2.FONT_HERSHEY_SIMPLEX, 0.45, colour, 1, cv2.LINE_AA)
|
|
|
|
cv2.line(frame, (session.line_x_start, session.line_y), (session.line_x_end, session.line_y),
|
|
(0, 255, 255), 2)
|
|
for edge in (session.line_y - session.margin, session.line_y + session.margin):
|
|
cv2.line(frame, (session.line_x_start, edge), (session.line_x_end, edge),
|
|
(0, 160, 160), 1)
|
|
|
|
panel = f"IN {session.loading} OUT {session.unloading} NET {session.loading - session.unloading}"
|
|
cv2.rectangle(frame, (12, 12), (12 + 9 * len(panel) + 20, 84), (0, 0, 0), -1)
|
|
cv2.putText(frame, panel, (24, 46), cv2.FONT_HERSHEY_SIMPLEX, 0.8,
|
|
(74, 222, 128), 2, cv2.LINE_AA)
|
|
cv2.putText(frame, f"{session.fps:.1f} fps {session.tracked} tracked {session.ignored} ignored",
|
|
(24, 72), cv2.FONT_HERSHEY_SIMPLEX, 0.55, (200, 200, 200), 1, cv2.LINE_AA)
|
|
|
|
ok, buffer = cv2.imencode(".jpg", frame, [cv2.IMWRITE_JPEG_QUALITY, 75])
|
|
return buffer.tobytes() if ok else None
|