news 2026/9/24 18:07:58

乳腺细胞癌症分割数据集实战:50张图跑通医学图像分割全流程

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
乳腺细胞癌症分割数据集实战:50张图跑通医学图像分割全流程

简介:本资源面向医学图像分割方向的初学者与算法实践者,提供一套乳腺细胞癌症分割的二分类数据集,可用于训练与验证语义分割网络,帮助解决医学影像中病灶区域自动提取的入门实验需求。压缩包共103个文件,以png图像为主(101个),另含1个txt类别说明与1个py可视化脚本,整体约23.91MB,采用7z格式打包。数据分为训练集与测试集:训练集含40张原图及40张对应mask,测试集含10张原图及10张mask,图像分辨率统一为512×512,mask为0与255的阈值图像,0代表背景、255代表癌症细胞,具体类别可在classes文本中查看。配套脚本无需修改即可直接运行,随机抽取一张图片,将原始图像、GT图像以及GT在原图上的蒙板结果一并展示并保存至当前目录,便于直观核对标注质量。目前已有207人学习下载,适合作为分割模型训练、掩膜可视化与数据预处理的练手素材。

1. 乳腺细胞癌症分割数据集:50 张图里藏着医学图像分割的完整闭环

医学图像分割入门最卡脖子的从来不是模型结构,而是找不到一份干净、带标注、能直接跑通的小数据集。公开的息肉分割、皮肤病变数据集动辄几百上千张,下载慢、标注格式杂,光做数据清洗就能劝退一批人。这份乳腺细胞癌症分割数据集走的是另一条路:50 张 512×512 的 PNG 图像,训练集 40 张、测试集 10 张,每张图配一张同尺寸的 mask 标签,像素值只有 0 和 255 两种,0 是背景、255 是癌症细胞。它小到能在笔记本上几分钟跑完一轮,又完整到包含 images、masks、classes 文本和一份可视化脚本,适合刚接触医学图像分割、想先把「读数据—看标签—训模型—验结果」这条链路走通的人。下面按我实际拆包的顺序讲清楚它怎么用、参数怎么设、哪里容易翻车。

2. 拆开数据包:目录结构、标签语义与可视化脚本怎么跑

2.1 目录结构与文件命名规律

拿到压缩包解压后,常见的目录组织是这样:

breast_cancer_seg/ ├── train/ │ ├── images/ # 40 张原图,png │ └── masks/ # 40 张对应 mask,png ├── test/ │ ├── images/ # 10 张原图 │ └── masks/ # 10 张对应 mask ├── classes.txt # 标签类别说明 └── visualize.py # 可视化脚本

文件名是07_1.png04_8.png10_1.png这种「编号_序号」的形式,images 和 masks 两个目录里同名文件一一对应。这一点很关键:做分割训练时,图像和标签必须靠文件名配对,任何一张图找不到同名 mask,训练时就会报FileNotFoundError或者更隐蔽地读到上一批缓存。我一般会先跑一遍配对检查,确认两边文件名集合完全相等再往下走。

import os img_dir = "train/images" mask_dir = "train/masks" imgs = {os.path.splitext(f)[0] for f in os.listdir(img_dir) if f.endswith(".png")} masks = {os.path.splitext(f)[0] for f in os.listdir(mask_dir) if f.endswith(".png")} print("仅图片有:", imgs - masks) print("仅标签有:", masks - imgs) print("配对成功:", len(imgs & masks))

这段代码用集合差集找出单边存在的文件。os.path.splitext去掉扩展名后比较,避免.png大小写或多余后缀干扰。正常输出应该是两个空集合加一个 40。如果差集非空,先手动补齐或删掉孤立文件,别带着脏数据进训练。

2.2 mask 的像素语义与 classes.txt

这份数据集的 mask 是单通道阈值图,像素分布只有 0 和 255。0 对应背景,255 对应癌症细胞区域。classes.txt里记录了具体类别,常见是两行,一行背景一行前景。这里有个新手最容易踩的点:很多人拿到 mask 直接除以 255 当标签,结果发现模型输出全是 0。原因是 255/255=1,看起来没问题,但如果用某些框架的CrossEntropyLoss,它期望的是类别索引 0/1 的整型张量,而不是 0/1 的浮点。正确做法是先确认任务类型——二分类分割用BCEWithLogitsLoss配 0/1 浮点标签,多分类用CrossEntropyLoss配 0/1 整型标签。

