简介面向医学影像分析与目标检测开发者的YOLO11血液细胞图像检测资源包聚焦血涂片中的血小板、红细胞与白细胞识别辅助血液疾病诊断。包内整合三百六十四张已标注的血液细胞图像提供文本标签与可扩展标记语言标签两套格式并预先划分训练集、验证集与测试集同时包含配套的配置文件可直接用于多个版本目标检测算法的训练。资源中还提供训练好的模型权重、基于Python的脚本以及使用教程文档覆盖数据准备、模型训练、推理评估等主要环节便于快速复现工作或迁移至自定义数据集。压缩包共一千八百五十四个文件以教程文档、样本图像、标签文件、脚本、配置与权重等类型为主整体大小约六十四兆字节目录结构清晰方便按需检索。目前已有九十三人学习适合具备一定Python基础的医学影像初学者或目标检测研究者直接上手。1. 用 ultralytics-yolo11 拆一套血液细胞检测364 张图的 BCCD 才是真正要解决的问题血液细胞图像的目标检测过去总被当成“数据不够就玩不动”的典型但这套 ultralytics-yolo11 检测和分析血液细胞图像资源里BCCD 数据集只有 364 张标注图却能把血小板、红细胞、白细胞三类目标完整跑通。真正难的不是模型是数据集格式、类别不平衡和部署路径三段。这个压缩包同时给了 YOLO txt 和 VOC xml 两种标签划分好了 train/val/test附 data.yaml 和训练好的权重适合的目标很明确想用 yolo11 做细胞检测、又不想花两周整理标注格式的从业者或新手。它是医工交叉检测一个很低的入门门槛检测结果也能为辅助血液疾病诊断里的细胞计数统计提供前端支撑。2. 先拆 BCCD 数据集两种标注格式、data.yaml 和目录划分2.1 拿到压缩包后第一件事把目录铺开这个包解压以后建议先别急着装 ultralytics而是把数据目录完整看一遍。BCCD 是血液细胞检测里很常用的公开基准集资源作者已经帮你做了最繁琐的工作图像统一放 imagesYOLO 标签按 txt 格式放 labelsVOC 标签按 xml 格式放 annotationstrain/val/test 三个划分也已经切好。压缩包里还有 inference.cpp、main.cc 这样的 C 部署入口文件以及训练时自动生成的 labels.cache后者在第 5 章会专门讲它的坑。我一般会先跑一次目录树把脑中的地图建起来BCCD/ ├── images/ │ ├── train/ # 约 250 张 │ ├── val/ # 约 60 张 │ └── test/ # 约 50 张 ├── labels/ │ ├── train/ # 与 images/train 同名同前缀的 txt │ ├── val/ │ └── test/ ├── annotations/ # VOC 格式 xmlv5/v8/v11 训练时不直接读 ├── data.yaml # 训练入口配置 └── labels.cache # 训练时自动生成的标签缓存这段结构的意义在于images 和 labels 的目录名、图片名前缀必须严格一致YOLO 训练时是靠“同名不同后缀”去找标签的。如果两者对不上训练会直接报 File not found 或者 image 无标签警告。2.2 三种细胞的检测任务差异BCCD 的类别不多只有三类但检测难度差别很大。先看看这三类在实际检测里分别难在哪类别英文名标签下标检测难点血小板Platelets0尺寸小很容易漏检红细胞RBC1密度高细胞之间粘连严重白细胞WBC2数量少样本极度不均衡这三类在辅助血液疾病诊断场景里的作用也不一样血小板数量异常和凝血功能相关红细胞数量对应贫血方向白细胞则和感染、炎症相关。但注意一点目标检测只负责“框出来 数出来”不是直接下诊断结论做工程落地时这个边界要拎清。可以用几行 Python 快速统计训练集里每个类别的目标数确认数据分布from pathlib import Path from collections import Counter names [Platelets, RBC, WBC] counter Counter() for txt in Path(BCCD/labels/train).glob(*.txt): for line in txt.read_text().strip().splitlines(): if not line.strip(): continue cls int(float(line.split()[0])) counter[names[cls]] 1 print(counter)这段代码读的是 YOLO txt 标签的第一列类别编号逐文件统计后你会发现 WBC 的数量可能只有 RBC 的十分之一甚至更少。训练策略就得针对这个不均衡做调整否则模型会倾向于把一切深色、有核的细胞都判成 RBC。2.3 看清 txt 和 xml 的对应关系YOLO 训练直接读 txt每行五个数字类别、归一化中心点 x、归一化中心点 y、归一化宽、归一化高。全部是 0 到 1 之间的比例值不是像素坐标。label_path Path(BCCD/labels/train/BloodImage_00001.txt) for line in label_path.read_text().strip().splitlines(): cls, cx, cy, w, h map(float, line.split()) print(fclass{int(cls)} cx{cx:.4f} cy{cy:.4f} w{w:.4f} h{h:.4f})这里 cx 是相对图像宽度的比例cy 是相对图像高度的比例。比如 cx0.5 代表目标中心在图像水平正中间和图像尺寸无关这是 YOLO 格式最核心的设计。VOC xml 则记录的是绝对像素坐标bndbox 节点下面 xmin、ymin、xmax、ymax 四个值直接对应原图坐标。解析 xml 的常见做法import xml.etree.ElementTree as ET xml_path BCCD/annotations/BloodImage_00001.xml root ET.parse(xml_path).getroot() img_w float(root.find(size/width).text) img_h float(root.find(size/height).text) for obj in root.findall(object): name obj.find(name).text box obj.find(bndbox) xmin float(box.find(xmin).text) ymin float(box.find(ymin).text) xmax float(box.find(xmax).text) ymax float(box.find(ymax).text) cx (xmin xmax) / 2 / img_w cy (ymin ymax) / 2 / img_h w (xmax - xmin) / img_w h (ymax - ymin) / img_h print(name, fyolo: {cx:.4f} {cy:.4f} {w:.4f} {h:.4f})如果你后续要往 VOC 格式迁移反推公式就是xmin (cx - w/2) * img_w其余同理。这个小脚本值得留着因为不少公开数据集只给一种格式跨格式迁移时它就是后悔药。2.4 data.yaml 里必须检查的两个字段data.yaml 是整个训练链路的入口配置压缩包里已经给了一份但直接拿去训练大概率会因为路径问题翻车。YOLO11 的 data.yaml 推荐写法是带 path 根目录# data.yaml path: D:/datasets/BCCD # 改成你自己的绝对路径 train: images/train val: images/val test: images/test nc: 3 names: 0: Platelets 1: RBC 2: WBC这里最容易踩的坑是 path 没改。很多人解压到某个目录后直接 yolo train结果 YOLO 在默认工作目录下找不到 images 目录。我一般会直接把 path 写成绝对路径train/val 保持相对路径这样不管从哪个目录启动训练都不会出错。nc 和 names 的顺序也要核对。BCCD 的标签 txt 是按 0Platelets、1RBC、2WBC 编的data.yaml 里的 names 顺序必须完全一致。一旦错位比如把 RBC 写成下标 0训练不会报错但模型学的东西全是错的而且你很难从 loss 曲线看出来。3. ultralytics 环境与训练参数从 yolo11n 起步的可复现配置3.1 安装 ultralytics 的正确姿势如果你之前用 yolov8 训练过自己的数据集对 ultralytics 这套接口应该很熟。BCCD 这套标签格式对 v5/v8/v9/v10/v11/v12 通吃但既然手头是 yolo11 资源我建议直接用 ultralytics 最新版。安装之前先建独立虚拟环境这是最快减少环境冲突的办法conda create -n yolo11 python3.10 -y conda activate yolo11 # GPU 用户先装对应版本的 torch以 CUDA 12.1 为例 pip install torch torchvision --index-url https://download.pytorch.org/whl/cu121 # 再装 ultralytics pip install ultralytics -i https://pypi.tuna.tsinghua.edu.cn/simple注意 Python 版本必须落在 3.8 到 3.12 之间超过 3.12 很容易出现第 5 章要讲的 could not find a version 报错。装完先跑一次官方预训练权重验证环境yolo predict modelyolo11n.pt sourcehttps://ultralytics.com/images/bus.jpg能输出一张带框的 bus.jpg说明环境就绪。这一步五分钟值得花避免把环境问题误判成数据和代码问题。3.2 为什么从 yolo11n 起步而不是直接上 yolo11s 或 xBCCD 只有 364 张图属于典型的小数据目标检测场景。模型容量越大过拟合风险越高。yolo11n 参数量最小、训练最快适合先把数据链路跑通确认 loss 能正常下降。yolo11s 可以作为第二轮实验专门看 WBC 召回率有没有提升。模型参数量级适用判断yolo11n最小首选跑通流程、确认收敛yolo11s中等WBC 召回不足时升级yolo11m/x较大数据量撑不住不建议直接用这套取舍逻辑也适用于其他目标检测数据集。先小模型验证“数据没问题、标签没问题、训练能收敛”再用大模型刷精度比一上来就大模型跑三天划算得多。3.3 训练命令和关键参数含义环境就绪后用下面的命令启动训练yolo detect train \ modelyolo11n.pt \ dataD:/datasets/BCCD/data.yaml \ epochs120 \ imgsz640 \ batch16 \ device0 \ workers4 \ cacheTrue \ projectruns/bccd \ nameyolo11n_bccdmodelyolo11n.pt 表示加载 COCO 预训练权重做迁移学习。BCCD 和 COCO 差距很大但迁移学习仍然能显著加速收敛这是目标检测小数据集的标准做法比从随机权重训练稳得多。参数值理由epochs120BCCD 很小训练很快配合早停不会浪费imgsz640默认值若 RBC 密集尺度漏检可升 960batch168GB 显存的保守值OOM 就降到 8cacheTrue把标签缓存进内存提速明显workers4Windows 下如果报 DataLoader 错误改成 2 或 0训练过程中看 runs/bccd/yolo11n_bccd/results.png 里的 box_loss 和 cls_loss正常情况两条曲线都在前 20 个 epoch 快速下降之后缓慢收敛。如果 loss 全程不动优先检查 data.yaml 的 path 和 label 目录名。3.4 权重选择best.pt 还是 last.pt训练结束后weights 目录下有两个权重best.pt 和 last.pt。best.pt 是验证集 mAP 最高的一轮last.pt 是最后一轮。绝大多数场景直接用 best.pt但有一个例外如果你打算接着用更多数据继续训练last.pt 更适合作为起点因为 best.pt 可能对应较早的 epoch学习率状态不太连续。微调时我一般会在 best.pt 基础上继续训但关闭预训练权重加载避免学习率跳变yolo detect train \ modelruns/bccd/yolo11n_bccd/weights/best.pt \ dataD:/datasets/BCCD/data.yaml \ epochs60 \ imgsz960 \ batch8这张命令本质是把 imgsz 从 640 提到 960专门应对小尺寸血小板漏检问题。图像分辨率提升后小目标在特征图上的像素占比变大漏检率通常会明显下降。4. 拿到 best.pt 之后Python 推理、导出 ONNX 与 C 部署入口4.1 Python 端推理和细胞计数训练好的权重可以直接用 ultralytics 的 Python API 跑推理这是最快看到效果的方式from ultralytics import YOLO import numpy as np model YOLO(runs/bccd/yolo11n_bccd/weights/best.pt) results model.predict( sourceD:/datasets/BCCD/images/test, conf0.25, iou0.45, imgsz640, saveTrue, save_txtTrue, projectruns/bccd/predict, nametest, ) for r in results: if r.boxes is None: continue clss r.boxes.cls.cpu().numpy().astype(int) counts np.bincount(clss, minlength3) print(f{r.path}: Platelets{counts[0]} RBC{counts[1]} WBC{counts[2]})conf0.25 是置信度阈值低于这个值的框会被过滤。在这套细胞数据上血小板置信度通常偏低我一般会单独把血小板场景的 conf 降到 0.2 再对比一轮用召回率换误检率。iou0.45 是 NMS 的 IoU 阈值细胞粘连程度高时可以把 iou 提到 0.5减少重叠框被误删的概率。这个计数循环可以直接输出每张图三类细胞的数量正是辅助血液疾病诊断里最需要的“统计”环节。4.2 导出 ONNX部署前的关键一步要把模型从 Python 搬走第一步是导出 ONNXyolo export \ modelruns/bccd/yolo11n_bccd/weights/best.pt \ formatonnx \ imgsz640 \ opset12 \ simplifyTrueopset12 对 onnxruntime 的兼容性比较稳simplifyTrue 会调用 onnxsim 去掉一些冗余计算。导出成功后模型文件从 .pt 变成 .onnx之后就可以脱离 PyTorch 环境部署。4.3 C 推理骨架inference.cc 到底在做什么压缩包里带了 inference.cpp、main.cc、config 这样的文件说明作者预留了 C 部署入口。常见做法是拿 ONNX Runtime 加载模型整个流程分三步预处理、推理、后处理。C 端最容易写错的就是预处理这里给出骨架#include onnxruntime_cxx_api.h #include opencv2/opencv.hpp cv::Mat letterbox(const cv::Mat src, int target 640) { float scale std::min((float)target / src.cols, (float)target / src.rows); cv::Mat resized, canvas(target, target, CV_8UC3, cv::Scalar(114, 114, 114)); cv::resize(src, resized, cv::Size(), scale, scale, cv::INTER_LINEAR); resized.copyTo(canvas(cv::Rect((target - resized.cols) / 2, (target - resized.rows) / 2, resized.cols, resized.rows))); return canvas; }letterbox 的核心是保持宽高比缩放四周用 114 灰度填充到 640×640。这里 114 是 YOLO 系列模型训练时的填充默认值和 Python 端的预处理必须完全一致。后处理时把输出坐标减去 padding再除以 scale才能还原到原图坐标。YOLO11 的 ONNX 输出形状是 1×(4nc)×8400nc3 时就是 1×7×8400。8400 来自 80×80、40×40、20×20 三个特征图相加。每一列代表一个候选框前 4 行是 cx、cy、w、h后 3 行是三个类别的得分没有单独的 objectness 分数这点和 YOLOv5 不同。4.4 快速验证直接用 val 命令看底数如果暂时不写代码只想确认训练好的模型质量直接跑验证命令yolo detect val \ modelruns/bccd/yolo11n_bccd/weights/best.pt \ dataD:/datasets/BCCD/data.yaml \ splittest \ conf0.25 \ iou0.5命令执行完会输出 mAP50、mAP50-95 和各类别 AP并生成混淆矩阵图。先看 mAP50 是否达到可接受水平再看 WBC 那一行的召回率。WBC 作为少数类如果 AP 明显低于 RBC训练阶段的类别不均衡就体现在这里了。5. BCCD 实战避坑五个我翻过车的地方5.1 pip install ultralytics 报 could not find a version that satisfies the requirement现象在某个 Python 环境里执行 pip install ultralytics提示 ERROR: Could not find a version that satisfies the requirement ultralytics后面还跟着 from versions: none。原因ultralytics 对 Python 版本有要求通常是 Python 3.8 到 3.12。如果当前环境是 Python 3.13 及以上或者 pip 版本太老PyPI 上找不到匹配 wheel就会报这个错。解决先升级 pip再看 Python 版本python -m pip install --upgrade pip python --version版本不对就重建虚拟环境用 conda 固定 Python 3.10再装 torch 和 ultralytics。装完用 yolo predict 验证一次确认 import 级正常。5.2 训练时 File not found 或 image 无标签警告现象启动训练后报错找不到 data.yaml或者大量输出 WARNING 提示某张图片没有标签但 labels 目录里文件明明存在。原因data.yaml 里的 path 是相对路径而实际工作目录不在数据集根目录或者 images 和 labels 目录名不匹配YOLO 只认 images 同级目录下的 labels。解决把 data.yaml 的 path 改成绝对路径并确认 train 的值是 images/train 而不是 label 路径。标签缺失的图直接从数据集里删掉不要留着否则训练时会反复警告并拖慢速度。5.3 labels.cache corrupted 导致训练中断现象第一次训练正常第二次改动数据集后启动训练报 CACHE 文件 corrupted 或者 cache 与标签不一致。原因YOLO 会把标签校验结果缓存到 labels.cache 文件里下次训练直接加载缓存跳过校验。但数据集内容变了旧缓存没有同步失效。解决找到数据集根目录下的 labels.cache 删掉重新训练会自动重建。我现在的习惯是每次增删图片或修改 txt 标签直接先删缓存再启动训练提前规避。5.4 WBC 样本太少训练完 WBC 的召回率特别低现象混淆矩阵里 RBC 的 AP 很高WBC 的召回率只有 RBC 的一半甚至更低测试集上 WBC 漏检严重。原因BCCD 里 WBC 数量远少于 RBC模型在训练时对 WBC 的特征学习不足。这是数据不均衡导致的不是模型 bug。解决常见做法是分三步走。第一步把 imgsz 提到 960让白细胞核的纹理更容易被提取。第二步对 WBC 标注做重复采样把 WBC 样本复制几份放进训练集但注意要配合随机增强否则只是重复记忆。第三步使用 mixup 增强让模型在混合样本里学习判别特征。数据增强参数可以这样加yolo detect train \ modelruns/bccd/yolo11n_bccd/weights/best.pt \ dataD:/datasets/BCCD/data.yaml \ epochs60 \ imgsz960 \ batch8 \ mixup0.3 \ fliplr0.5mixup0.3 表示有 30% 的概率对两张图做混合比单纯复制样本更抗过拟合。WBC 召回率上来了再看 RBC 有没有被误伤动态调整 mixup 比例。5.5 C 推理和 Python 结果不一致现象同一张测试图Python 端检测出 15 个目标C 端只输出 8 个或者框的位置整体偏移。原因两端预处理不一致。常见差异包括 letterbox 填充值不是 114、缩放插值方式不同、图像通道顺序 RGB/BGR 反了、归一化时用 255 还是 1.0以及推理后的 dequantize 类型不对。解决用一张固定测试图把两端的输出全部 dump 成 numpy 或者 txt 逐列比对。先对比第一层的输入 tensor 是否数值一致再对比输出 tensor 是否一致。输入差 0.001 就能导致输出差好几个框。C 端我一般固定用 OpenCV 读图 BGR、letterbox 填充 114、除以 255 转 float32和 Python 端保持同一套公式不再各自调参。6. 收尾验证用 val 指标和 ONNX 对比拦住部署翻车6.1 三个必须看的指标模型训练完不要只看 loss 曲线就说“训好了”。我每次都会跑一遍完整评估重点盯三个数字mAP0.5、mAP0.5:0.95、以及每个类别的召回率。from ultralytics import YOLO model YOLO(runs/bccd/yolo11n_bccd/weights/best.pt) m model.val(splittest, conf0.25, iou0.5, plotsTrue) print(mAP0.5:, m.box.map50) print(mAP0.5:0.95:, m.box.map) print(per-class:, m.box.ap_class_index, m.box.ap)plotsTrue 会在验证目录生成 confusion_matrix.png 和 PR 曲线。看混淆矩阵时重点看 WBC 这一行被误判成 RBC 的样本越多说明类别不均衡问题越严重。这三个数字会成为你后续调参的基准线每次改动只允许一个指标变差否则回滚。6.2 导出前后的 golden 对比一张图拦住 90% 的部署翻车C 端部署最大的风险是“练好的模型到了 C 端就变了个模型”。我的习惯是导出 ONNX 前后拿固定的一张测试图做一次输出对比。先用 Python 记录 ONNX Runtime 的输出作为基准再让 C 端输出同一张图的同一维度结果做数值比较。import onnxruntime as ort import cv2 import numpy as np def make_blob(img, target640): h, w img.shape[:2] scale min(target / w, target / h) nw, nh int(w * scale), int(h * scale) resized cv2.resize(img, (nw, nh), interpolationcv2.INTER_LINEAR) canvas np.full((target, target, 3), 114, dtypenp.uint8) top (target - nh) // 2 left (target - nw) // 2 canvas[top:topnh, left:leftnw] resized blob canvas.transpose(2, 0, 1)[None].astype(np.float32) / 255.0 return canvas, scale, left, top img cv2.imread(demo.jpg) canvas, scale, left, top make_blob(img) sess ort.InferenceSession(best.onnx, providers[CPUExecutionProvider]) input_name sess.get_inputs()[0].name out sess.run(None, {input_name: blob})[0] print(output shape:, out.shape) print(first column:, out[0, :, 0])这段代码里 letterbox 的 left、top 偏移被显式记录后处理时直接用它们还原坐标。C 端同样存这两个值就能保证两端的坐标还原逻辑一致。第一列的 7 个数字是第一个候选框的 cx、cy、w、h 和三个类别得分直接对比这 7 个数字是否一致比看最终框更底层、更可靠。从那以后我每次做检测类项目都强制走一遍固定流程先统计类别分布再核 data.yaml然后小模型跑通收敛最后导出前后做一次 golden 对比。这四个动作能拦住九成以上的翻车现场。希望帮到你。本文还有配套的精品资源点击获取
阅读完成 · 觉得有帮助?