PWM / PWM_code /reward_model /scripts /overlay_object_tracks_on_pred.py
hchen657Naza's picture
Add files using upload-large-folder tool
dd253d4 verified
Raw History Blame Contribute Delete
5.02 kB
"""Overlay 3-PoinTr object tracks (3D positions, projected via stored intrinsics)
onto the existing hand-action _pred.mp4 frames, producing _pred_handobject.mp4.
The hand silhouettes (black) are preserved; object tracks are drawn only on the
white background. Using small colored dots avoids visually colliding with the
hand silhouettes the WM is already conditioned on.
"""
import argparse, os, json
import numpy as np
import torch
import cv2
import imageio.v2 as imageio
def load_video(path):
cap = cv2.VideoCapture(path); frames = []
while True:
r, f = cap.read()
if not r: break
frames.append(cv2.cvtColor(f, cv2.COLOR_BGR2RGB))
cap.release()
return frames
def load_episode(ep_dir):
meta = json.load(open(os.path.join(ep_dir, "metadata.json")))
T = meta["T"]
pos, vis = [], []
for k in range(1, T + 1):
ts = os.path.join(ep_dir, f"timestep_{k}")
pos.append(torch.load(os.path.join(ts, f"{k}_pos.pth"), weights_only=False).numpy())
vis.append(torch.load(os.path.join(ts, f"{k}_visibility.pth"), weights_only=False).numpy())
pos = np.stack(pos, 0); vis = np.stack(vis, 0)
K = meta["intrinsics"]["camera"]
return pos, vis, (K["fx"], K["fy"], K["cx"], K["cy"]), meta
def project(p, fx, fy, cx, cy):
z = np.maximum(p[..., 2], 1e-6)
u = p[..., 0] / z * fx + cx
v = p[..., 1] / z * fy + cy
return np.stack([u, v], -1)
def is_white(pixel, thresh=235):
return (pixel >= thresh).all()
def overlay_object_tracks(pred_frames, pos_3d, vis, K, *, color="red",
dot_radius=3, stride=1, draw_only_on_white=True,
white_thresh=230, trail_len=0):
"""Draw colored dots on the pred frames at projected object positions.
`draw_only_on_white=True` ensures hand silhouettes (black) are never overwritten,
so the WM can still see the same hand instruction.
"""
fx, fy, cx, cy = K
Tp = len(pred_frames)
Tt = pos_3d.shape[0]
T = min(Tp, Tt)
H, W = pred_frames[0].shape[:2]
color_map = {
"red": (220, 30, 30),
"blue": (30, 120, 255),
"green": (40, 200, 40),
"magenta": (220, 30, 200),
}
col_rgb = color_map[color]
out = []
proj = project(pos_3d, fx, fy, cx, cy) # (T, N, 2)
for t in range(T):
f = pred_frames[t].copy()
# current-frame dots
for n in range(0, pos_3d.shape[1], stride):
if not vis[t, n]:
continue
x, y = proj[t, n]
if not (0 <= x < W and 0 <= y < H):
continue
xi, yi = int(round(x)), int(round(y))
if draw_only_on_white and not is_white(f[yi, xi], white_thresh):
# skip drawing on top of hand silhouette pixels
continue
cv2.circle(f, (xi, yi), dot_radius, col_rgb, -1, cv2.LINE_AA)
# short trail
if trail_len > 0 and t > 0:
t0 = max(0, t - trail_len)
for n in range(0, pos_3d.shape[1], stride):
for ti in range(t0 + 1, t + 1):
if not (vis[ti, n] and vis[ti - 1, n]):
continue
x1, y1 = proj[ti - 1, n]
x2, y2 = proj[ti, n]
if not (0 <= x1 < W and 0 <= y1 < H and 0 <= x2 < W and 0 <= y2 < H):
continue
cv2.line(f, (int(x1), int(y1)), (int(x2), int(y2)), col_rgb, 1, cv2.LINE_AA)
out.append(f)
return out
def main():
ap = argparse.ArgumentParser()
ap.add_argument("--pred_video", required=True)
ap.add_argument("--ep_dir", required=True,
help="3-PoinTr episode dir, e.g. .../no_actions/stack_can/0001")
ap.add_argument("--out_video", required=True)
ap.add_argument("--color", default="red", choices=["red", "blue", "green", "magenta"])
ap.add_argument("--stride", type=int, default=1)
ap.add_argument("--dot_radius", type=int, default=3)
ap.add_argument("--trail_len", type=int, default=0)
ap.add_argument("--no_white_only", action="store_true",
help="Allow drawing on hand silhouette too (default protects hands).")
args = ap.parse_args()
print(f"[in] pred : {args.pred_video}")
print(f"[in] ep_dir: {args.ep_dir}")
pred_frames = load_video(args.pred_video)
pos, vis, K, meta = load_episode(args.ep_dir)
print(f" pred T={len(pred_frames)} tracks T={pos.shape[0]} N={pos.shape[1]}")
print(f" intrinsics: fx={K[0]:.1f} fy={K[1]:.1f} cx={K[2]:.1f} cy={K[3]:.1f}")
out = overlay_object_tracks(
pred_frames, pos, vis, K,
color=args.color, dot_radius=args.dot_radius, stride=args.stride,
draw_only_on_white=(not args.no_white_only),
trail_len=args.trail_len,
)
imageio.mimwrite(args.out_video, out, fps=15, macro_block_size=1)
print(f"[out] {args.out_video} ({len(out)} frames)")
if __name__ == "__main__":
main()