import numpy as np from PIL import Image mask = np.array(Image.open("train/masks/07_1.png")) print("shape:", mask.shape) # (512, 512) 或 (512, 512, 3) print("unique:", np.unique(mask)) # 期望 [0, 255] print("前景像素占比:", (mask == 255).mean())

np.unique是验证标签语义最快的手段。如果输出里出现 128、200 这类中间值,说明 mask 被做过抗锯齿或压缩,需要重新二值化。前景占比能帮你判断样本是否极度不平衡——乳腺细胞分割里前景往往只占几个百分点,后面选损失函数时要考虑这一点。

2.3 可视化脚本的运行与输出解读

数据集自带的visualize.py是随机抽一张图,把原图、GT 掩膜、GT 叠加在原图上的蒙版三张图并排展示,并保存到当前目录。脚本不需要改路径就能跑,前提是你解压后直接在数据集根目录执行。

cd breast_cancer_seg python visualize.py

运行后当前目录会多出一张拼接图。三栏分别是:原始 RGB 图像、纯黑白 mask、红色半透明叠加图。叠加图是判断标注质量的关键——如果红色区域明显溢出到细胞外的空白区,或者漏掉了明显的细胞团,说明这份标注本身有噪声,训练时要么接受这个上限,要么手动修几张。我一般会连跑几次脚本,随机多看几张,对整体标注风格有个印象再开训。脚本里通常用matplotlibsubplot做拼接,alpha参数控制叠加透明度,想调得更清楚可以把它从 0.5 改到 0.3。

3. 把数据喂进模型:从 Dataset 到训练循环的落地写法

3.1 自定义 Dataset 的同步增强

50 张图属于极小样本,直接训必然过拟合。常见做法是在 Dataset 里做在线增强,但分割任务有个铁律:图像和 mask 必须用同一组随机参数做几何变换,否则标签就错位了。用albumentations可以一次性同步处理。

import cv2 import numpy as np import albumentations as A from torch.utils.data import Dataset class BreastSegDataset(Dataset): def __init__(self, img_dir, mask_dir, size=512): self.img_dir = img_dir self.mask_dir = mask_dir self.names = sorted(os.listdir(img_dir)) self.tf = A.Compose([ A.Resize(size, size), A.HorizontalFlip(p=0.5), A.VerticalFlip(p=0.5), A.RandomRotate90(p=0.5), A.ShiftScaleRotate(shift_limit=0.05, scale_limit=0.1, rotate_limit=15, p=0.5), ]) def __len__(self): return len(self.names) def __getitem__(self, idx): name = self.names[idx] img = cv2.imread(os.path.join(self.img_dir, name)) img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) mask = cv2.imread(os.path.join(self.mask_dir, name), 0) mask = (mask > 127).astype(np.float32) # 二值化到 0/1 out = self.tf(image=img, mask=mask) img = out["image"].astype(np.float32) / 255.0 img = img.transpose(2, 0, 1) # HWC -> CHW return torch.from_numpy(img), torch.from_numpy(out["mask"]).unsqueeze(0)

A.Compose里的几何变换会同时作用于 image 和 mask,这是分割增强和分类增强最大的区别。mask > 127把 255 压成 1,同时容忍轻微压缩噪声。transpose(2,0,1)是 PyTorch 要求的通道前置格式,忘了这步会报维度不匹配。unsqueeze(0)给 mask 补一个通道维,配合BCEWithLogitsLoss使用。

3.2 损失函数与评价指标的选择

前景占比低的时候,纯 BCE 容易被背景主导,模型学会全预测 0 就能拿到很高的像素准确率,但 IoU 惨不忍睹。常见做法是 BCE 加 Dice 的混合损失。

