胰腺病变分割数据集实战:210张训练图与可视化脚本
发布时间:2026/9/24 23:28:16来源:尧图网络
简介本资源为胰腺病变图像分割数据集面向医学图像分割方向的研究者、算法工程师及深度学习学习者用于训练和评估二类别分割模型背景与病变区域。包内按训练集与测试集组织训练集约210张图像及对应mask测试集约50张图像及对应mask均以images图片目录与masks标签目录成对存放便于直接接入常见分割网络。资源共533个文件以531个png图像与标签为主另含1个txt说明和1个py可视化脚本压缩包约22.58MB体积轻便易于下载与本地部署。配套脚本可随机抽取一张图片将原始图像、GT图像及GT在原图上的蒙板结果一并展示并保存至当前目录方便快速核验标注质量与数据分布。目前已有605人学习下载适合作为分割模型训练、数据预处理与结果可视化的实践素材。1. 胰腺病变分割数据集210 张训练图能跑出什么名堂胰腺病变的自动分割是腹部 CT 影像分析里公认难啃的一块。胰腺本身位置深、形态不规则病变区域又常常和周围组织灰度接近边界模糊。很多做医学图像分割的同行卡在第一步——找不到带标注的胰腺病变数据。公开数据集里胰腺相关的本来就少专门针对病变区域的更稀缺。这份胰腺病变图像分割数据集包含训练集约 210 张、测试集约 50 张每张图片都有对应的 mask 标签分背景和病变区域两类。它适合正在做医学图像分割实验、想验证 U-Net 类网络在胰腺病变上表现的人。数据集还附带一个可视化脚本能随机抽一张图把原图、GT 图和 GT 在原图上的蒙板一起展示出来。拿到手就能直接进训练流程不用再花时间写数据加载和可视化。2. 数据集结构与标签格式先搞清楚目录怎么摆2.1 训练集与测试集的目录组织这份数据集按标准的分割任务目录来组织。训练集和测试集各自独立每个集合下分 images 和 masks 两个目录。images 里放原始医学图像masks 里放对应的二值或灰度标签图。文件名一一对应比如 images 里有 8_50.pngmasks 里就有 8_50.png。这种命名方式在数据加载时可以直接用文件名做键来配对不需要额外维护映射表。常见做法是训练集和测试集的比例控制在 4:1 左右这里 210 对 50 基本符合。训练集用来更新网络权重测试集用来评估泛化能力。注意测试集不能参与任何训练过程包括数据增强的参数拟合。我一般会在代码里把测试集的路径单独写死避免手滑混入训练循环。2.2 标签类别与 mask 像素值数据集标注了两类背景和病变区域。mask 图像通常是单通道灰度图背景像素值为 0病变区域像素值为 1 或 255。具体是 1 还是 255得实际打开一张 mask 看一眼。用 Python 读一下像素分布就能确认import numpy as np from PIL import Image mask np.array(Image.open(masks/8_50.png)) print(unique values:, np.unique(mask)) print(shape:, mask.shape) print(dtype:, mask.dtype)这段代码做三件事读入一张 mask打印所有出现过的像素值打印图像尺寸和数据类型。如果 unique 输出是 [0, 1]说明标签是 0/1 编码如果是 [0, 255]就是 0/255 编码。训练时如果损失函数用的是 BCEWithLogitsLoss标签需要转成 float 且范围在 0 到 1 之间如果用 CrossEntropyLoss标签要是 long 类型且从 0 开始编号。这个细节不确认训练时 loss 可能直接变 NaN血泪经验。2.3 图像尺寸与预处理注意事项医学图像分割里图像尺寸不统一是常态。这份数据集里的图片尺寸需要自己确认。用 PIL 或 OpenCV 批量读一遍统计宽高分布import os from PIL import Image from collections import Counter sizes Counter() for f in os.listdir(train/images): with Image.open(os.path.join(train/images, f)) as im: sizes[im.size] 1 for size, count in sizes.most_common(): print(size, count)如果尺寸集中比如全是 512×512那可以直接 resize 到网络输入尺寸。如果尺寸差异大常见做法是统一 resize 到 256×256 或 512×512同时把 mask 用最近邻插值避免引入不存在的类别值。注意 mask 不能用双线性插值否则边缘会产生 0 和 1 之间的浮点数类别就乱了。3. 可视化脚本拆解随机抽图看原图、GT 和蒙板3.1 脚本要解决的三个展示需求可视化脚本的核心任务很明确随机从数据集里抽一张图把原始图像、GT 标签图、以及 GT 叠加在原图上的蒙板效果三张图并排展示并保存到当前目录。这个脚本在调试阶段非常有用。训练前看一眼原图和 mask 是否对齐训练后看一眼预测结果和 GT 的差异都靠它。我一般会把脚本写成可配置的指定数据集根目录、指定是训练集还是测试集、指定随机种子。这样每次运行结果可复现方便对比不同模型输出。3.2 用 matplotlib 实现三图并排下面是一个可直接运行的脚本框架import os import random import numpy as np import matplotlib.pyplot as plt from PIL import Image def visualize(data_root, splittrain, seed42): random.seed(seed) img_dir os.path.join(data_root, split, images) mask_dir os.path.join(data_root, split, masks) fname random.choice(os.listdir(img_dir)) img np.array(Image.open(os.path.join(img_dir, fname)).convert(RGB)) mask np.array(Image.open(os.path.join(mask_dir, fname)).convert(L)) # 将 mask 二值化确保叠加时只显示病变区域 mask_bin (mask 0).astype(np.uint8) # 构造叠加图原图上病变区域用红色高亮 overlay img.copy() overlay[mask_bin 1] [255, 0, 0] fig, axes plt.subplots(1, 3, figsize(15, 5)) axes[0].imshow(img) axes[0].set_title(Original Image) axes[1].imshow(mask_bin, cmapgray) axes[1].set_title(Ground Truth Mask) axes[2].imshow(overlay) axes[2].set_title(GT Overlay on Image) for ax in axes: ax.axis(off) save_path fvisualization_{split}_{fname} plt.savefig(save_path, bbox_inchestight, dpi150) plt.show() print(fSaved to {save_path}) if __name__ __main__: visualize(., splittrain, seed42)逻辑说明先固定随机种子保证每次抽到同一张图。然后分别读原图和 maskmask 转成灰度后二值化大于 0 的都算病变区域。叠加图是在原图副本上把病变区域的像素直接替换成红色。三张图用 subplots 并排关掉坐标轴保存到当前目录。参数方面data_root 是数据集根目录split 控制用训练集还是测试集seed 控制随机抽取结果。dpi 设 150 够用再高文件会很大。3.3 叠加蒙板的颜色与透明度调整上面脚本用的是硬替换病变区域直接变纯红。如果想看原图细节可以用透明度叠加overlay img.copy().astype(np.float32) red np.zeros_like(overlay) red[:, :, 0] 255 alpha 0.4 overlay[mask_bin 1] (1 - alpha) * overlay[mask_bin 1] alpha * red[mask_bin 1] overlay overlay.astype(np.uint8)alpha 控制红色蒙板的透明度0.4 左右既能看清病变范围又不至于完全遮住原图纹理。这个技巧在写论文配图时特别实用审稿人一眼就能看出分割区域和周围组织的关系。4. 训练集与测试集划分210 张图怎么用才不浪费4.1 训练集内部再分验证集的比例数据集已经给了训练集和测试集但训练过程中还需要一个验证集来监控过拟合。常见做法是从 210 张训练图里再切出 15% 到 20% 做验证也就是 30 到 40 张。切分时要注意类别平衡病变区域大的图和病变区域小的图都要覆盖到。如果随机切分后验证集里全是小病变验证指标会虚高。我一般用 sklearn 的 train_test_split按文件名切不按像素切from sklearn.model_selection import train_test_split import os all_files sorted(os.listdir(train/images)) train_files, val_files train_test_split(all_files, test_size0.15, random_state42) print(ftrain: {len(train_files)}, val: {len(val_files)})random_state 固定后每次切分结果一致。test_size 设 0.15 对应约 31 张验证图。如果后续要做交叉验证可以把这个切分循环多次每次换 random_state取平均指标。4.2 数据增强在胰腺病变上的边界胰腺病变区域通常只占图像的一小部分数据量又只有 210 张不做增强很容易过拟合。但增强不能乱做。翻转、旋转、轻微缩放是安全的因为胰腺的解剖位置不会因为左右翻转就变得不合理。但弹性形变要慎用胰腺和周围器官的相对位置有解剖约束形变太强会生成不真实的样本。常见做法是用 Albumentations 库把增强定义成一个管道import albumentations as A train_transform A.Compose([ A.HorizontalFlip(p0.5), A.RandomRotate90(p0.5), A.ShiftScaleRotate(shift_limit0.05, scale_limit0.1, rotate_limit15, p0.5), A.Resize(256, 256), ])参数说明HorizontalFlip 概率 0.5RandomRotate90 概率 0.5ShiftScaleRotate 的平移限制 0.05、缩放限制 0.1、旋转限制 15 度都是比较保守的值。Resize 放在最后统一到 256×256。注意增强要同时作用于 image 和 maskAlbumentations 的 Compose 会自动处理只要把 image 和 mask 一起传进去。4.3 测试集的使用时机与评估指标测试集只在模型训练完成、超参数确定之后用一次。用之前不能看测试集的任何统计信息包括像素分布、病变大小分布。评估指标方面医学图像分割常用 Dice 系数和 IoU。Dice 对类别不平衡更敏感胰腺病变这种小目标场景Dice 比像素准确率更有参考价值。计算 Dice 的代码def dice_coef(pred, target, smooth1e-6): pred pred.contiguous().view(-1) target target.contiguous().view(-1) intersection (pred * target).sum() return (2. * intersection smooth) / (pred.sum() target.sum() smooth)smooth 防止分母为零。pred 是经过 sigmoid 后的概率图通常以 0.5 为阈值二值化后再算。如果验证集 Dice 在 0.7 以上测试集 Dice 掉到 0.6 以下说明过拟合严重得回头加增强或减模型复杂度。5. 避坑与排查胰腺分割训练里最容易翻车的几件事5.1 现象loss 一直不降Dice 停在 0.1 左右原因最常见的是标签编码和损失函数不匹配。mask 像素值是 0 和 255直接喂给 BCEWithLogitsLoss标签没归一化到 0 到 1梯度会爆炸或消失。另一个可能是图像和 mask 没对齐比如 images 里是 8_50.pngmasks 里却是 8_50_mask.png文件名对不上加载时全读成空白。解决先跑一遍 2.2 节的像素值检查确认 mask 取值范围。如果 mask 是 0/255在 Dataset 的getitem里除以 255。文件名配对用 os.path.splitext 去掉扩展名后再拼不要硬编码后缀。5.2 现象训练集 Dice 很高测试集 Dice 很低原因数据量小模型记住了训练样本。210 张图对深度网络来说太少了尤其是如果用了 ResNet 之类的预训练编码器参数量远大于样本量。另一个原因是增强太弱或者验证集和训练集分布差异大。解决加强增强把 ShiftScaleRotate 的概率提到 0.7加一点高斯噪声。或者换更轻量的编码器比如用 MobileNet 做 backbone。还可以加 Dropout 和权重衰减。如果测试集本身和训练集来自不同设备或不同扫描参数那得考虑域适应不是简单调参能解决的。5.3 现象可视化脚本保存的图全黑或全白原因mask 读进来是单通道但 imshow 默认用 viridis 色图0 和 1 的对比度不够。或者原图是 16 位灰度PIL 读进来后没归一化imshow 显示时被截断。解决mask 显示时指定 cmapgray并且确保 mask_bin 是 0 和 1 的 uint8。原图如果是 16 位先转成 8 位再显示img np.array(Image.open(path)) img ((img - img.min()) / (img.max() - img.min()) * 255).astype(np.uint8)这个归一化对 CT 图像特别重要因为 CT 的 HU 值范围可能从 -1000 到 3000直接显示就是一片黑。5.4 现象训练到一半 loss 突然变 NaN原因学习率太大或者某张图的 mask 全为 0Dice loss 的分母变成 smooth 主导梯度异常。胰腺病变数据集里如果某张图没有病变区域mask 就是全黑这种样本在训练时要么剔除要么给一个极小的权重。解决先把学习率降到 1e-4 甚至 1e-5用 AdamW 优化器。然后在 Dataset 里过滤掉 mask 全零的样本或者统计一下有多少张全零 mask。如果全零样本占比超过 5%说明数据集标注可能有问题得回头确认。5.5 现象测试集评估时 Dice 波动很大原因测试集只有 50 张单张图的 Dice 方差大平均下来不稳定。另外如果病变区域特别小预测偏几个像素Dice 就从 0.8 掉到 0.3。解决报告指标时同时给出均值和标准差不要只报一个平均值。可以按病变大小分层统计小病变、中等病变、大病变各算一组 Dice。这样能看出模型到底在哪个尺度上表现差。如果小病变 Dice 特别低考虑在损失函数里加 Focal Loss 或者 Tversky Loss加大对小目标的惩罚。6. 从这份数据集到自己的分割流程一个可复用的验证习惯拿到一份新数据集我现在的习惯是先跑三件事再动模型。第一件用 2.2 节的代码确认标签编码和图像尺寸。第二件用第 3 章的可视化脚本随机抽 5 张图肉眼确认原图和 mask 对齐。第三件用 4.1 节的切分代码把训练集再分出一个验证集固定随机种子。这三步走完再开始搭网络。这份胰腺病变数据集的价值在于它把最耗时的数据整理和标注环节省掉了。210 张训练图不算多但足够验证一个分割网络的基本可行性。测试集 50 张用来做最终评估也够用。可视化脚本虽然简单但省去了自己写 matplotlib 排版的时间。如果你打算在这个数据集上做实验我建议先用一个轻量 U-Net 跑通全流程Dice 能到 0.6 以上再换更复杂的模型。不要一上来就上 Transformer 或者 nnU-Net数据量撑不住调参时间会成倍增加。等基线跑通了再逐步加增强、换损失函数、调学习率策略。每一步只改一个变量记录验证集 Dice 的变化。这样即使最后效果不理想你也清楚是哪个环节拖了后腿。从那以后我每次拿到新的分割数据集都强制走一遍「查标签、看对齐、切验证」这三步再也没出现过训练到一半发现标签读错的情况。希望帮到你。本文还有配套的精品资源点击获取
网站建设高端定制企业官网