Add more preview
This commit is contained in:
@@ -23,7 +23,7 @@ from extract_turn_local_features import (
|
||||
FrozenQwenLocalEncoder, ego4d_clip_boxes, extract_local,
|
||||
validate_source_timeline,
|
||||
model_config_digest,
|
||||
box_coordinate_offset, frame_crops, parse_args, preview_boxes,
|
||||
box_coordinate_offset, frame_crops, parse_args, preview_boxes, preview_ticks, preview_time_bounds,
|
||||
TESTED_TRANSFORMERS_VERSIONS, validate_local_transformers_version,
|
||||
main as extract_main,
|
||||
)
|
||||
@@ -160,6 +160,100 @@ class LocalTests(unittest.TestCase):
|
||||
self.assertEqual(audit[0]["boxes"][0]["box"], [100, 80, 160, 140])
|
||||
self.assertTrue((folder / audit[0]["image"]).is_file())
|
||||
|
||||
def test_preview_can_save_more_than_four_images_in_a_later_range(self):
|
||||
clip = SimpleNamespace(path=Path("source.mp4"), width=640, height=360,
|
||||
crop=None, dense_start=0.)
|
||||
media = SimpleNamespace(clips=[clip],
|
||||
_source_frame_for_time=lambda t: (0, round(t * 2), t),
|
||||
frame_at_or_before=lambda t: Image.new("RGB", (640, 360)))
|
||||
with tempfile.TemporaryDirectory() as directory:
|
||||
args = SimpleNamespace(box_coordinate_space="camera", crop_expansion=1., video_fps=2.,
|
||||
output_root=Path(directory), preview_count=8,
|
||||
preview_start=2., preview_end=6., preview_with_boxes=False)
|
||||
preview_boxes(media, [{}], args, "clip", 10.)
|
||||
folder = Path(directory) / "clip_preview"
|
||||
audit = json.loads((folder / "boxes.json").read_text())
|
||||
self.assertEqual([row["time"] for row in audit], [2., 2.5, 3., 3.5, 4., 4.5, 5., 5.5])
|
||||
self.assertEqual(audit[0]["image"], "frame_000004.jpg")
|
||||
self.assertEqual(len(list(folder.glob("*.jpg"))), 8)
|
||||
report = json.loads((folder / "preview.json").read_text())
|
||||
self.assertEqual(report["saved_count"], 8)
|
||||
self.assertEqual(report["saved_with_boxes"], 0)
|
||||
|
||||
def test_boxed_preview_filters_valid_corrected_crops_without_decoding(self):
|
||||
# Encoded boxes are corrected by the crop origin, as in feature extraction.
|
||||
clip = SimpleNamespace(crop=(204, 0, 640, 360), width=844, height=360)
|
||||
media = SimpleNamespace(clips=[clip], _source_frame_for_time=lambda t: (0, round(t * 2), t))
|
||||
valid = {"id": "p", "xyxy": [304, 80, 364, 140]}
|
||||
invalid = {"id": "p", "xyxy": [4, 80, 64, 140]} # entirely inside removed banner
|
||||
annotations = [{1: [valid], 3: [invalid], 5: [valid], 7: [valid]}]
|
||||
args = SimpleNamespace(box_coordinate_space="encoded", crop_expansion=1., video_fps=2.,
|
||||
preview_count=2, preview_start=0., preview_end=None, preview_with_boxes=True)
|
||||
selected, grid_count, eligible_count = preview_ticks(media, annotations, args, 4.)
|
||||
self.assertEqual(selected, [1, 7]) # uniform among valid frames, not first N
|
||||
self.assertEqual((grid_count, eligible_count), (8, 3))
|
||||
# No RGB reader is needed by the scan, and annotations are not changed.
|
||||
self.assertEqual(len(annotations[0]), 4)
|
||||
|
||||
def test_empty_boxed_preview_writes_an_explicit_empty_report(self):
|
||||
clip = SimpleNamespace(crop=None, width=640, height=360)
|
||||
media = SimpleNamespace(clips=[clip], _source_frame_for_time=lambda t: (0, round(t * 2), t))
|
||||
with tempfile.TemporaryDirectory() as directory:
|
||||
args = SimpleNamespace(box_coordinate_space="camera", crop_expansion=1., video_fps=2.,
|
||||
output_root=Path(directory), preview_count=40,
|
||||
preview_start=0., preview_end=None, preview_with_boxes=True)
|
||||
preview_boxes(media, [{}], args, "empty_clip", 4.)
|
||||
folder = Path(directory) / "empty_clip_preview"
|
||||
self.assertEqual(json.loads((folder / "boxes.json").read_text()), [])
|
||||
report = json.loads((folder / "preview.json").read_text())
|
||||
self.assertEqual(report["eligible_frame_count"], 0)
|
||||
self.assertEqual(report["saved_count"], 0)
|
||||
self.assertEqual(list(folder.glob("*.jpg")), [])
|
||||
|
||||
def test_preview_range_clips_to_available_end_and_excludes_endpoint(self):
|
||||
args = SimpleNamespace(video_fps=2., preview_start=.1, preview_end=100., preview_count=100)
|
||||
self.assertEqual(preview_time_bounds(args, 1.), (.1, 1.))
|
||||
self.assertEqual(preview_ticks(None, [], args, 1.), ([1], 1, 1))
|
||||
args.preview_start = 2.
|
||||
with self.assertRaisesRegex(ValueError, "outside the available prefix"):
|
||||
preview_time_bounds(args, 1.)
|
||||
|
||||
def test_preview_cli_validation(self):
|
||||
import contextlib
|
||||
import io
|
||||
|
||||
required = ["--data-root", "/raw", "--feature-root", "/global", "--target-root", "/targets",
|
||||
"--output-root", "/preview", "--samples", "4"]
|
||||
valid = parse_args(required + ["--preview-only", "--preview-count", "40", "--preview-start", "30",
|
||||
"--preview-end", "120", "--preview-with-boxes"])
|
||||
self.assertEqual((valid.preview_count, valid.preview_start, valid.preview_end), (40, 30., 120.))
|
||||
for extra in (["--preview-only", "--preview-count", "0"],
|
||||
["--preview-only", "--preview-start", "-1"],
|
||||
["--preview-only", "--preview-end", "nan"],
|
||||
["--preview-only", "--preview-start", "10", "--preview-end", "10"],
|
||||
["--preview-only", "--max-steps", "20", "--preview-end", "60"],
|
||||
["--preview-count", "40"], ["--preview-with-boxes"]):
|
||||
with self.subTest(extra=extra), contextlib.redirect_stderr(io.StringIO()), self.assertRaises(SystemExit):
|
||||
parse_args(required + extra)
|
||||
|
||||
def test_preview_end_limits_media_reader_without_loading_encoder(self):
|
||||
with tempfile.TemporaryDirectory() as directory:
|
||||
root = Path(directory)
|
||||
reference, _, labels = fixture()
|
||||
torch.save(reference, root / "Session_4.pt")
|
||||
np.save(root / "Session_4.npy", labels)
|
||||
args = ["--data-root", str(root), "--feature-root", str(root), "--target-root", str(root),
|
||||
"--output-root", str(root / "preview"), "--samples", "4",
|
||||
"--preview-only", "--preview-end", "2", "--preview-count", "20"]
|
||||
media = SimpleNamespace(clips=[], metadata=lambda: {})
|
||||
with patch("extract_turn_local_features.build_media_and_boxes", return_value=(media, [])) as build, \
|
||||
patch("extract_turn_local_features.preview_boxes") as preview, \
|
||||
patch("extract_turn_local_features.FrozenQwenLocalEncoder") as encoder:
|
||||
extract_main(args)
|
||||
self.assertEqual(build.call_args.args[2], 2.)
|
||||
preview.assert_called_once()
|
||||
encoder.assert_not_called()
|
||||
|
||||
def test_sidecar_alignment_contract_and_modalities(self):
|
||||
reference, side, _ = fixture()
|
||||
with tempfile.TemporaryDirectory() as directory:
|
||||
|
||||
Reference in New Issue
Block a user