import torch import torch.nn as nn class BCEDiceLoss(nn.Module): def __init__(self, bce_weight=0.5): super().__init__() self.bce = nn.BCEWithLogitsLoss() self.bce_weight = bce_weight def forward(self, logits, targets): bce_loss = self.bce(logits, targets) probs = torch.sigmoid(logits) inter = (probs * targets).sum(dim=(2, 3)) union = probs.sum(dim=(2, 3)) + targets.sum(dim=(2, 3)) dice = (2 * inter + 1e-6) / (union + 1e-6) dice_loss = 1 - dice.mean() return self.bce_weight * bce_loss + (1 - self.bce_weight) * dice_loss

bce_weight控制两项的配比,0.5 是常用起点。Dice 里的1e-6防止空 mask 导致除零。评价指标建议直接算 IoU 和 Dice,别只看 loss,因为 loss 下降不代表分割边界变好。验证时把torch.sigmoid(logits) > 0.5作为预测掩膜,和 GT 比。

3.3 训练循环与显存控制

512×512 的图,batch size 设 4 在 8G 显存上比较稳,设 8 可能就 OOM。训练轮数不用太多,50 张图 100 到 200 轮足够看到收敛趋势。

from torch.utils.data import DataLoader import torch.optim as optim train_ds = BreastSegDataset("train/images", "train/masks") train_loader = DataLoader(train_ds, batch_size=4, shuffle=True, num_workers=2) model = ... # 常见选 U-Net 或轻量 DeepLabV3+ model = model.cuda() criterion = BCEDiceLoss().cuda() optimizer = optim.Adam(model.parameters(), lr=1e-3) for epoch in range(150): model.train() for img, mask in train_loader: img, mask = img.cuda(), mask.cuda() optimizer.zero_grad() logits = model(img) loss = criterion(logits, mask) loss.backward() optimizer.step()

num_workers=2在 Windows 上偶尔会卡死,遇到就改成 0。学习率 1e-3 配 Adam 是安全起点,如果 loss 震荡就降到 3e-4。每 10 轮存一次权重,小数据集上过拟合来得快,早停比硬训到底更划算。

4. 避坑与排查:这份数据集上最容易翻车的五件事

4.1 现象:训练 loss 正常下降,但预测全是黑图

原因通常是标签没二值化,mask 读进来还是 0/255,BCEWithLogitsLoss把 255 当成极大正样本,梯度爆炸后模型输出饱和。解决:在 Dataset 里强制(mask > 127).astype(np.float32),并在第一个 batch 打印mask.max()确认是 1.0。

4.2 现象:可视化脚本报FileNotFoundError

原因是没在数据集根目录执行,脚本里用的是相对路径。解决:cd到解压后的根目录再跑,或者把脚本里的路径改成绝对路径。别在别的目录用python /path/to/visualize.py,相对路径会以当前工作目录为基准。

4.3 现象:图像和 mask 尺寸对不上,报维度错误

512×512 是标准尺寸,但个别图可能被工具重新保存成 513 或 511。解决:在 Dataset 里统一A.Resize(512, 512),别依赖原始尺寸一致。同时检查 mask 是不是三通道,三通道 mask 要取单通道再二值化。

4.4 现象:验证集 IoU 远低于训练集

50 张图里训练 40、测试 10,测试集太小,单张图波动就能让指标跳十几个点。解决:别把测试集当唯一标准,从训练集里再切 8 张做验证,或者做 5 折交叉验证。小数据集上报告单一 IoU 数字意义有限,多看几张预测叠加图更实在。

4.5 现象:增强后 mask 出现灰色边缘

原因是用了带插值的几何变换,mask 被双线性插值出中间值。解决:几何变换对 mask 用最近邻插值,albumentations默认对 mask 就是最近邻,但如果你手动用cv2.resize就要显式指定interpolation=cv2.INTER_NEAREST

5. 小数据集的进阶玩法:交叉验证、伪标签与边界后处理

50 张图想榨出更多信息,单次训练切分太浪费。我一般会做 5 折交叉验证:把 50 张图分成 5 份,每份 10 张轮流当验证集,其余 40 张训练。这样每个样本都参与过验证,指标更稳,还能顺带产出 5 个模型做集成。集成时把 5 个模型的 sigmoid 输出平均再阈值化,边界通常比单模型干净。

import numpy as np def ensemble_predict(models, img): probs = [torch.sigmoid(m(img)).cpu().numpy() for m in models] mean_prob = np.mean(probs, axis=0) return (mean_prob > 0.5).astype(np.uint8)

