feat(detect): 把 Label Studio 的 YOLO 导出装配成带 train/val 划分的数据集
scripts/build_yolo_dataset.py:导出(zip 或目录)+ 复核材料里的 images/ -> data/ 下 可训练的数据集。Label Studio 的 YOLO 导出只有标签,本地存储的图片不会打包进去 (get_local_path 对 local-files 直接返回磁盘路径,YOLO_WITH_IMAGES 也一样), 所以图片从准备复核材料的目录按文件名取,硬链接过去。 - 类别顺序照抄导出的 classes.txt:转换器把标签收进 set 再排序编号,与 labeling config 的顺序无关,标签里的 class_id 是按它写的。 - 按类别分层切分,分层用"框最多的那个类别"——人工复核后一张图可能有多个类别的框。 - 标签逐行校验:字段数、类别下标、坐标范围。坏标签训练时不会崩,只会悄悄拉低指标。 - 空标签默认保留为负样本;标签找不到图直接报错,图多于标签则告警。 顺带把 link_or_copy 提到 utils/fs.py 共用(此前 generate_boxes 与 prepare_label_studio 各有一份)。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
65bc6b2045
commit
998e6601d4
@@ -55,7 +55,6 @@ from __future__ import annotations
|
||||
import argparse
|
||||
import contextlib
|
||||
import csv
|
||||
import errno
|
||||
import io
|
||||
import json
|
||||
import logging
|
||||
@@ -73,7 +72,7 @@ sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
|
||||
import yaml # noqa: E402
|
||||
|
||||
from datasets.yolo import IMAGE_SUFFIXES, write_classes_txt # noqa: E402
|
||||
from utils import setup_logging # noqa: E402
|
||||
from utils import link_or_copy, setup_logging # noqa: E402
|
||||
|
||||
logger = None
|
||||
|
||||
@@ -116,21 +115,6 @@ def materialize_png(source: Path, destination: Path) -> str:
|
||||
return "convert"
|
||||
|
||||
|
||||
def link_or_copy(source: Path, destination: Path) -> str:
|
||||
"""硬链接;跨文件系统时退回复制。"""
|
||||
if destination.exists() or destination.is_symlink():
|
||||
destination.unlink()
|
||||
destination.parent.mkdir(parents=True, exist_ok=True)
|
||||
try:
|
||||
os.link(source, destination)
|
||||
return "hard"
|
||||
except OSError as exc:
|
||||
if exc.errno != errno.EXDEV:
|
||||
raise
|
||||
shutil.copy2(source, destination)
|
||||
return "copy"
|
||||
|
||||
|
||||
class Sample(NamedTuple):
|
||||
"""一张图及其标签。
|
||||
|
||||
|
||||
Reference in New Issue
Block a user