# data 存放数据集本体或指向数据集的软链接;除本文件外的内容都不入库(见 .gitignore)。 **原始数据一律放在 `data/raw/<数据集名>/` 下**,派生数据(如按聚类结果导出的数据集) 放在 `data/` 下与 `raw/` 平级,两者一眼可分: ``` data/ ├── raw/ # 原始数据,只读 │ └── film/ │ ├── images/ # 原图(或指向 NAS 的软链:ln -s /mnt/nas/film/images data/raw/film/images) │ │ ├── train/0001.png │ │ └── val/0002.png │ ├── labels/ # 与 images 目录结构一一对应 │ │ ├── train/0001.txt │ │ └── val/0002.txt │ └── data.yaml # path / train / val / nc / names └── film_r18_cluster_k4/ # 派生:scripts/export_clusters.py 的产物 ├── 0/ 1/ 2/ 3/ └── manifest.json ``` 标注采用 **YOLO 风格**:`images/` 下每张图在同层 `labels/` 里有一个同名 `.txt`。 标注文件每行一个目标,坐标**相对图像宽高归一化**到 [0, 1],中心点格式: ``` 0 0.312500 0.204688 0.087500 0.065625 1 0.640625 0.712500 0.120000 0.093750 ``` - `class_id` 是 `data.yaml` / 配置里 `classes` 的下标,顺序即含义,改动必须重新训练。 - **空文件或缺失 `.txt` = 无缺陷样本(OK 片)**,会作为纯负样本参与训练。 - 也接受 YOLO 分割格式的多边形行(`class_id x1 y1 x2 y2 ...`),读取时取外接矩形。 `data.yaml` 与 ultralytics 通用: ```yaml path: data/raw/film train: images/train val: images/val nc: 5 names: {0: scratch, 1: bubble, 2: particle, 3: crease, 4: stain} ``` 配置里的 `classes` 既可以直接写类别列表,也可以写成 `data/raw/film/data.yaml` 由框架读取 `names`。 ## 还没分类的样本 `data/raw/film` 下按人工整理留下的目录(`grease`、`wrinkle`、`反面纵黑点` ……)只是历史产物, 不是最终类别。要重新梳理类别时用无监督聚类,它会忽略这些目录名、把所有图拉平处理: ```bash uv run python scripts/cluster_unlabeled.py --config configs/cluster/film.yaml ``` 结果里的 `clusters/cluster_XX/` 是软链目录,人工确认后再决定每个簇对应什么缺陷、 以及是否要合并/拆分。 ## 从其它格式转过来 ```bash # labelme / VOC -> YOLO txt(顺带生成 data.yaml) uv run python scripts/convert_annotations.py --format labelme \ --input data/raw/film/labelme --images data/raw/film/images \ --output data/raw/film/labels --data-yaml data/raw/film/data.yaml # 划分 train / val(默认建软链,不复制数据) uv run python scripts/split_dataset.py --images data/raw/film/images \ --labels data/raw/film/labels --val-ratio 0.2 --data-yaml data/raw/film/data.yaml ```