Multi-CamTracker / src /utils /visualization.py
sngram's picture
Upload folder using huggingface_hub
56dd776 verified
Raw History Blame Contribute Delete
2.73 kB
import cv2
import numpy as np
def get_color(idx):
"""Generate a distinct, bright BGR color based on integer ID using golden ratio HSV palette."""
idx = int(idx)
golden_ratio_conjugate = 0.618033988749895
h = (idx * golden_ratio_conjugate) % 1.0
s = 0.85
v = 0.95
# Convert HSV (0..1) to BGR (0..255)
hsv = np.uint8([[[h * 180, s * 255, v * 255]]])
bgr = cv2.cvtColor(hsv, cv2.COLOR_HSV2BGR)[0][0]
return (int(bgr[0]), int(bgr[1]), int(bgr[2]))
def draw_bounding_box(frame, track_id, bbox, confidence=None, text_prefix="ID"):
"""
Draw a clean, modern bounding box with a filled header badge for the ID label.
bbox: [x1, y1, x2, y2]
"""
x1, y1, x2, y2 = [int(v) for v in bbox]
h, w = frame.shape[:2]
x1 = max(0, min(x1, w - 1))
y1 = max(0, min(y1, h - 1))
x2 = max(0, min(x2, w - 1))
y2 = max(0, min(y2, h - 1))
color = get_color(track_id)
line_thickness = max(2, int(round(min(w, h) / 400.)))
# Draw main rectangle
cv2.rectangle(frame, (x1, y1), (x2, y2), color, line_thickness)
# Label text
if confidence is not None:
label = f"{text_prefix} #{track_id} ({confidence:.2f})"
else:
label = f"{text_prefix} #{track_id}"
font_scale = max(0.4, min(w, h) / 1000.)
font_thickness = max(1, int(font_scale * 2))
(text_width, text_height), baseline = cv2.getTextSize(label, cv2.FONT_HERSHEY_SIMPLEX, font_scale, font_thickness)
# Draw background box for text badge
badge_y1 = max(0, y1 - text_height - 8)
badge_y2 = y1
badge_x2 = min(w, x1 + text_width + 10)
cv2.rectangle(frame, (x1, badge_y1), (badge_x2, badge_y2), color, -1)
# Text inside badge (white or dark depending on color brightness)
text_color = (255, 255, 255)
cv2.putText(
frame,
label,
(x1 + 5, badge_y2 - 5),
cv2.FONT_HERSHEY_SIMPLEX,
font_scale,
text_color,
font_thickness,
lineType=cv2.LINE_AA
)
def create_side_by_side_grid(frames):
"""Stack a list of frames horizontally or in a grid for multi-camera view."""
if not frames:
return None
if len(frames) == 1:
return frames[0]
# Resize frames to match height of first frame
target_h = frames[0].shape[0]
resized_frames = []
for f in frames:
h, w = f.shape[:2]
if h != target_h:
target_w = int(w * (target_h / float(h)))
f_res = cv2.resize(f, (target_w, target_h))
else:
f_res = f
resized_frames.append(f_res)
# Combine horizontally
combined = np.hstack(resized_frames)
return combined