简介:这份腹部14器官分割数据集面向医学图像分割方向的学习者与研究者,尤其适合正在做3D UNet、nnUNet等腹部多器官分割实验的同学。数据以3D医学nii.gz格式提供,共30个样本及对应标签,可用ITK-SNAP直接打开查看,标注覆盖背景、脾脏、右肾、左肾、胆囊、食道、肝脏、胃、主动脉、下腔静脉、门静脉和脾静脉、胰腺、左右肾上腺共14类,具体英文类别可参考随包json文件。资源包共61个文件,以60个gz数据与标签文件和1个json类别说明为主,压缩包约953.26MB,采用7z格式打包,目录结构清晰,便于按训练集与标签集分别读取。目前已有713人学习下载,适合需要真实腹部CT标注数据来搭建分割流程、验证模型效果或复现相关UNet项目的读者参考使用。
1. 腹部14器官分割数据集:从 nii.gz 文件到 3D 医学分割的第一道门槛
拿到一个腹部 14 器官分割数据集,很多人第一反应是直接喂给模型,结果卡在第一步——nii.gz 文件打不开,或者打开了发现方向不对、标签对不上、层厚不一致。腹部 14 器官分割数据集(基于 3D 的医学 nii.gz 格式)本质上是一批带体素级标注的 CT 或 MRI 容积数据,覆盖肝、脾、肾、胰、胃、胆囊、食管、肾上腺、十二指肠、空肠、回肠、结肠、直肠、膀胱等腹腔与盆腔器官。它的核心价值在于:你不需要从零标注,可以直接用来训练 3D 分割网络,比如 nnU-Net、V-Net、Swin UNETR 这类架构。适合谁?做医学影像 AI 的算法工程师、影像组学研究者、以及想把 2D 分割经验迁移到 3D 的深度学习从业者。但前提是,你得先搞懂 nii.gz 这个格式的脾气,否则后面全是玄学。
2. nii.gz 格式拆解与 3D 医学数据的读取逻辑
2.1 为什么医学分割偏爱 nii.gz 而不是 png 序列
nii.gz 是 NIfTI 格式的 gzip 压缩版本,它把三维容积数据、仿射矩阵、体素间距、方向信息打包在一个文件里。和 png 序列相比,它不会丢失层间距信息,也不会因为文件名排序错误导致层面错位。腹部 CT 的层厚通常是 0.5 到 5 毫米不等,层内像素间距可能是 0.6 到 1.0 毫米,这种各向异性的体素在 nii.gz 里由 pixdim 字段精确记录。如果你把它转成 png 序列再读回来,这些信息就丢了,模型会把 5 毫米层厚和 0.6 毫米层内间距当成等向的,分割边界直接糊掉。常见做法是用 nibabel 或 SimpleITK 读取,保留原始仿射矩阵,后续做重采样和归一化时才有依据。
2.2 用 Python 读取 nii.gz 并检查关键元数据
import nibabel as nib import numpy as np # 读取图像和标签 img = nib.load('case_001_ct.nii.gz') label = nib.load('case_001_seg.nii.gz') # 获取数据数组,注意 dtype 和形状 img_data = img.get_fdata() # float64,形状 (X, Y, Z) label_data = label.get_fdata() # float64,标签通常是整数 # 关键元数据检查 print('图像形状:', img_data.shape) print('体素间距:', img.header.get_zooms()) # (sx, sy, sz) print('仿射矩阵:\n', img.affine) print('标签唯一值:', np.unique(label_data)) print('图像强度范围:', img_data.min(), img_data.max())这段代码的逻辑是先加载两个文件,然后分别检查形状、体素间距、仿射矩阵和标签值。get_fdata()返回 float64 数组,对于标签建议用np.asanyarray(label.dataobj)避免不必要的类型转换。体素间距的第三个值就是层厚,如果它和层内间距差异大,说明数据是各向异性的,后续训练时要么做重采样到等向,要么在数据增强时注意不要在 Z 轴做大幅旋转。标签唯一值必须核对,腹部 14 器官的标签通常是 1 到 14,如果出现 0 以外的非整数,说明标注文件有问题。图像强度范围用于判断是否需要做窗宽窗位调整,腹部 CT 的 HU 值通常在 -1000 到 3000 之间,但有些数据集已经做过归一化,范围可能是 0 到 1。
2.3 仿射矩阵与方向:最容易翻车的地方
仿射矩阵决定了体素坐标到世界坐标的映射,也决定了你看到的图像方向。不同扫描仪、不同重建软件导出的 nii.gz 可能带有不同的方向编码,比如 RAS、LAS、LPS。如果你直接用 matplotlib 的imshow看某一层,可能发现图像是上下颠倒或左右镜像的。更严重的是,如果图像和标签的仿射矩阵不一致,即使形状相同,体素也可能对不上。我一般会先做一次方向统一,用nib.as_closest_canonical()把图像转到 RAS 方向,同时用同样的变换处理标签。注意,这个操作会改变数据数组的形状,所以必须在重采样之前做。另一个坑是,有些数据集的标签仿射矩阵是单位矩阵,而图像是真实仿射,这种情况下标签和图像的空间对应关系是错的,需要手动把图像的仿射赋给标签,或者用resample_from_to做对齐。
3. 从原始 nii.gz 到可训练张量:预处理流水线怎么搭
3.1 重采样到统一体素间距:选 1.5mm 还是 2.0mm
腹部 14 器官分割的公开数据集里,原始层厚差异很大。有的薄层 CT 是 0.5mm,有的常规 CT 是 5mm。直接混合训练会导致模型对层厚敏感,薄层数据学到的细节在厚层数据上失效。常见做法是把所有数据重采样到统一的体素间距,比如 1.5mm × 1.5mm × 1.5mm 或 2.0mm × 2.0mm × 2.0mm。选 1.5mm 能保留更多细节,但显存占用大;选 2.0mm 显存友好,但对小器官如肾上腺、胆囊的分割精度会下降。我一般会先统计数据集的体素间距分布,如果大部分数据层厚在 1mm 到 3mm 之间,就选 1.5mm;如果很多数据层厚超过 3mm,选 2.0mm 更稳妥。重采样用 SimpleITK 的ResampleImageFilter,插值方式:图像用线性插值,标签用最近邻插值,否则标签会出现小数。
import SimpleITK as sitk def resample_image(image, target_spacing, is_label=False): original_spacing = image.GetSpacing() original_size = image.GetSize() target_size = [ int(round(original_size[i] * original_spacing[i] / target_spacing[i])) for i in range(3) ] resampler = sitk.ResampleImageFilter() resampler.SetSize(target_size) resampler.SetOutputSpacing(target_spacing) resampler.SetOutputOrigin(image.GetOrigin()) resampler.SetOutputDirection(image.GetDirection()) resampler.SetInterpolator( sitk.sitkNearestNeighbor if is_label else sitk.sitkLinear ) return resampler.Execute(image)这段代码的核心是计算目标尺寸,保持物理尺寸不变。target_size是原始物理长度除以目标间距,四舍五入取整。SetOutputOrigin和SetOutputDirection保持和原图一致,避免空间错位。插值器选择是关键:标签必须用最近邻,否则会出现 1.5 这种无意义的标签值。图像用线性插值,虽然会轻微模糊,但比最近邻的锯齿好。重采样之后,图像的形状会变,标签的形状必须和图像完全一致,可以用sitk.Resample对标签做同样的操作,或者用resample_from_to把标签重采样到图像空间。
3.2 窗宽窗位调整与强度归一化:腹部 CT 的 HU 值怎么处理
腹部 CT 的原始 HU 值范围很大,从空气的 -1000 到骨骼的 1000 以上。但腹部器官的软组织对比度主要集中在 -100 到 200 之间。如果直接把原始 HU 值喂给网络,模型会被骨骼和空气的高对比度吸引,忽略软组织边界。常见做法是做窗宽窗位裁剪,比如腹部窗设为 WL=40, WW=400,对应范围是 -160 到 240。裁剪之后再做归一化到 [0, 1] 或 z-score 标准化。我一般会先裁剪到 [-160, 240],然后除以 400 映射到 [0, 1]。注意,这个操作只对图像做,标签不动。有些数据集已经做过归一化,范围是 0 到 1,这时候不要再做窗宽窗位,否则会破坏原始对比度。判断方法很简单:看图像强度范围,如果 min 接近 -1000,就是原始 HU;如果 min 接近 0,就是已经归一化过。
3.3 数据增强:3D 场景下哪些增强不能乱用
2D 分割里常用的随机旋转、翻转、缩放,在 3D 医学数据里要谨慎。腹部器官有固定的解剖位置,肝在右上腹,脾在左上腹,如果做左右翻转,肝脏跑到左边,模型会学到错误的解剖先验。所以左右翻转不能用,上下翻转也不能用。随机旋转要限制角度,一般 ±15 度以内,否则器官会转到不自然的位置。缩放可以做,但要注意保持体素间距的物理意义,缩放后要重新计算 spacing。弹性形变可以用,但幅度要小,否则会把器官边界扭曲得不像真实解剖。我一般会用的增强包括:随机旋转 ±10 度、随机缩放 0.9 到 1.1、随机弹性形变(控制点间距 30mm,形变幅度 5mm)、随机亮度对比度扰动。注意,所有增强必须同时作用于图像和标签,标签用最近邻插值。
4. 避坑与排查:腹部 14 器官分割数据处理的 5 个血泪教训
4.1 标签值不连续,模型输出全零
现象:训练时 loss 一直不降,预测结果全是背景。原因:标签文件里器官的标签值不是 1 到 14 连续整数,而是比如 1, 2, 3, 5, 8, 13,中间缺了 4, 6, 7。模型输出通道数按 14 设,但实际有效类别只有 6 个,交叉熵计算时大量通道没有正样本,梯度被背景主导。解决:先统计所有标签文件的唯一值,取并集,重新映射成 0 到 N 的连续整数,保存映射表。推理时再映射回去。
4.2 图像和标签形状不一致,广播报错
现象:数据加载时报错,说图像和标签形状不匹配。原因:图像和标签在重采样时用了不同的目标尺寸,或者一个做了方向统一另一个没做。解决:所有空间变换必须成对操作,图像和标签用同一个变换矩阵。建议写一个apply_transform(image, label, transform)函数,确保两者始终同步。
4.3 层厚差异导致小器官消失
现象:胆囊、肾上腺在厚层数据上分割 Dice 接近 0。原因:厚层数据层厚 5mm,小器官在 Z 轴只有两三层,重采样到 1.5mm 后虽然层数变多,但信息是插值出来的,没有新增细节。解决:对小器官做单独评估,如果数据集中厚层数据占比高,考虑在损失函数里给小器官更高权重,或者用两阶段分割,先定位再细分。
4.4 仿射矩阵单位化导致空间错位
现象:图像和标签看起来形状一样,但叠加显示时器官位置偏移。原因:标签的仿射矩阵是单位矩阵,而图像是真实仿射。解决:用nibabel的resample_from_to把标签重采样到图像空间,或者手动把图像的 affine 赋给标签,前提是形状一致。
4.5 显存爆炸,batch size 只能设 1
现象:3D 数据直接输入网络,显存不够,batch size 降到 1 还是 OOM。原因:3D 卷积的显存占用是 2D 的立方级增长。解决:用 patch-based 训练,从每个容积里随机裁剪 128×128×128 或 96×96×96 的 patch,batch size 可以设 2 到 4。推理时用滑窗,重叠率 0.5。另外,混合精度训练和梯度检查点也能省显存。
5. 用 nnU-Net 跑通腹部 14 器官分割:从数据准备到推理的完整命令
nnU-Net 是目前医学分割里最省心的框架,它自动处理体素间距、patch size、网络深度等超参数。但前提是数据格式要符合它的要求。你需要把 nii.gz 文件整理成特定目录结构,每个病例一个文件夹,里面放_0000.nii.gz图像和.nii.gz标签。标签值必须是连续整数,背景为 0。然后运行nnUNetv2_plan_and_preprocess做预处理,它会自动重采样到中位体素间距,并生成 patch 配置。训练用nnUNetv2_train,推理用nnUNetv2_predict。我一般会先跑 2D 配置做快速验证,再跑 3D 全分辨率。注意,nnU-Net 默认用 5 折交叉验证,如果数据量少,可以只跑单折。推理时用--save_probabilities保存概率图,方便后续做后处理。最后用nnUNetv2_evaluate_folder算 Dice 和 HD95。这套流程跑通后,腹部 14 器官的平均 Dice 通常能到 0.85 以上,小器官如胆囊、肾上腺可能在 0.6 到 0.7 之间。如果小器官指标太低,可以试试在 nnU-Net 的损失函数里加 focal loss,或者用 Tversky loss 调整 FP/FN 权重。我自己踩过的坑是,nnU-Net 对标签值很敏感,如果标签里有 15 或 -1,它会直接报错,所以预处理第一步就是清洗标签。希望帮到你。
本文还有配套的精品资源,点击获取