File size: 3,466 Bytes
8e5456b | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 | #!/usr/bin/env python3
"""Extract only the front-view (center) Multi-VSL clips from Data.zip.
The zip holds 87,817 mp4 across center/left/right plus ~176k stale .lock/.metadata
files from an interrupted HuggingFace upload. This pulls out just the clips named in
`Multi-VSL_WACV_2025/data/front_{train,val,test}.csv` (28,412 clips, ~23 GB) into a
flat directory, and records the per-clip resolution and fps -- both vary across
clips because the dataset ships per-clip YOLO crops, and the packing step needs
them to normalize.
"""
import argparse
import csv
import json
import os
import subprocess
import zipfile
from tqdm import tqdm
REPO = os.path.join(os.path.dirname(os.path.abspath(__file__)), '..')
def probe(path):
out = subprocess.run(
['ffprobe', '-v', 'error', '-select_streams', 'v:0', '-show_entries',
'stream=width,height,r_frame_rate,nb_frames', '-of', 'json', path],
capture_output=True, text=True).stdout
try:
st = json.loads(out)['streams'][0]
num, den = st['r_frame_rate'].split('/')
return {'width': int(st['width']), 'height': int(st['height']),
'fps': float(num) / float(den),
'nb_frames': int(st.get('nb_frames') or 0)}
except Exception:
return None
def main():
ap = argparse.ArgumentParser()
ap.add_argument('--zip', default=os.path.join(REPO, 'WACV-Data-SLR', 'Data.zip'))
ap.add_argument('--labels-dir', default=os.path.join(REPO, 'Multi-VSL_WACV_2025', 'data'))
ap.add_argument('--out-dir', default=os.path.join(REPO, 'Multi-VSL_front'))
ap.add_argument('--probe', action='store_true', help='ffprobe each clip (slower)')
args = ap.parse_args()
vid_dir = os.path.join(args.out_dir, 'videos')
os.makedirs(vid_dir, exist_ok=True)
wanted = {}
for split in ('train', 'val', 'test'):
with open(os.path.join(args.labels_dir, f'front_{split}.csv'), encoding='utf-8') as f:
for r in csv.DictReader(f):
wanted[r['name']] = {'split': split, 'label': int(r['label']),
'word': r['word']}
print(f'front-view clips wanted: {len(wanted)}')
z = zipfile.ZipFile(args.zip)
inzip = {os.path.basename(n): n for n in z.namelist() if n.lower().endswith('.mp4')}
print(f'mp4 in zip: {len(inzip)}')
meta, missing, skipped = [], 0, 0
for name, info in tqdm(sorted(wanted.items()), desc='extract'):
src = inzip.get(name)
if src is None:
missing += 1
continue
dst = os.path.join(vid_dir, name)
if not os.path.exists(dst) or os.path.getsize(dst) == 0:
with z.open(src) as fi, open(dst, 'wb') as fo:
while True:
b = fi.read(1 << 20)
if not b:
break
fo.write(b)
else:
skipped += 1
rec = {'name': name, **info, 'size': os.path.getsize(dst)}
if args.probe:
p = probe(dst)
if p:
rec.update(p)
meta.append(rec)
with open(os.path.join(args.out_dir, 'clips.json'), 'w', encoding='utf-8') as f:
json.dump(meta, f, ensure_ascii=False)
print(f'extracted {len(meta)} clips ({skipped} already present), {missing} missing')
print(f'-> {vid_dir}')
tot = sum(m['size'] for m in meta)
print(f'total {tot/1e9:.1f} GB')
if __name__ == '__main__':
main()
|