PWM / PWM_code /reward_model /scripts /archive /visualize_tracks.py
hchen657Naza's picture
Add files using upload-large-folder tool
23e1f91 verified
Raw History Blame Contribute Delete
4.19 kB
"""Visualize a tracks.npz on top of source frames: point IDs are color-coded,
visibility shown via marker style, and trails up to the current frame are drawn."""
import argparse, os
import numpy as np
import cv2
import imageio
def load_video(path, max_frames=None):
cap = cv2.VideoCapture(path); frames=[]
while True:
r, f = cap.read()
if not r: break
frames.append(cv2.cvtColor(f, cv2.COLOR_BGR2RGB))
if max_frames and len(frames) >= max_frames: break
cap.release(); return frames
def colormap(N):
rng = np.random.default_rng(0)
return (rng.uniform(0, 255, (N, 3))).astype(np.uint8)
def draw_frame(frame, tracks_so_far, vis_so_far, colors, trail_alpha=0.6, radius=4):
"""tracks_so_far: (t+1, N, 2). Draw trail and current-pt for each id."""
img = frame.copy()
overlay = img.copy()
T_now, N, _ = tracks_so_far.shape
# Trails (semi-transparent)
for n in range(N):
pts = tracks_so_far[:, n, :].astype(np.int32)
v = vis_so_far[:, n]
col = tuple(int(c) for c in colors[n])
# draw segments where both endpoints visible
for i in range(1, T_now):
if v[i] and v[i-1]:
cv2.line(overlay, tuple(pts[i-1]), tuple(pts[i]), col, 1, cv2.LINE_AA)
img = cv2.addWeighted(overlay, trail_alpha, img, 1 - trail_alpha, 0)
# Current points: filled circle if visible, hollow ring otherwise
cur = tracks_so_far[-1].astype(np.int32)
cur_v = vis_so_far[-1]
for n in range(N):
col = tuple(int(c) for c in colors[n])
x, y = int(cur[n, 0]), int(cur[n, 1])
if cur_v[n]:
cv2.circle(img, (x, y), radius, col, -1, cv2.LINE_AA)
cv2.circle(img, (x, y), radius, (0, 0, 0), 1, cv2.LINE_AA)
else:
cv2.circle(img, (x, y), radius, col, 1, cv2.LINE_AA)
return img
def main():
ap = argparse.ArgumentParser()
ap.add_argument("--video", required=True)
ap.add_argument("--tracks_npz", required=True)
ap.add_argument("--out_dir", required=True)
ap.add_argument("--max_frames", type=int, default=0)
ap.add_argument("--keyframes", type=int, nargs="+", default=None,
help="frames to dump as PNG (defaults to evenly spaced 4)")
ap.add_argument("--make_video", action="store_true",
help="also dump a track-with-trails MP4")
args = ap.parse_args()
os.makedirs(args.out_dir, exist_ok=True)
frames = load_video(args.video, args.max_frames or None)
z = np.load(args.tracks_npz)
tracks, vis = z["tracks"], z["vis"].astype(bool)
T = min(len(frames), tracks.shape[0])
frames, tracks, vis = frames[:T], tracks[:T], vis[:T]
N = tracks.shape[1]
colors = colormap(N)
print(f"T={T}, N={N}")
print(f"vis frame 0: {int(vis[0].sum())}/{N}")
print(f"vis frame -1: {int(vis[-1].sum())}/{N}")
keyframes = args.keyframes or list(np.linspace(0, T - 1, 4).astype(int))
panels = []
for k in keyframes:
img = draw_frame(frames[k], tracks[:k+1], vis[:k+1], colors)
cv2.putText(img, f"frame {k} vis={int(vis[k].sum())}/{N}", (16, 36),
cv2.FONT_HERSHEY_SIMPLEX, 1.0, (255, 255, 255), 3, cv2.LINE_AA)
cv2.putText(img, f"frame {k} vis={int(vis[k].sum())}/{N}", (16, 36),
cv2.FONT_HERSHEY_SIMPLEX, 1.0, (0, 0, 0), 1, cv2.LINE_AA)
out_p = os.path.join(args.out_dir, f"trail_frame{k:03d}.png")
imageio.imwrite(out_p, img)
print(f" saved {out_p}")
panels.append(img)
# Side-by-side panel of key frames
H, W, _ = panels[0].shape
panel = np.concatenate(panels, axis=1)
panel_p = os.path.join(args.out_dir, "panel.png")
imageio.imwrite(panel_p, panel)
print(f" saved {panel_p} ({panel.shape[1]}x{panel.shape[0]})")
if args.make_video:
out = []
for t in range(T):
out.append(draw_frame(frames[t], tracks[:t+1], vis[:t+1], colors))
outp = os.path.join(args.out_dir, "tracks_with_trails.mp4")
imageio.mimwrite(outp, out, fps=15, macro_block_size=1)
print(f" saved {outp}")
if __name__ == "__main__":
main()