
简介这份脑肿瘤实例分割医疗影像数据集面向医学影像AI开发者、算法研究人员及放射科教学人员用于构建脑肿瘤自动识别与病灶定位系统解决医学图像分割中标注数据稀缺、边界模糊样本不足的问题。资源包共2000个文件以829张jpg医学影像和1169个txt标注文件为主另含1个yaml数据配置与1份docx说明文档压缩包约30.6MB原生适配YOLOv5/v7/v8等实例分割框架。数据按训练集803张、验证集237张、测试集129张划分采用多边形坐标点精确标注Brain_Tumor类别涵盖胶质瘤、脑膜瘤等多种肿瘤类型标注经三甲医院放射科医师双重校验并保留肿瘤异质性与边界模糊等临床特征。已有171人学习下载读者可据此训练UNet、Mask R-CNN等模型开展病灶量化分析与三维重建研究也可作为医师培训的标准化教学素材。1. 脑肿瘤实例分割数据集从拿到 .zip 到跑出第一张掩码你从公开渠道拿到一个名为「脑肿瘤实例分割医疗影像数据集.zip」的压缩包解压后大概率是一堆 NIfTI 或 PNG 文件外加几个 JSON 或 CSV 标注。真正让人头疼的不是模型选型而是搞清楚这批数据到底能不能直接喂给 YOLO 实例分割或 Mask R-CNN。脑肿瘤影像的实例分割和自然图像完全不是一个玩法T1、T1ce、T2、FLAIR 四个模态对齐肿瘤边界模糊增强区域和水肿区域经常粘连一个患者可能对应多张切片切片之间还不能随便打散。这篇笔记就按我实际处理这类数据集的顺序从目录结构判断、格式转换、标签生成一路写到训练参数和验证方法。适合手里已经拿到压缩包、准备做脑肿瘤实例分割但还没跑通第一轮训练的人也适合想评估这批数据值不值得投入的团队做参考。2. 先看懂压缩包里的目录结构再动手2.1 脑肿瘤实例分割数据集常见的三种组织方式拿到压缩包先别急着写 DataLoader解压后第一件事是tree -L 3或find . -maxdepth 3 -type d看目录层级。脑肿瘤实例分割数据集常见三种组织方式不同方式决定你后面走哪条转换路径。第一种是按患者 ID 分目录每个患者文件夹下放四个模态文件加一个标注文件类似BraTS风格。这种结构最适合做 3D 滑窗训练但如果你要用 YOLO 实例分割做 2D 切片训练需要自己按切片展开并保证同一患者的切片不跨 train/val 泄漏。第二种是已经切成 2D PNG 或 JPG按images/和masks/分开mask 是灰度图或彩色索引图。这种最省事但要注意 mask 是实例掩码还是语义掩码——实例分割要求每个肿瘤子区域有独立 ID如果所有肿瘤都标成同一个灰度值你拿到的是语义分割数据不能直接当实例分割用。第三种是 COCO JSON 或 VIA 标注图像和标注分离。这种需要先解析 JSON 里的category_id和segmentation字段确认标注是多边形还是 RLE。脑肿瘤边界不规则多边形标注点太少会丢细节RLE 更常见。# 快速摸清目录结构重点看有没有患者级文件夹和标注文件 find . -maxdepth 3 -type d | head -50 find . -name *.json -o -name *.csv -o -name *.nii* | head -30 # 统计图像数量和格式分布 find . -type f \( -name *.png -o -name *.jpg -o -name *.nii -o -name *.nii.gz \) | wc -l上面命令先看目录层级再找标注文件最后统计图像格式。如果find结果里.nii.gz占多数说明是 3D 体数据后面必须做切片展开如果全是.png重点转向检查 mask 的像素值分布。2.2 判断标注是实例级还是语义级这一步直接决定你能不能叫它「实例分割数据集」。用 Python 读一张 mask看唯一像素值。import numpy as np from PIL import Image mask np.array(Image.open(masks/case_001_slice_045.png)) unique_vals, counts np.unique(mask, return_countsTrue) print(唯一像素值:, unique_vals) print(各值像素数:, counts) # 如果唯一值只有 0 和 1大概率是二值语义掩码 # 如果出现 1,2,3 或 10,20,30 这类可能是实例 ID 或类别 ID逻辑说明np.unique返回 mask 里所有不同像素值。如果只有 0 和 1说明所有肿瘤区域被合并成一个前景这是语义分割标注不是实例分割。如果出现多个非零值且每个值对应一个独立连通区域才是实例级标注。参数上注意有些数据集用 255 表示前景用 1、2、3 表示不同实例需要看数据集说明或标注 JSON 里的categories字段确认。提示如果确认是语义掩码但你又必须做实例分割可以用连通域分析把相邻但不相连的肿瘤区域拆成不同实例但粘连区域无法自动拆分需要人工复核。3. 把 3D 体数据转成 YOLO 实例分割可用的 2D 切片3.1 NIfTI 读取与切片展开的最小脚本脑肿瘤数据集很多是 NIfTI 格式四个模态配准到同一空间。做 2D 实例分割时我一般选 T1ce 或 FLAIR 作为主模态因为增强肿瘤在 T1ce 上对比度最高水肿在 FLAIR 上最明显。下面脚本把 3D 体数据按轴向切片展开成 PNG同时保留患者 ID 和切片号。import os import numpy as np import nibabel as nib from PIL import Image def nii_to_slices(nii_path, mask_path, out_img_dir, out_mask_dir, modalityt1ce): img_vol nib.load(nii_path).get_fdata() mask_vol nib.load(mask_path).get_fdata() # 按轴向切片切片数取第三维 for z in range(img_vol.shape[2]): img_slice img_vol[:, :, z] mask_slice mask_vol[:, :, z] # 跳过全黑切片减少无效样本 if img_slice.max() 0: continue # 归一化到 0-255脑肿瘤 MRI 常用百分位裁剪 p1, p99 np.percentile(img_slice, (1, 99)) img_slice np.clip(img_slice, p1, p99) img_slice ((img_slice - p1) / (p99 - p1 1e-8) * 255).astype(np.uint8) mask_slice (mask_slice 0).astype(np.uint8) * 255 case_id os.path.basename(nii_path).split(.)[0] Image.fromarray(img_slice).save(f{out_img_dir}/{case_id}_z{z:03d}.png) Image.fromarray(mask_slice).save(f{out_mask_dir}/{case_id}_z{z:03d}.png) nii_to_slices(data/case_001_t1ce.nii.gz, data/case_001_seg.nii.gz, out/images, out/masks)逻辑说明nib.load读取 NIfTI 文件get_fdata()返回浮点数组。切片方向选第三维是常见做法但脑肿瘤有时需要冠状面或矢状面取决于肿瘤位置。百分位裁剪用 1% 和 99% 分位数避免极端亮斑拉低整体对比度。跳过全黑切片能减少大量无效样本脑肿瘤数据集里空切片比例可能超过一半。参数上modality变量只是标记用途实际读哪个文件由nii_path决定。3.2 从 mask 生成 YOLO 实例分割标签YOLO 实例分割要求每个实例一行格式为class_id x1 y1 x2 y2 ... xn yn坐标归一化到 0-1。如果 mask 是实例级标注直接用cv2.findContours提取轮廓。import cv2 import numpy as np def mask_to_yolo(mask_path, img_w, img_h, class_id0): mask cv2.imread(mask_path, cv2.IMREAD_GRAYSCALE) # 二值化假设非零为前景 _, binary cv2.threshold(mask, 1, 255, cv2.THRESH_BINARY) contours, _ cv2.findContours(binary, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) lines [] for cnt in contours: # 过滤太小的轮廓脑肿瘤边缘噪声多 if cv2.contourArea(cnt) 20: continue # 多边形简化减少点数但保留形状 epsilon 0.002 * cv2.arcLength(cnt, True) approx cv2.approxPolyDP(cnt, epsilon, True) points approx.reshape(-1, 2) # 归一化坐标 norm_points [(x / img_w, y / img_h) for x, y in points] coords .join([f{x:.6f} {y:.6f} for x, y in norm_points]) lines.append(f{class_id} {coords}) return lines逻辑说明cv2.findContours用RETR_EXTERNAL只取外轮廓避免内孔产生多余实例。approxPolyDP做多边形简化epsilon设为周长的 0.002 倍这个值太大丢边界细节太小则点数过多。面积过滤阈值 20 像素是经验值脑肿瘤切片里经常有零星噪声点。归一化坐标保留 6 位小数YOLO 训练时对精度不敏感但格式必须统一。注意如果 mask 是语义掩码findContours会把所有肿瘤区域当成一个实例。需要先用连通域分析拆分但粘连区域无法自动分开这是脑肿瘤实例分割数据集最常见的坑。4. 训练参数怎么设YOLO 实例分割在脑肿瘤上的调参记录4.1 输入尺寸、batch size 与模态选择脑肿瘤 MRI 切片常见尺寸是 240×240 或 512×512。YOLO 实例分割默认 640×640直接 resize 会拉伸变形。我一般保持长宽比做 letterbox或者直接把输入设为 256×256 或 320×320因为肿瘤区域通常只占图像一小部分太大分辨率反而让模型关注背景。参数推荐值说明imgsz256 或 320脑肿瘤切片小太大浪费显存batch8 或 16取决于显存256 尺寸下 8GB 显存可跑 16epochs100-200医疗数据少需要多轮但早停lr00.001比自然图像低避免震荡mosaic0.5 或关闭脑肿瘤切片拼接会破坏解剖结构fliplr0.5水平翻转可用垂直翻转慎用degrees0旋转会引入插值伪影不建议模态选择上如果数据集提供 T1ce 和 FLAIR我一般用 T1ce 做主模态因为增强肿瘤边界清晰。如果要做多模态融合可以把 T1ce 和 FLAIR 叠成三通道或六通道但 YOLO 默认三通道需要改第一层卷积。4.2 从 COCO 格式转 YOLO 格式的完整命令如果数据集给的是 COCO JSON用官方脚本转换最稳。# 假设 COCO 标注在 annotations/instances_train.json python -c from ultralytics.data.converter import convert_coco convert_coco( labels_dirannotations/, use_segmentsTrue, save_dirdatasets/brain_tumor/ ) 逻辑说明convert_coco是 ultralytics 提供的转换工具use_segmentsTrue表示输出实例分割标签而不是检测框。labels_dir指向包含 JSON 的目录save_dir是输出根目录转换后会生成labels/train和labels/val。参数上注意COCO JSON 里的category_id从 1 开始YOLO 要求从 0 开始转换脚本会自动减 1但如果你自己写转换代码这一步容易漏。转换完成后检查标签文件行数和图像数量是否一致再写 data.yaml。# data.yaml path: datasets/brain_tumor train: images/train val: images/val nc: 1 names: [tumor]nc是类别数脑肿瘤实例分割通常只分肿瘤和非肿瘤如果数据集区分增强区、水肿区、坏死区nc改成 3 并对应修改names。4.3 训练启动与关键监控指标yolo segment train datadata.yaml modelyolov8n-seg.pt epochs150 imgsz320 batch16 lr00.001 patience30model选 nano 或 small 版本先跑通医疗数据量通常不大大模型容易过拟合。patience30表示 30 轮验证指标不提升就早停。训练时重点看metrics/mAP50-95(M)这是掩码 mAP比检测框 mAP 更能反映实例分割质量。如果掩码 mAP 远低于框 mAP说明轮廓回归有问题检查标签多边形点数是否太少或太多。5. 避坑与排查脑肿瘤实例分割数据集处理中的 5 个翻车点5.1 现象训练 loss 正常下降但掩码预测全是背景原因标签文件里坐标没有归一化或者归一化用了错误的宽高。脑肿瘤切片展开后图像尺寸和原始 NIfTI 尺寸不一致如果归一化时用了原始尺寸坐标会全部偏到图像外。解决在生成标签前打印一张图的宽高确认和标签归一化用的宽高一致。用cv2.imread读图后取shape[1]和shape[0]不要用 NIfTI 的 shape。5.2 现象验证集 mAP 很高但推理时一个肿瘤都检测不到原因训练集和验证集按切片随机划分同一患者的相邻切片同时出现在两边。相邻切片高度相似模型记住了患者特征而不是肿瘤特征。解决按患者 ID 划分 train/val确保同一患者的切片只出现在一个集合。如果数据集已经切好切片从文件名提取患者 ID 再分组。5.3 现象mask 轮廓锯齿严重掩码 mAP 上不去原因approxPolyDP的 epsilon 设太大或者原始 mask 分辨率太低。脑肿瘤边界模糊轮廓点太少会丢失浸润区域。解决epsilon 降到 0.001 或直接用原始轮廓点同时确认 mask 和图像同分辨率。如果 mask 是低分辨率上采样来的考虑在损失函数里对边界区域加权。5.4 现象训练到一半 loss 突然变成 NaN原因学习率太高或者输入图像里有全黑切片导致归一化除零。脑肿瘤数据集里空切片多如果没过滤干净百分位裁剪时 p99 可能等于 p1。解决在归一化前加判断if p99 - p1 1e-6: continue。学习率从 0.001 降到 0.0005 再试。5.5 现象多模态输入时模型只学会其中一个模态原因不同模态灰度分布差异大简单叠通道后模型偏向对比度高的模态。T1ce 增强区域亮FLAIR 水肿亮直接拼接会让模型忽略 FLAIR。解决每个模态单独做百分位归一化后再拼接或者用两个分支分别提特征再融合。YOLO 改多通道输入需要改第一层卷积的in_channels并重新初始化该层权重。6. 验证实例分割质量除了 mAP 还要看什么mAP 是标准指标但脑肿瘤实例分割里 mAP 高不代表临床可用。我一般额外看三个东西边界 Dice 系数、实例数量误差、以及小肿瘤召回率。边界 Dice 系数专门算预测掩码和真实掩码在边界区域的 overlap。做法是把真实掩码和预测掩码都做形态学膨胀和腐蚀取差值得到边界带再算 Dice。这个指标对浸润性肿瘤特别敏感因为 mAP 对内部填充不敏感边界错了 mAP 可能只掉一点但 Dice 会明显下降。import cv2 import numpy as np def boundary_dice(pred_mask, gt_mask, kernel_size5): kernel np.ones((kernel_size, kernel_size), np.uint8) pred_boundary cv2.dilate(pred_mask, kernel) - cv2.erode(pred_mask, kernel) gt_boundary cv2.dilate(gt_mask, kernel) - cv2.erode(gt_mask, kernel) intersection np.logical_and(pred_boundary, gt_boundary).sum() return 2.0 * intersection / (pred_boundary.sum() gt_boundary.sum() 1e-8)kernel_size控制边界带宽度脑肿瘤切片上一般取 3 到 7太小对边界偏移不敏感太大则退化成整体 Dice。实例数量误差看预测出的肿瘤个数和真实个数差多少。脑肿瘤经常出现一个患者多个病灶如果模型把两个相邻病灶合并成一个mAP 可能还行但实例数量误差会暴露问题。小肿瘤召回率单独统计面积小于 100 像素的实例这批样本在 mAP 里权重低但临床上小病灶恰恰不能漏。我自己的习惯是每轮验证都保存预测掩码可视化图按患者 ID 分组看。有一次 mAP 到 0.78 觉得可以了结果可视化发现模型把所有肿瘤都预测得比真实大一圈边界 Dice 只有 0.52。后来把损失函数里边界区域的权重调高mAP 掉到 0.74但边界 Dice 升到 0.68临床同事反而觉得后者更可用。医疗影像实例分割指标好看和实际可用之间经常有 gap多看一眼可视化图能省很多后悔药。希望帮到你。本文还有配套的精品资源点击获取