阈值 0.5 不是金科玉律。医学分割里如果更怕漏检,把阈值降到 0.3 能提高召回,代价是误检增多。可以画一条不同阈值下的 Dice 曲线,挑拐点。

另一个技巧是伪标签:用训练好的模型在测试集 10 张图上预测,把置信度高的预测当额外标签,和原训练集合并再训一轮。小数据集上这招偶尔能涨一两个点,但前提是初始模型别太差,否则错误会被放大。我一般只在 Dice 已经过 0.7 之后才尝试。

边界后处理也值得一试。预测出的 mask 常有孤立小噪点,用形态学开运算去掉,再保留最大连通域,能明显改善视觉效果。

import cv2 def postprocess(mask): kernel = np.ones((3, 3), np.uint8) mask = cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernel) num, labels, stats, _ = cv2.connectedComponentsWithStats(mask) if num > 1: largest = 1 + np.argmax(stats[1:, cv2.CC_STAT_AREA]) mask = (labels == largest).astype(np.uint8) return mask

MORPH_OPEN先腐蚀后膨胀,去掉小噪点。connectedComponentsWithStats找出所有连通域,保留面积最大的那个。注意如果一张图里确实有多个独立细胞团,这步会误删,所以先看几张可视化结果再决定要不要加。

从那以后我每次拿到新的分割数据集,都强制先跑一遍配对检查、np.unique看标签、可视化脚本随机抽三张,这三步走完再写训练代码。这份乳腺细胞癌症分割数据集规模小、结构清晰,正好适合把这套流程固化成习惯。希望帮到你。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/24 18:07:42

Python实现Disco Diffusion本地图像生成:原理、配置与实战

简介:基于Python的Disco Diffusion图像生成工具,将CLIP语义理解与扩散模型结合,可根据文本提示直接生成高质量图像,面向AI绘画爱好者、设计师及深度学习初学者;项目对原始代码做了简化和修改,降低了上手门槛…

作者头像 李华
网站建设 2026/9/24 18:07:09

LSTM排放预测实战:从时序切片到在线微调的落地指南

简介:本资源面向本科及以上阶段、具备一定MATLAB基础的学生与研究人员,提供一套基于长短期记忆神经网络(LSTM)的汽车排放量预测完整实现方案。汽车排放数据本质上属于时间序列,相比普通前馈神经网络,LSTM在…

作者头像 李华
网站建设 2026/9/24 18:06:36

单图重建实战:神经3D网络渲染器全流程解析

简介:这份资源面向计算机视觉方向的学习者与开发者,聚焦从单张二维图像恢复三维结构的实战项目,借助神经3D网络渲染器完成建模与渲染,适合具备一定深度学习基础、希望深入理解单图重建流程的中高级读者。压缩包共28个文件&#xf…

作者头像 李华
网站建设 2026/9/24 18:06:35

JavaWeb经典实战:Servlet直连MySQL宿舍管理系统开发与避坑指南

简介:这是一套面向Java Web初学者的ServletJSPMySQL宿舍管理系统实战源码,适合刚接触Web开发、需要完整小项目练手的学生与自学者。系统实现用户注册登录及宿舍信息的增删改查,涵盖Servlet处理请求、JSP渲染页面、JDBC连接MySQL等核心环节&am…

作者头像 李华
网站建设 2026/9/24 18:06:17

茶叶叶片病害图像分类:如何用4,000张已标注图片训出高精度ResNet模型

简介:面向茶叶叶片病害识别与图像分类实验,这份数据集提供了覆盖褐枯病、灰枯萎病、红点病等5个常见类别的已标注叶片图像,适合计算机视觉初学者、农业信息化研究者及CNN模型调优人员使用。数据已划分为训练集、验证集和测试集,各…

作者头像 李华
网站建设 2026/9/24 18:03:50

Python空气质量数据挖掘与可视化分析系统实战

简介:本资源面向环境科学、数据挖掘与机器学习方向的学习者与研究者,提供一套基于Python的空气质量数据可视化分析系统源码及配套数据,可用于城市群划分、污染传输网络构建与传播过程探索等课题实践。压缩包共约2000个文件,以1295…

作者头像 李华