feat: add --show-events overlay with raw log intensity
Visualize raw temporal brightness change (threshold=0, log domain) as green(+)/red(-) gradient overlay proportional to |change|. Supports video output and live display modes. Enables EventProcessor threshold=0 for raw mode without clipping. Generated by Mistral Vibe. Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
This commit is contained in:
@@ -34,6 +34,7 @@ from src.velocity_prediction.utils import (
|
||||
R_ODOM_TO_BODY,
|
||||
)
|
||||
from src.velocity_prediction.config import DATASET_ROOT, VELOCITY_MEAN, VELOCITY_STD
|
||||
from src.event_utils import EventProcessor
|
||||
|
||||
|
||||
# ──────────────────────────── Data loading ────────────────────────────
|
||||
@@ -140,6 +141,8 @@ def draw_pose_overlay(
|
||||
euler: np.ndarray,
|
||||
frame_idx: int,
|
||||
ts: float,
|
||||
events: np.ndarray | None = None,
|
||||
show_events: bool = False,
|
||||
):
|
||||
"""
|
||||
Draw body-frame pose and velocity information onto the image.
|
||||
@@ -285,6 +288,21 @@ def draw_pose_overlay(
|
||||
cv2.LINE_AA,
|
||||
)
|
||||
|
||||
# ── Event overlay (gradient temporal intensity) ──
|
||||
if show_events and events is not None:
|
||||
limit = max(np.abs(events).max(), 1e-6)
|
||||
norm = np.clip(events / limit, -1.0, 1.0)
|
||||
pos = norm > 0
|
||||
neg = norm < 0
|
||||
intensity = np.abs(norm) # [0, 1] magnitude
|
||||
overlay = np.zeros_like(display, dtype=np.uint8)
|
||||
# bg = np.ones_like(display, dtype=np.uint8) * 255
|
||||
# Color intensity proportional to |norm|: dark → bright
|
||||
overlay[pos, 1] = (255 * intensity[pos]).astype(np.uint8) # green channel
|
||||
overlay[neg, 2] = (255 * intensity[neg]).astype(np.uint8) # red channel
|
||||
# display = cv2.addWeighted(bg, 0.5, overlay, 1.0, 0)
|
||||
display = cv2.addWeighted(display, 0.5, overlay, 1.0, 0)
|
||||
|
||||
return display
|
||||
|
||||
|
||||
@@ -297,6 +315,7 @@ def create_video(
|
||||
fps: float = 30.0,
|
||||
max_frames: int | None = None,
|
||||
show: bool = False,
|
||||
show_events: bool = False,
|
||||
):
|
||||
"""
|
||||
Read scene data, overlay pose info, and write to video file (or show).
|
||||
@@ -316,6 +335,9 @@ def create_video(
|
||||
# Reset attitude offset for this scene
|
||||
reset_attitude_offset()
|
||||
|
||||
# Event processor (threshold=0 → raw temporal intensity)
|
||||
event_processor = EventProcessor(threshold=0.3, use_log=True) if show_events else None
|
||||
|
||||
# Get dimensions from first frame
|
||||
h, w = frames[0]["img"].shape
|
||||
|
||||
@@ -334,6 +356,12 @@ def create_video(
|
||||
for i, frame_data in enumerate(frames):
|
||||
q_raw = frame_data["pose"][3:7] # [qx, qy, qz, qw] world→odom
|
||||
|
||||
# Compute events if enabled
|
||||
if event_processor is not None:
|
||||
events_binary, _, _ = event_processor(frame_data["img"])
|
||||
else:
|
||||
events_binary = None
|
||||
|
||||
# Body up vector (pitch & roll only, no yaw) — matches DiffPhysDrone
|
||||
body_up = body_up_vector_np(q_raw) # (3,) unit vector
|
||||
|
||||
@@ -354,6 +382,8 @@ def create_video(
|
||||
euler=euler_deg,
|
||||
frame_idx=i,
|
||||
ts=frame_data["ts"],
|
||||
events=events_binary,
|
||||
show_events=show_events,
|
||||
)
|
||||
|
||||
if show:
|
||||
@@ -404,6 +434,9 @@ def main():
|
||||
parser.add_argument(
|
||||
"--show", action="store_true", help="Display on screen instead of saving video"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--show-events", action="store_true", help="Overlay event frames (green=+1, red=-1)"
|
||||
)
|
||||
args = parser.parse_args()
|
||||
|
||||
# Collect scenes to process
|
||||
@@ -436,6 +469,7 @@ def main():
|
||||
fps=args.fps,
|
||||
max_frames=args.max_frames,
|
||||
show=args.show,
|
||||
show_events=args.show_events,
|
||||
)
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user