File size: 4,423 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
95
96
97
#!/usr/bin/env python3
"""Build a 3-view (front/left/right) Full_TriVis CSV that `prepare_vsl_data.py` can pack.

`Full_TriVis/split_lab_front.csv` covers only the front view: 24,151 clips.
`Full_TriVis/Label/Dataset_full_lab.csv` is the master label file and holds all three
views of the same sentences -- 72,453 rows = 24,151 x 3, scene `lab` throughout -- which
matches the 72,453 lab `.npz` files under `Full_TriVis/skeleton/` exactly.

The split is INHERITED, not redrawn. `splits.json` used `split_key = Sign_sentence`, so
assigning each master row the split of its `Sign_sentence` keeps every view of a sentence
in the same split. That preserves the text-disjoint property (a sentence never spans
splits), and it keeps the new test set a strict superset of the old one, so front-only
results stay directly comparable -- the front subset of the new test split IS the old test
split.

npz path = "Full_TriVis/skeleton/" + Sentence_video_path with .mp4 -> .npz.
"""
import argparse
import collections
import csv
import os

REPO = os.path.join(os.path.dirname(os.path.abspath(__file__)), '..')
COLS = ['split', 'npz_path', 'Sentence', 'Sign_sentence', 'Category', 'group', 'view',
        'scene', 'ID_sentence', 'Sentence_video_path']


def main():
    ap = argparse.ArgumentParser()
    ap.add_argument('--front-csv', default=os.path.join(REPO, 'Full_TriVis',
                                                       'split_lab_front.csv'))
    ap.add_argument('--master-csv', default=os.path.join(REPO, 'Full_TriVis', 'Label',
                                                        'Dataset_full_lab.csv'))
    ap.add_argument('--skeleton-root', default='Full_TriVis/skeleton')
    ap.add_argument('--repo-root', default=REPO)
    ap.add_argument('--views', default='front,left,right')
    ap.add_argument('--out', default=os.path.join(REPO, 'Full_TriVis',
                                                 'split_lab_3view.csv'))
    ap.add_argument('--check-exists', action='store_true',
                    help='stat every npz and drop the missing ones (slow but safe)')
    args = ap.parse_args()

    want = set(args.views.split(','))

    with open(args.front_csv, newline='', encoding='utf-8') as f:
        front = list(csv.DictReader(f))
    split_of = {r['Sign_sentence']: r['split'] for r in front}
    print(f'{len(front)} front rows -> {len(split_of)} distinct Sign_sentence with a split')

    with open(args.master_csv, newline='', encoding='utf-8') as f:
        master = list(csv.DictReader(f))
    print(f'{len(master)} master rows, views {sorted({r["view"] for r in master})}')

    rows, missing_split, missing_file = [], 0, 0
    for r in master:
        if r['view'] not in want:
            continue
        sp = split_of.get(r['Sign_sentence'])
        if sp is None:
            missing_split += 1
            continue
        npz = os.path.join(args.skeleton_root,
                           r['Sentence_video_path'].replace('.mp4', '.npz'))
        if args.check_exists and not os.path.exists(os.path.join(args.repo_root, npz)):
            missing_file += 1
            continue
        rows.append({'split': sp, 'npz_path': npz, 'Sentence': r['Sentence'],
                     'Sign_sentence': r['Sign_sentence'], 'Category': r['Category'],
                     'group': r['group'], 'view': r['view'], 'scene': r['scene'],
                     'ID_sentence': r['ID_sentence'],
                     'Sentence_video_path': r['Sentence_video_path']})

    with open(args.out, 'w', newline='', encoding='utf-8') as f:
        w = csv.DictWriter(f, fieldnames=COLS)
        w.writeheader()
        w.writerows(rows)

    print(f'wrote {args.out}: {len(rows)} rows '
          f'(no split {missing_split}, missing npz {missing_file})')
    print('  split x view:')
    c = collections.Counter((r['split'], r['view']) for r in rows)
    for sp in ('train', 'val', 'test'):
        line = '  '.join(f'{v} {c[(sp, v)]}' for v in sorted(want))
        print(f'    {sp:<6} {line}   total {sum(c[(sp, v)] for v in want)}')

    # leak check, the same one splits.json reports
    by = collections.defaultdict(set)
    for r in rows:
        by[r['Sign_sentence']].add(r['split'])
    span = sum(1 for v in by.values() if len(v) > 1)
    print(f'  leakage_check: {"PASS" if span == 0 else "FAIL"}: {span} Sign_sentence '
          f'values span multiple splits')


if __name__ == '__main__':
    main()