Download src/tool/inspect_nyu_depth_v2.py from AXERA-TECH/DepthART: direct link, hf CLI and curl.
- Browser
- Download file 8.36 kB
-
https://huggingface.co/AXERA-TECH/DepthART/resolve/main/src/tool/inspect_nyu_depth_v2.py
- Command line
-
hf download hf://AXERA-TECH/DepthART/src/tool/inspect_nyu_depth_v2.py
-
curl -L -o inspect_nyu_depth_v2.py https://huggingface.co/AXERA-TECH/DepthART/resolve/main/src/tool/inspect_nyu_depth_v2.py
8.36 kB
| #!/usr/bin/env python3 | |
| # -*- coding: utf-8 -*- | |
| """ | |
| NYU Depth V2 (labeled) 数据集查看与导出工具。 | |
| nyu_depth_v2_labeled.mat 是 MATLAB v7.3 (HDF5) 格式,scipy.io.loadmat 无法读取, | |
| 这里统一用 h5py 按需读取,避免一次性载入 2.8GB。 | |
| 数据内容(N = 1449,图像为竖版 640x480,H=640, W=480,RGB 与深度已对齐): | |
| images [N, 3, 640, 480] uint8 RGB | |
| depths [N, 640, 480] float32 已填补深度,单位米 | |
| rawDepths [N, 640, 480] float32 原始深度,0 表示缺失 | |
| labels [N, 640, 480] uint16 语义标签,0=未标注,1..894 对应 names | |
| instances [N, 640, 480] uint8 实例标签,0=无实例 | |
| names [1, 894] cell 类别名(1-based 下标即 label id) | |
| namesToIds containers.Map MATLAB Map,h5py 无法直接解析 | |
| scenes [1, N] cell 场景名,如 kitchen_0004 | |
| sceneTypes [1, N] cell 场景类型,如 kitchen | |
| rawRgbFilenames [1, N] cell 原始 RGB 文件名 | |
| rawDepthFilenames [1, N] cell 原始深度文件名 | |
| accelData [4, N] float32 加速度计数据 | |
| 用法(在 hs/DepthART 目录下执行): | |
| # 打印结构、场景/类别统计和深度数值范围(默认抽样 step=50) | |
| ../../venv/bin/python src/tool/inspect_nyu_depth_v2.py --mat ../../datasets/nyu_depth_v2_labeled.mat | |
| # 全量扫描统计(较慢) | |
| ... --mat ../../datasets/nyu_depth_v2_labeled.mat --full-stats | |
| # 列出全部 894 个类别名 | |
| ... --mat ... --list-classes | |
| # 单样本导出:rgb.png / depth.npy / depth_vis.png / raw_depth.npy | |
| ... --mat ... --index 0 --out-dir results/nyu_demo --with-labels | |
| # 批量导出,例如某场景全部帧 | |
| ... --mat ... --export-dir results/nyu_export --scene kitchen_0004 --with-labels | |
| # 批量导出前 50 张 | |
| ... --mat ... --export-dir results/nyu_export --count 50 | |
| """ | |
| import argparse | |
| import collections | |
| from pathlib import Path | |
| import cv2 | |
| import h5py | |
| import numpy as np | |
| from tqdm import tqdm | |
| # 深度可视化统一范围(米),超出部分截断 | |
| DEPTH_VIS_RANGE = (0.5, 10.0) | |
| def decode_cell(f, ref): | |
| """把 MATLAB cell 中的 char 数组解码为 str。""" | |
| return ''.join(chr(c) for c in np.asarray(f[ref]).ravel()) | |
| def read_cell_list(dset): | |
| return [decode_cell(dset.file, dset[0, i]) for i in range(dset.shape[1])] | |
| def print_info(f, stride, full_stats): | |
| print('== 变量 ==') | |
| for k in f.keys(): | |
| if k.startswith('#'): | |
| continue | |
| o = f[k] | |
| line = f'{k:20s} shape={str(o.shape):24s} dtype={o.dtype}' | |
| if o.compression: | |
| line += f' compression={o.compression}' | |
| print(line) | |
| n = f['depths'].shape[0] | |
| h, w = f['depths'].shape[1:] | |
| names = read_cell_list(f['names']) | |
| scenes = read_cell_list(f['scenes']) | |
| scene_types = read_cell_list(f['sceneTypes']) | |
| print('\n== 规模 ==') | |
| print(f'样本数 {n}') | |
| print(f'分辨率 W={w}, H={h}(data layout 为 [N, C, H, W])') | |
| print(f'场景数 {len(set(scenes))}') | |
| print(f'场景类型数 {len(set(scene_types))}') | |
| print(f'语义类别数 {len(names)}(label id 1..{len(names)},0 为未标注)') | |
| print('场景类型分布 ' + ', '.join(f'{k}:{v}' for k, v in | |
| collections.Counter(scene_types).most_common())) | |
| idx = range(0, n) if full_stats else range(0, n, stride) | |
| idx = list(idx) | |
| print(f'\n== 数值统计({"全量" if full_stats else f"抽样 {len(idx)} 张, step={stride}"}) ==') | |
| d_min, d_max = np.inf, -np.inf | |
| raw_missing = 0 | |
| raw_total = 0 | |
| cls_count = collections.Counter() | |
| inst_max = 0 | |
| for i in tqdm(idx, desc='scan', ncols=80): | |
| d = f['depths'][i] | |
| r = f['rawDepths'][i] | |
| d_min = min(d_min, float(d.min())) | |
| d_max = max(d_max, float(d.max())) | |
| raw_missing += int((r == 0).sum()) | |
| raw_total += r.size | |
| for c in np.unique(f['labels'][i]): | |
| if c > 0: | |
| cls_count[int(c)] += 1 | |
| inst_max = max(inst_max, int(f['instances'][i].max())) | |
| print(f'depths 范围 [{d_min:.4f}, {d_max:.4f}] m') | |
| print(f'rawDepths 缺失 {raw_missing / raw_total * 100:.2f}% (值为 0)') | |
| print(f'出现类别数 {len(cls_count)} / {len(names)}') | |
| print(f'instances 最大 {inst_max}') | |
| print('\n最常见类别 ' + ', '.join( | |
| f'{names[c - 1]}({cnt})' for c, cnt in cls_count.most_common(15))) | |
| def depth_to_vis(depth, raw=False): | |
| lo, hi = DEPTH_VIS_RANGE | |
| norm = np.clip((depth - lo) / (hi - lo), 0.0, 1.0) | |
| vis = cv2.applyColorMap((norm * 255).astype(np.uint8), cv2.COLORMAP_TURBO) | |
| if raw: | |
| vis[depth <= 0] = 0 | |
| return vis | |
| def export_sample(f, index, out_dir, with_labels): | |
| entry = out_dir / f'{index:05d}_{decode_cell(f, f["scenes"][0, index])}' | |
| entry.mkdir(parents=True, exist_ok=True) | |
| rgb = np.asarray(f['images'][index]).transpose(1, 2, 0) # CHW -> HWC, RGB | |
| depth = np.asarray(f['depths'][index], dtype=np.float32) | |
| raw = np.asarray(f['rawDepths'][index], dtype=np.float32) | |
| cv2.imwrite(str(entry / 'rgb.png'), cv2.cvtColor(rgb, cv2.COLOR_RGB2BGR)) | |
| cv2.imwrite(str(entry / 'depth_vis.png'), depth_to_vis(depth)) | |
| cv2.imwrite(str(entry / 'raw_depth_vis.png'), depth_to_vis(raw, raw=True)) | |
| np.save(entry / 'depth.npy', depth) | |
| np.save(entry / 'raw_depth.npy', raw) | |
| if with_labels: | |
| labels = np.asarray(f['labels'][index]) | |
| np.save(entry / 'labels.npy', labels) | |
| # 语义标签着色:按 label id 的哈希色,0 保持黑色 | |
| rng = np.random.default_rng(0) | |
| lut = rng.integers(40, 255, size=(65536, 3), dtype=np.uint8) | |
| lut[0] = 0 | |
| cv2.imwrite(str(entry / 'labels_vis.png'), lut[labels]) | |
| return entry | |
| def main(): | |
| parser = argparse.ArgumentParser(description='查看/导出 NYU Depth V2 labeled 数据集') | |
| parser.add_argument('--mat', required=True, help='nyu_depth_v2_labeled.mat 路径') | |
| parser.add_argument('--list-classes', action='store_true', help='打印全部类别名及 id') | |
| parser.add_argument('--index', type=int, help='导出单个样本的下标') | |
| parser.add_argument('--out-dir', help='--index 模式的输出目录') | |
| parser.add_argument('--export-dir', help='批量导出目录') | |
| parser.add_argument('--count', type=int, help='批量导出数量,默认全部') | |
| parser.add_argument('--step', type=int, default=1, help='批量导出间隔,默认 1') | |
| parser.add_argument('--scene', help='只导出指定场景,如 kitchen_0004') | |
| parser.add_argument('--with-labels', action='store_true', help='同时导出语义标签') | |
| parser.add_argument('--full-stats', action='store_true', help='统计时扫描全部样本') | |
| parser.add_argument('--stats-stride', type=int, default=50, help='抽样统计间隔,默认 50') | |
| args = parser.parse_args() | |
| with h5py.File(args.mat, 'r') as f: | |
| if args.list_classes: | |
| names = read_cell_list(f['names']) | |
| for i, name in enumerate(names, 1): | |
| print(f'{i:4d} {name}') | |
| return | |
| if args.index is not None: | |
| out_dir = Path(args.out_dir or '.') | |
| entry = export_sample(f, args.index, out_dir, args.with_labels) | |
| print(f'已导出 {entry}') | |
| return | |
| if args.export_dir: | |
| n = f['depths'].shape[0] | |
| indices = list(range(0, n, args.step)) | |
| if args.scene: | |
| scenes = read_cell_list(f['scenes']) | |
| indices = [i for i in indices if scenes[i] == args.scene] | |
| print(f'场景 {args.scene} 命中 {len(indices)} 张') | |
| if args.count: | |
| indices = indices[:args.count] | |
| out_dir = Path(args.export_dir) | |
| for i in tqdm(indices, desc='export', ncols=80): | |
| export_sample(f, i, out_dir, args.with_labels) | |
| print(f'已导出 {len(indices)} 张到 {out_dir}') | |
| return | |
| print_info(f, args.stats_stride, args.full_stats) | |
| if __name__ == '__main__': | |
| main() | |