Handle two-frame Ego4D bbox tails and preserve worker errors
This commit is contained in:
@@ -27,6 +27,9 @@ from local_turn_features import (
|
||||
|
||||
|
||||
TESTED_TRANSFORMERS_VERSIONS = ("4.52.3", "4.57.6")
|
||||
# Verified Ego4D exports can retain one or two bbox frame indices after the
|
||||
# media endpoint. This bounds frame positions, not the number of people/boxes.
|
||||
EGO4D_MAX_TERMINAL_FRAME_OVERRUN = 2
|
||||
|
||||
|
||||
def validate_local_transformers_version(version: str) -> str:
|
||||
@@ -191,12 +194,13 @@ def load_ego4d_boxes(paths: list[Path], names: list[str]) -> dict[str, Any]:
|
||||
|
||||
|
||||
def validate_ego4d_box_frames(name: str, annotation: dict[str, Any], source):
|
||||
"""Ignore only a confirmed exclusive-end record; never shift/clamp boxes."""
|
||||
"""Ignore a bounded, boundary-confirmed tail; never shift/clamp boxes."""
|
||||
frames, bounds = annotation["frames"], annotation["bounds"]
|
||||
count = source.num_frames
|
||||
outside = sorted(frame for frame in frames if not 0 <= frame < count)
|
||||
audit = {
|
||||
"policy": "clip-local-zero-based; ignore-confirmed-exclusive-end-only",
|
||||
"policy": "clip-local-zero-based; ignore-confirmed-tail-up-to-2-frames",
|
||||
"max_terminal_frame_overrun": EGO4D_MAX_TERMINAL_FRAME_OVERRUN,
|
||||
"source_frames": count, "source_fps": source.source_fps,
|
||||
"declared_bounds": dict(bounds),
|
||||
"annotation_frame_range": [min(frames), max(frames)] if frames else None,
|
||||
@@ -211,22 +215,27 @@ def validate_ego4d_box_frames(name: str, annotation: dict[str, Any], source):
|
||||
and source.source_fps > 0 and abs(start_sec) <= 1e-6
|
||||
and abs((end_sec - start_sec) - count / source.source_fps) <= 1e-4
|
||||
)
|
||||
if (outside != [count] or bounds.get("clip_start_frame") != 0
|
||||
# Allow only N and N+1. Counting outliers alone would accidentally permit
|
||||
# sparse but arbitrarily distant boxes; the maximum index must be bounded.
|
||||
small_terminal_tail = count <= outside[0] <= outside[-1] < count + EGO4D_MAX_TERMINAL_FRAME_OVERRUN
|
||||
if (not small_terminal_tail or bounds.get("clip_start_frame") != 0
|
||||
or bounds.get("clip_end_frame") != count or not duration_matches):
|
||||
raise ValueError(
|
||||
f"Ego4D annotation frame exceeds source clip: {name}; "
|
||||
f"source_frames={count}, source_fps={source.source_fps}, "
|
||||
f"annotation_range={audit['annotation_frame_range']}, "
|
||||
f"out_of_range_count={len(outside)}, first_10={outside[:10]}, "
|
||||
f"declared_bounds={bounds}. Only frame == source_frames == clip_end_frame "
|
||||
"with zero-origin, matching duration is an allowed terminal record; "
|
||||
f"declared_bounds={bounds}. Only terminal indices in "
|
||||
f"[{count}, {count + EGO4D_MAX_TERMINAL_FRAME_OVERRUN - 1}] "
|
||||
"with source_frames == clip_end_frame, zero origin and matching duration are allowed; "
|
||||
"check annotation/video alignment instead of clamping or skipping the clip."
|
||||
)
|
||||
audit.update(ignored_frame_indices=[count], ignored_box_count=len(frames[count]))
|
||||
print(f"{name}: ignoring exclusive-end bbox record at frame {count} "
|
||||
f"({len(frames[count])} boxes); decoded frames are 0..{count - 1}. "
|
||||
ignored_boxes = sum(len(frames[frame]) for frame in outside)
|
||||
audit.update(ignored_frame_indices=outside, ignored_box_count=ignored_boxes)
|
||||
print(f"{name}: ignoring terminal bbox frame indices {outside} "
|
||||
f"({ignored_boxes} boxes); decoded frames are 0..{count - 1}. "
|
||||
"No frame shift or feature/target row removal.", flush=True)
|
||||
return {frame: boxes for frame, boxes in frames.items() if frame != count}, audit
|
||||
return {frame: boxes for frame, boxes in frames.items() if 0 <= frame < count}, audit
|
||||
|
||||
|
||||
def build_media_and_boxes(args: argparse.Namespace, name: str, end: float, ego_boxes: dict[str, Any]):
|
||||
|
||||
Reference in New Issue
Block a user