多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

YOLO红细胞目标检测数据集:格式转换、划分脚本与训练避坑指南

YOLO红细胞目标检测数据集:格式转换、划分脚本与训练避坑指南 简介本资源为YOLO红细胞目标检测数据集面向从事医学图像检测、目标检测算法学习与课程实践的学生及开发者可解决红细胞识别任务中数据获取难、标注格式不统一的问题。压缩包共2000个文件约19.82MB包含1000张真实场景高质量图片以及vocxml、cocojson和yolotxt三种格式标签另附yaml配置文件、划分脚本与训练教程网页方便直接接入YOLO系列模型训练。资源还提供训练集、验证集、测试集划分脚本可按需重新划分数据并配有Windows与Linux环境搭建及训练案例教程帮助读者快速跑通从环境配置到模型训练的全流程。目前已有347人学习下载适合作为课程设计、科研实验或算法入门的实战数据集。1. 从一批红细胞图片说起YOLO 数据集到底该怎么组装手里拿到 1000 张显微镜下的红细胞图片第一反应往往不是兴奋而是发愁——这些图怎么变成 YOLO 能吃的格式标注文件在哪训练集验证集怎么切这恰恰是「YOLO 红细胞目标检测数据集」这个标题背后最真实的诉求。它不是一个单纯的图片压缩包而是一整套从原始图像到可训练样本的流水线1000 张红细胞显微图像、VOC / COCO / YOLO 三种格式的标签、一份划分脚本外加一份训练教程。做医学图像检测的团队、做细胞计数自动化的开发者、以及刚接触目标检测想找一个完整数据集练手的人都是这套东西的目标用户。红细胞检测本身有它的特殊性细胞密集、边缘粘连、尺度变化大这些特性决定了后面格式转换和训练参数不能照搬通用数据集的做法。这一章先把这套数据集的全貌讲清楚后面几章再一步步拆开怎么做格式转换、怎么跑划分脚本、怎么把模型训起来。2. 三种标签格式的取舍VOC、COCO、YOLO 各自适合什么场景拿到数据集先别急着解压就训。三种格式并存不是冗余而是对应三种不同的下游工具链。选错了格式后面要么写一堆转换脚本要么在框架里反复报错。这一章把三种格式的结构、适用场景和转换关系讲透让你拿到手就知道该用哪一份。2.1 VOC XML 的结构与适用场景VOC 格式是目标检测里最老牌的一种每张图对应一个同名 XML 文件。它的核心字段是object下的name、bndbox里的xmin/ymin/xmax/ymax坐标是绝对像素值。红细胞数据集里如果给了 VOC 标签通常长这样annotation filenamerbc_0001.jpg/filename size width640/width height480/height depth3/depth /size object nameRBC/name bndbox xmin112/xmin ymin88/ymin xmax156/xmax ymax132/ymax /bndbox /object /annotationVOC 的好处是可读性强用labelImg打开就能直接改适合人工复核标注质量。缺点是文件数量翻倍1000 张图就是 1000 个 XML磁盘上小文件一多读取速度会明显下降。如果你用的是早期版本的mmdetection或者自己写的 PyTorch DatasetVOC 是最省事的入口。但要注意VOC 的坐标是绝对像素图像做 resize 之后必须同步缩放标注框否则框会全部错位——这是新手最常翻车的地方。2.2 COCO JSON 的结构与适用场景COCO 格式把所有标注塞进一个 JSON 文件结构分images、annotations、categories三块。红细胞数据集转成 COCO 后categories里通常只有一个类别id为 1name为RBC或red_blood_cell。annotations里的bbox是[x, y, width, height]注意这里是左上角坐标加宽高不是右下角坐标和 VOC 的xmax/ymax差一个减法。{ images: [{id: 1, file_name: rbc_0001.jpg, width: 640, height: 480}], annotations: [ {id: 1, image_id: 1, category_id: 1, bbox: [112, 88, 44, 44], area: 1936, iscrowd: 0} ], categories: [{id: 1, name: RBC, supercategory: cell}] }COCO 适合detectron2、mmdetection以及 COCO API 那一套评估工具。它的优势是单文件、加载快、评估指标现成。坑在于area字段必须和bbox一致iscrowd一般设 0如果从 VOC 转过来时忘了算area评估阶段会直接报错或者指标全为 0。另外 COCO 的id必须全局唯一多张图合并时容易撞 id写转换脚本时要用计数器而不是文件名哈希。2.3 YOLO TXT 的结构与适用场景YOLO 格式最轻量每张图一个.txt每行一个目标格式是class_id x_center y_center width height全部归一化到 0~1。红细胞数据集里的 YOLO 标签一行大概是这样0 0.218750 0.229167 0.068750 0.091667这个格式直接对应 Ultralytics 的 YOLOv5/v8/v11 训练入口也是目前最主流的做法。它的优点是解析极快、和图像一一对应、不需要额外依赖。坑在于归一化坐标一旦算错框会跑到图像外面训练时 loss 不降反升。还有一个隐蔽问题如果某张图没有目标YOLO 要求有一个空的.txt文件而不是不生成文件否则训练时图像和标签数量对不上会直接报错。2.4 三种格式的字段对照与转换关系把三种格式的字段放在一起看转换逻辑就清楚了字段含义VOCCOCOYOLO左上角 xxminbbox[0](x_center - w/2) * img_w左上角 yyminbbox[1](y_center - h/2) * img_h宽xmax - xminbbox[2]w * img_w高ymax - yminbbox[3]h * img_h类别namecategory_idclass_id坐标类型绝对像素绝对像素归一化转换的核心就三件事坐标原点统一、宽高算法统一、类别映射统一。VOC 和 COCO 都是绝对像素互转只需要处理xmax/ymax和width/height的换算YOLO 多一步除以图像宽高。实际做的时候我一般以 VOC 为中间格式先统一转 VOC再从 VOC 分叉转 COCO 和 YOLO这样脚本最好维护。3. 用划分脚本切分训练集与验证集别让数据泄漏毁掉评估1000 张图如果全拿去训练模型在验证集上的指标就是自欺欺人。划分脚本的作用是把数据按比例切成 train / val有时还要切出 test。这一章讲清楚划分的逻辑、脚本怎么写、以及红细胞数据集中划分时最容易踩的坑。3.1 划分比例与随机种子的选择红细胞检测这种任务1000 张图不算多常见比例是 8:1:1 或 7:2:1。如果只做训练和验证8:2 也够用。关键是随机种子要固定否则每次跑脚本切出来的验证集都不一样指标没法对比。我一般用seed42并且在脚本里显式设置random.seed(42)和numpy.random.seed(42)。另一个容易被忽略的点是分层抽样。如果红细胞图像里有一部分是低倍镜、一部分是高倍镜或者有不同染色条件直接随机切可能导致验证集里某种条件一张都没有。稳妥做法是按图像来源或亮度分桶再在桶内随机切。数据集如果没给来源信息至少按文件名的前缀分组切避免同一批连续拍摄的图同时进训练和验证。3.2 划分脚本的完整实现下面这份脚本以 VOC 标注为输入输出 train / val 两个列表文件同时把对应的图片和 XML 复制到目标目录。逻辑是先扫描所有 XML提取文件名打乱后按比例切分再复制文件。import os import random import shutil import xml.etree.ElementTree as ET # 参数区按实际路径修改 SRC_IMG_DIR data/images SRC_XML_DIR data/annotations DST_ROOT dataset TRAIN_RATIO 0.8 VAL_RATIO 0.1 TEST_RATIO 0.1 SEED 42 random.seed(SEED) # 收集所有有对应 XML 的图片名不含扩展名 names [] for xml_file in os.listdir(SRC_XML_DIR): if not xml_file.endswith(.xml): continue stem os.path.splitext(xml_file)[0] img_path os.path.join(SRC_IMG_DIR, stem .jpg) if os.path.exists(img_path): names.append(stem) names.sort() random.shuffle(names) n len(names) n_train int(n * TRAIN_RATIO) n_val int(n * VAL_RATIO) splits { train: names[:n_train], val: names[n_train:n_train n_val], test: names[n_train n_val:] } # 创建目录并复制文件 for split, items in splits.items(): img_out os.path.join(DST_ROOT, split, images) xml_out os.path.join(DST_ROOT, split, annotations) os.makedirs(img_out, exist_okTrue) os.makedirs(xml_out, exist_okTrue) for stem in items: shutil.copy(os.path.join(SRC_IMG_DIR, stem .jpg), os.path.join(img_out, stem .jpg)) shutil.copy(os.path.join(SRC_XML_DIR, stem .xml), os.path.join(xml_out, stem .xml)) print(f{split}: {len(items)} samples) # 同时输出 YOLO 训练需要的 txt 列表 for split, items in splits.items(): with open(os.path.join(DST_ROOT, f{split}.txt), w) as f: for stem in items: f.write(os.path.join(DST_ROOT, split, images, stem .jpg) \n)脚本里几个参数值得说明。TRAIN_RATIO和VAL_RATIO按需改剩下的自动归 test。SEED固定后每次切分结果一致方便复现。复制而不是移动是为了保留原始数据切错了还能重来。最后输出的train.txt/val.txt是给 YOLO 训练用的图像路径列表Ultralytics 的data.yaml里可以直接引用。3.3 划分后必须做的三项校验切完不是就完事了至少校验三件事。第一train / val / test 之间没有重名文件用集合求交集结果必须是空集。第二每个 split 里图像数量和标注数量一致红细胞数据集里如果某张图漏了 XML训练时会报找不到标签。第三统计每个 split 的目标框总数如果 val 的框数少得离谱说明切分不均匀需要换种子重切。# 校验示例 train_set set(splits[train]) val_set set(splits[val]) assert len(train_set val_set) 0, train 和 val 有重叠 for split, items in splits.items(): img_cnt len(os.listdir(os.path.join(DST_ROOT, split, images))) xml_cnt len(os.listdir(os.path.join(DST_ROOT, split, annotations))) assert img_cnt xml_cnt, f{split} 图像与标注数量不一致 print(f{split}: images{img_cnt}, xml{xml_cnt})这三项校验花不了两分钟但能省掉后面训练时几个小时的排查。血泪经验是数据泄漏往往不是切分逻辑错而是文件名有重复或者大小写不一致校验脚本能直接抓出来。4. 从 VOC 到 YOLO转换脚本与四个边界坑数据集给了三种格式但真正训练时通常只用一种。这一章以 VOC 转 YOLO 为主线把转换脚本写完整再把转换过程中最容易出错的四个边界情况讲清楚。COCO 的转换逻辑类似只是输出结构不同掌握了 VOC 转 YOLO转 COCO 就是换个写文件的方式。4.1 VOC 转 YOLO 的完整脚本转换的核心是读 XML、取图像宽高、把绝对坐标归一化、写 TXT。下面这份脚本处理单类别红细胞检测类别 id 固定为 0。import os import xml.etree.ElementTree as ET from PIL import Image SRC_XML_DIR dataset/train/annotations SRC_IMG_DIR dataset/train/images DST_LABEL_DIR dataset/train/labels CLASS_MAP {RBC: 0} os.makedirs(DST_LABEL_DIR, exist_okTrue) for xml_file in os.listdir(SRC_XML_DIR): if not xml_file.endswith(.xml): continue stem os.path.splitext(xml_file)[0] xml_path os.path.join(SRC_XML_DIR, xml_file) img_path os.path.join(SRC_IMG_DIR, stem .jpg) # 用 PIL 读实际图像尺寸而不是信 XML 里的 size with Image.open(img_path) as im: img_w, img_h im.size tree ET.parse(xml_path) root tree.getroot() lines [] for obj in root.findall(object): name obj.find(name).text if name not in CLASS_MAP: continue cls_id CLASS_MAP[name] bndbox obj.find(bndbox) xmin float(bndbox.find(xmin).text) ymin float(bndbox.find(ymin).text) xmax float(bndbox.find(xmax).text) ymax float(bndbox.find(ymax).text) # 裁剪到图像边界内防止越界框 xmin max(0.0, min(xmin, img_w - 1)) xmax max(0.0, min(xmax, img_w - 1)) ymin max(0.0, min(ymin, img_h - 1)) ymax max(0.0, min(ymax, img_h - 1)) x_center (xmin xmax) / 2.0 / img_w y_center (ymin ymax) / 2.0 / img_h w (xmax - xmin) / img_w h (ymax - ymin) / img_h lines.append(f{cls_id} {x_center:.6f} {y_center:.6f} {w:.6f} {h:.6f}) # 即使没有目标也要写空文件YOLO 训练要求图像和标签一一对应 with open(os.path.join(DST_LABEL_DIR, stem .txt), w) as f: f.write(\n.join(lines))脚本里有两个关键决策。一是用 PIL 读实际图像尺寸而不是直接用 XML 里的size因为标注工具填的尺寸有时和真实图像不一致尤其是图像被裁剪过之后。二是坐标裁剪到边界内红细胞密集区域经常出现标注框超出图像边缘的情况不裁剪的话归一化后会出现负数或大于 1 的值YOLO 训练时这些框会被当成无效样本丢弃白白浪费标注。4.2 边界坑一坐标越界与负值现象是训练日志里出现大量ignoring invalid bbox或者 loss 突然变成 NaN。原因是标注框的xmax超过了图像宽度归一化后x_center w/2 1。解决就是在转换时做 clamp把坐标限制在[0, img_w-1]和[0, img_h-1]范围内。更稳妥的做法是转换后加一步校验统计所有 TXT 里的坐标范围发现越界就打印文件名。4.3 边界坑二类别名大小写与空格现象是转换后所有标签都是空的或者类别 id 全是 -1。原因是 XML 里的name写的是rbc而脚本里映射的是RBC或者名字前后带了空格。解决是在读取时统一strip().upper()映射表也用大写键。红细胞数据集如果来自不同标注员类别名不一致很常见转换前先跑一遍统计把所有出现过的name值列出来。4.4 边界坑三图像与标注文件名不匹配现象是转换脚本报FileNotFoundError或者转换后 labels 目录里文件数比 images 少。原因是图像是.jpg而标注是.JPG或者文件名里有中文、空格。解决是转换前先做一次文件名对齐用os.path.splitext取 stem 后统一小写比较。如果数据集里确实有图像没有标注要么补标注要么把图像移出训练集不要留着让训练脚本去猜。4.5 边界坑四空标签文件的处理现象是 YOLO 训练启动时报No labels found或者某个 batch 的 loss 为 0。原因是某张图没有目标转换脚本没生成对应的空 TXT。YOLO 的要求是每张图必须有一个同名 TXT哪怕内容是空的。解决就是在循环里无条件写文件lines为空时写空字符串。这一点和 COCO 不同COCO 里没有目标的图可以不出现但 YOLO 不行。5. 红细胞检测训练避坑从 data.yaml 到 BN 崩溃的排查清单格式转好了、数据切好了接下来就是训练。这一章不讲 YOLO 算法原理只讲红细胞数据集训练时实际会遇到的坑。每条按「现象 → 原因 → 解决」写都是我在类似任务里踩过的。5.1 坑一data.yaml 路径写错导致训练集为空现象是训练启动后显示train: 0 images或者 loss 一直是 0。原因是data.yaml里的train和val路径写的是相对路径而训练脚本的工作目录不是数据集根目录。解决是统一用绝对路径或者确认path字段指向数据集根目录train/val写相对于path的子路径。红细胞数据集如果解压后目录层级多建议先把结构整理成images/train、labels/train的标准布局。path: /abs/path/to/rbc_dataset train: images/train val: images/val nc: 1 names: [RBC]5.2 坑二BN 层崩溃与 batch size 的关系现象是训练几个 epoch 后 loss 突然变 NaN日志里出现BatchNorm相关的报错。原因是 batch size 太小红细胞图像分辨率又高BN 层统计量不稳定。解决是先把 batch size 调到 8 以上如果显存不够就降图像尺寸到 640 或 512而不是继续压 batch。另一个办法是改用GroupNorm或者冻结 BN 层但这会改变模型结构不如调 batch 来得直接。5.3 坑三红细胞粘连导致漏检现象是验证集上密集区域的细胞漏检严重指标上 recall 明显低于 precision。原因是红细胞边缘粘连标注框重叠NMS 阶段把相邻框抑制掉了。解决是调低 NMS 的 IoU 阈值从默认 0.45 降到 0.3 左右或者改用 soft-NMS。另外可以在训练时开启 mosaic 增强让模型见到更多密集场景。如果数据集里粘连样本少可以针对性补充。5.4 坑四验证集指标波动大现象是每个 epoch 的 mAP 跳动超过 5 个点没法判断模型是否收敛。原因是验证集太小1000 张图切 10% 只有 100 张统计噪声大。解决是增大验证集比例到 20%或者用交叉验证。另一个原因是数据增强在验证阶段没关YOLO 默认验证不做增强但如果自己改了配置要确认augmentFalse。5.5 坑五混淆矩阵类别错位现象是混淆矩阵里红细胞被预测成背景或者背景被预测成红细胞。原因是类别 id 和names列表顺序不一致。YOLO 的names是列表索引从 0 开始TXT 里的 class_id 必须和索引对应。如果转换脚本里CLASS_MAP写的是{RBC: 1}而names只有一个元素就会错位。解决是转换脚本和data.yaml用同一份类别映射最好从一个配置文件读。6. 把 1000 张图用到极致小样本下的增强策略与验证技巧1000 张图在目标检测里属于小样本红细胞检测又对密集和粘连敏感所以增强策略和验证方法决定了最终指标的上限。这一章讲几个我实际用过、对红细胞任务有效的技巧最后用一个习惯收尾。6.1 针对红细胞的增强组合通用增强里mosaic 和 mixup 对小样本帮助最大但红细胞图像背景单一mosaic 拼接后容易出现不自然的边界建议 mosaic 概率设 0.5 而不是默认的 1.0。颜色抖动要克制红细胞染色差异本身是噪声HSV 的h通道扰动范围设小一点s和v可以稍大。旋转和缩放是必须的红细胞没有固定朝向degrees180可以开scale0.5覆盖不同放大倍数。翻转里水平翻转安全垂直翻转在显微镜图像里也合理都可以开。# Ultralytics 增强配置片段 hsv_h: 0.010 hsv_s: 0.500 hsv_v: 0.300 degrees: 180.0 translate: 0.1 scale: 0.5 shear: 0.0 perspective: 0.0 flipud: 0.5 fliplr: 0.5 mosaic: 0.5 mixup: 0.1参数说明hsv_h压到 0.01 是因为染色色调变化不该被当成特征mosaic降到 0.5 是避免拼接边界干扰mixup开 0.1 增加样本多样性但不至于让图像过于模糊。6.2 用切片推理提升密集区域召回红细胞在图像里分布密集时整图推理容易漏掉小目标。切片推理SAHI的思路是把大图切成有重叠的小块分别推理后再合并。对 1000 张图的数据集训练时不用切片但推理阶段用切片能明显提升 recall。做法是把图像切成 512×512、重叠 128 像素的块每块单独送模型最后用 NMS 合并。代价是推理时间增加但红细胞检测通常不是实时任务这个代价可以接受。6.3 验证时看什么指标mAP 是综合指标但红细胞检测更要看 recall 和每类 AP。如果 recall 低于 0.8说明漏检多优先调 NMS 和切片推理。如果 precision 低说明误检多检查标注里有没有把背景杂质标成红细胞。混淆矩阵要确认背景和红细胞的区分度如果背景被大量预测成红细胞说明负样本不够可以从图像里裁一些无细胞的区域作为背景图加入训练。6.4 一个我坚持的习惯每次改完增强或 NMS 参数我都会固定跑三次训练取指标中位数而不是看单次结果。红细胞数据集小单次训练的随机性很大看单次指标容易做出错误决策。这个习惯让我少走了很多弯路也避免过把偶然的高 mAP 当成调参成果。希望帮到你。本文还有配套的精品资源点击获取
返回列表