Handle Ego4D terminal voice endpoints
This commit is contained in:
@@ -28,6 +28,7 @@ class CandidateConfig:
|
||||
relation_window_seconds: float = 3.0
|
||||
same_speaker_pause_max_seconds: float = 2.0
|
||||
other_handover_max_seconds: float = 1.5
|
||||
max_terminal_overrun_seconds: float = 0.1
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
@@ -296,14 +297,24 @@ def derive_clip_candidates(
|
||||
clip: dict[str, Any], *, split: str, config: CandidateConfig
|
||||
) -> tuple[list[dict[str, Any]], list[dict[str, Any]]]:
|
||||
segments, wearer_id = load_clip_segments(clip)
|
||||
clip_end = _number(clip.get("clip_end_sec", max((row.end for row in segments), default=0.0)), field="clip_end_sec")
|
||||
outside = [row for row in segments if row.end > clip_end + 1e-6]
|
||||
if outside:
|
||||
first = outside[0]
|
||||
declared_clip_end = _number(
|
||||
clip.get("clip_end_sec", max((row.end for row in segments), default=0.0)),
|
||||
field="clip_end_sec",
|
||||
)
|
||||
maximum_segment_end = max((row.end for row in segments), default=declared_clip_end)
|
||||
terminal_overrun = max(0.0, maximum_segment_end - declared_clip_end)
|
||||
if terminal_overrun > config.max_terminal_overrun_seconds + 1e-9:
|
||||
first = next(row for row in segments if row.end > declared_clip_end)
|
||||
raise ValueError(
|
||||
f"{clip.get('clip_uid')}: voice segment {first.uid} ends at {first.end:.6f}s "
|
||||
f"after clip_end_sec={clip_end:.6f}; refusing to clamp or drop it"
|
||||
f"after clip_end_sec={declared_clip_end:.6f}; terminal overrun "
|
||||
f"{terminal_overrun:.6f}s exceeds the audited limit "
|
||||
f"{config.max_terminal_overrun_seconds:.6f}s; refusing to clamp or drop it"
|
||||
)
|
||||
# Ego4D v1 has quantized terminal voice endpoints a few milliseconds past
|
||||
# the 30-fps video endpoint (for example 300.008 vs 299.966667 seconds).
|
||||
# Preserve that official endpoint and make the bounded exception explicit.
|
||||
clip_end = max(declared_clip_end, maximum_segment_end)
|
||||
candidates: list[dict[str, Any]] = []
|
||||
wearer_segments = [row for row in segments if row.person_id == wearer_id]
|
||||
|
||||
@@ -409,6 +420,14 @@ def derive_clip_candidates(
|
||||
))
|
||||
control_sequence += 1
|
||||
candidates.sort(key=lambda row: (float(row["event_time"]), str(row["uid"])))
|
||||
for row in candidates:
|
||||
row["temporal_evidence"].update({
|
||||
"declared_clip_end_seconds": declared_clip_end,
|
||||
"maximum_voice_segment_end_seconds": maximum_segment_end,
|
||||
"terminal_voice_overrun_seconds": terminal_overrun,
|
||||
"max_allowed_terminal_overrun_seconds": config.max_terminal_overrun_seconds,
|
||||
"terminal_voice_endpoint_preserved_not_clamped": True,
|
||||
})
|
||||
return candidates, [_timeline_row(row) for row in segments]
|
||||
|
||||
|
||||
@@ -462,6 +481,10 @@ def parse_args() -> argparse.Namespace:
|
||||
parser.add_argument("--relation-window-seconds", type=float, default=3.0)
|
||||
parser.add_argument("--same-speaker-pause-max-seconds", type=float, default=2.0)
|
||||
parser.add_argument("--other-handover-max-seconds", type=float, default=1.5)
|
||||
parser.add_argument(
|
||||
"--max-terminal-overrun-seconds", type=float, default=0.1,
|
||||
help="Allow and audit a bounded official voice endpoint past clip_end_sec (default: %(default)s).",
|
||||
)
|
||||
parser.add_argument("--overwrite", action="store_true")
|
||||
return parser.parse_args()
|
||||
|
||||
@@ -471,6 +494,7 @@ def main() -> None:
|
||||
numeric = [
|
||||
args.context_seconds, args.relation_window_seconds,
|
||||
args.same_speaker_pause_max_seconds, args.other_handover_max_seconds,
|
||||
args.max_terminal_overrun_seconds,
|
||||
]
|
||||
if any(value < 0 for value in numeric):
|
||||
raise ValueError("all time windows must be non-negative")
|
||||
|
||||
Reference in New Issue
Block a user