ObjectInsertion / visualizer.py
Leema Krishna Murali
Initial commit
f3d0a26
# demo/visualizer.py
import numpy as np
import cv2
from typing import Optional
def draw_box_on_frame(
frame: np.ndarray, # [H, W, 3] uint8 RGB
box: list, # [x1, y1, x2, y2]
color: tuple = (255, 255, 0),
label: str = "",
thickness: int = 2,
dashed: bool = False
) -> np.ndarray:
"""Draw a single bounding box on a frame"""
frame = frame.copy()
x1, y1, x2, y2 = [int(v) for v in box]
if dashed:
# Draw dashed rectangle manually
dash_len = 10
gap_len = 5
pts = [
((x1, y1), (x2, y1)), # top
((x2, y1), (x2, y2)), # right
((x2, y2), (x1, y2)), # bottom
((x1, y2), (x1, y1)), # left
]
for (px1, py1), (px2, py2) in pts:
dx = px2 - px1
dy = py2 - py1
dist = max(abs(dx), abs(dy))
if dist == 0:
continue
for i in range(0, dist, dash_len + gap_len):
s = i / dist
e = min(i + dash_len, dist) / dist
sx = int(px1 + s * dx)
sy = int(py1 + s * dy)
ex = int(px1 + e * dx)
ey = int(py1 + e * dy)
cv2.line(frame, (sx, sy), (ex, ey), color, thickness)
else:
cv2.rectangle(frame, (x1, y1), (x2, y2), color, thickness)
if label:
cv2.putText(
frame, label,
(x1, max(y1 - 8, 12)),
cv2.FONT_HERSHEY_SIMPLEX,
0.6, color, 2
)
return frame
def draw_trajectory_on_frame(
frame: np.ndarray,
boxes: np.ndarray, # [T, 4] — full trajectory
current_t: int,
color: tuple = (255, 200, 0)
) -> np.ndarray:
"""
Draw the motion path (center points) up to current frame.
Gives a visual "trail" showing where the object came from.
"""
frame = frame.copy()
centers = np.stack([
(boxes[:, 0] + boxes[:, 2]) / 2,
(boxes[:, 1] + boxes[:, 3]) / 2
], axis=1).astype(int)
# Draw path line
for i in range(1, current_t + 1):
alpha = i / (current_t + 1) # fade older points
c = tuple(int(v * alpha) for v in color)
cv2.line(
frame,
tuple(centers[i-1]),
tuple(centers[i]),
c, 2
)
# Draw current center dot
cv2.circle(frame, tuple(centers[current_t]), 5, color, -1)
return frame
def create_comparison_strip(
original: np.ndarray, # [T, H, W, 3]
result: np.ndarray, # [T, H, W, 3]
pred_boxes: np.ndarray, # [T, 4]
sample_ts: list = None # which frames to show
) -> np.ndarray:
"""
Creates a horizontal strip for visual comparison.
Shows: Original | Result | Diff for N sampled frames.
"""
T = len(original)
if sample_ts is None:
sample_ts = [0, T//4, T//2, 3*T//4, T-1]
rows = []
for t in sample_ts:
orig_t = original[t].copy()
res_t = result[t].copy()
# Draw box on result
res_t = draw_box_on_frame(
res_t, pred_boxes[t],
color=(0, 255, 0),
label=f"t={t}"
)
# Amplified diff
diff_t = np.abs(
orig_t.astype(np.int32) - result[t].astype(np.int32)
)
diff_t = (diff_t * 4).clip(0, 255).astype(np.uint8)
# Add labels
def add_label(img, text):
img = img.copy()
cv2.putText(img, text, (10, 25),
cv2.FONT_HERSHEY_SIMPLEX, 0.7,
(255, 255, 255), 2)
cv2.putText(img, text, (10, 25),
cv2.FONT_HERSHEY_SIMPLEX, 0.7,
(0, 0, 0), 1)
return img
orig_t = add_label(orig_t, "Original")
res_t = add_label(res_t, "Result")
diff_t = add_label(diff_t, "Diff x4")
row = np.concatenate([orig_t, res_t, diff_t], axis=1)
rows.append(row)
return np.concatenate(rows, axis=0)