恒美微站 Logo 恒美微站
  • 首页
  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心
  • 联系我们

nii.gz 3D MRI脊椎分割:预处理、训练与避坑全指南

  • 首页
  • 资讯中心
  • /
  • nii.gz 3D MRI脊椎分割:预处理、训练与避坑全指南

相关资讯

基于SpringBoot的社区智能垃圾管理系统完整实战解析 2026/10/10 13:45:52
a2a-types:Python实现A2A协议的类型层,规范Agent通信 2026/10/10 13:45:51
云厂商 MaaS 五强对决:2026 大模型 API 平台横评与迁移指南 2026/10/10 13:40:51

最新资讯

UI自动化跳过登录的工程化实践:五种方案与避坑指南
php数组合并的二种方法
信创测试中的异常场景设计与故障注入实战
50.8k 星怎么来的:一个纯 Markdown 文件比插件传播快,三个结构性原因
Python爬虫到DCGAN人脸生成:数据清洗决定模型上限的完整链路
港科大工学院MSc体验日全记录:课程选择与申请关键点解析

今日推荐

Codex 总用英文回答?从 AGENTS.md 到 config.toml 的中文输出调优指南
OpenClaw 自定义插件开发完整指南(2026最新版):从 TypeScript 到 npm 发布
基于Spark的电影推荐系统全链路实战:从爬虫到Web展示

本周热门

MR25H40CDF + PIC18F65K40:工业记录仪高可靠存储实战
基于STM32的数控恒压恒流电源设计:从硬件到PID调参全解析
LT9211 MIPI重定时器原理与双路扇出实战指南

本月精选

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证
2026 大模型集体涨价:用 Python 做企业 Token 成本测算与选型避坑(附配置)

nii.gz 3D MRI脊椎分割:预处理、训练与避坑全指南

发布时间:2026/10/10 13:45:52
nii.gz 3D MRI脊椎分割:预处理、训练与避坑全指南 简介用于脊椎SPINE分割、MRI三维分割任务的数据集采用医学影像标准nii.gz格式存储面向医学影像分析与深度学习方向的开发者、研究者及研究生可直接用于模型训练、算法验证或相关课题研究特别适合从事3D医学图像分割工作的算法工程师进行实验对比与效果评估。压缩包共222个文件其中220个为nii格式图像从命名规律看包含原始MRI扫描文件与对应分割标注另附1个txt索引说明和1个dataset.json配置文件便于了解数据组织方式与任务定义整体包体约374.58MB兼顾样本量与下载便携性。目前已有299人浏览学习适合需要脊椎分割基准数据、开展消融实验或完成课程设计/毕业设计的医学图像算法学习者。数据文件编号清晰、目录结构直观实践中可省去繁琐的格式转换与预处理时间使开发者能将更多精力放在分割网络优化、Loss设计及最终评估上。1. 拿到一批nii.gz的3D MRI脊椎分割数据先别急着训练先弄清楚spine数据长什么样你刚拿到一批3D MRI人体脊椎分割数据集文件全是nii.gz每个病例对应一张T1或T2加权图、一张label里面是从颈椎到腰椎的椎体或椎间盘标注。外面看「脊椎SPINE分割、MRI分割、3D分割」就是读个数据、跑个网络但真上手会发现最先卡住你的往往不是神经网络而是nii.gz背后的坐标空间。同一个序列有人读取后图像和标签左右翻转有人重采样后label出现半像素偏移最后Dice死活上不去。这篇笔记按我实际处理这类数据集的顺序展开先把nii.gz和MRI的特性读明白再做预处理然后搭一个能跑通的3D分割基线最后用临床认可的指标验证。适合刚拿到数据不知道从哪下手的工程师也适合从2D图像分割转到3D体数据的老手。2. 读懂nii.gz与MRI体数据文件结构、坐标变换与3D MRI分割的可视化2.1 nii.gz是什么头文件、体素间距与affine矩阵拿到nii.gz之后第一步永远是把文件结构确认清楚。一个.nii.gz不是单纯的「三维数组文件」它是被gzip压缩后的NIfTI-1格式。NIfTI文件里除了体素数组还带一个约348字节的header里面存着数据维度dim、体素物理间距pixdim、整数类型datatype以及最重要的affine矩阵。affine是一个4x4的仿射变换作用是把数组下标(i,j,k)映射到物理坐标(x,y,z)。如果只在numpy里读数组而丢掉这个矩阵后面所有重采样、裁剪、标签对齐都会变成空中楼阁。处理spine数据的第一件事就是打印每个样本的shape、dtype、spacing和affine。T1/T2的spine MRI体数据常见shape在(240,240,30)到(512,512,64)之间dtype可能是int16或uint16z方向体素间距往往大于x/y方向。这个信息决定后面是走各向同性重采样还是按原spacing直接训练。import nibabel as nib import numpy as np img nib.load(spine_001_t1.nii.gz) data img.get_fdata() header img.header affine img.affine print(shape:, data.shape) print(dtype:, data.dtype) print(spacing (mm):, header.get_zooms()) print(orientation:, nib.orientations.aff2axcodes(affine))这里有几个容易忽略的点。get_fdata()返回float64数组原始整数会被转成浮点方便后续归一化标签文件读取后要立刻转成np.uint8再参与计算。header.get_zooms()返回三个方向的体素间距如果z轴spacing是3mm而x/y是1mm一个体素实际是1×1×3mm的扁立方体直接按数组索引做卷积卷积核在三视图方向的有效感受野并不一致。aff2axcodes返回类似(R,A,S)的方向码表示体数据在物理空间中右侧Right、前侧Anterior、上侧Superior的走向。不同来源的病例方向码可能一个是(R,A,S)另一个是(L,A,S)。不统一方向图像和标签在batch里就是错位的这也是很多自动化预处理脚本暗藏的雷。提示不要用img.get_data()这个接口在NiBabel新版里已经废弃。统一用get_fdata()然后把标签转成uint8。2.2 用NiBabel读入3D MRI体数据并切片可视化MRI和CT不同同一个病人的T1、T2信号范围可以差好几倍肉眼看一遍三个方向的切片能发现很多标注和伪影问题。下面代码把轴向axial、冠状coronal、矢状sagittal三个方向的中位切片画出来。import matplotlib.pyplot as plt def show_three_planes(data): # data 是 nib.load().get_fdata() 读出的体数据数组 ax data[:, :, data.shape[2] // 2] # 轴向切片沿 z 取中间 co data[:, data.shape[1] // 2, :] # 冠状切片沿 y 取中间 sa data[data.shape[0] // 2, :, :] # 矢状切片沿 x 取中间 plt.figure(figsize(14, 4)) for i, slice_data in enumerate([ax, co, sa]): plt.subplot(1, 3, i 1) plt.imshow(slice_data.T, cmapgray, originlower) plt.axis(off) plt.show() show_three_planes(data)注意这里做了.T和originlower因为NiBabel数组的第一个轴对应影像学里的x方向直接imshow会把图像左右或上下反过来。这是读nii.gz最容易踩的地方看到椎体是反的不代表数据坏了而是显示时没有处理方向。另外如果三个轴的spacing差别很大这个代码画出来的冠状位和矢状位会被拉伸变形可以在imshow里加extent把物理坐标画准但训练流程里不需要只要心里有数即可。如果读出来的数据维度是4个比如多期增强MRI那就要用data[..., 0]取第一个时间点并确认每个vol是否严格对齐。2.3 3D分割与2D分割的本质差异为什么不能无脑切2D有人喜欢把3D MRI按z轴逐片切成2D图再跑U-Net省显存但结果通常不理想。脊椎在z轴方向是连续结构相邻切片上的椎体和椎间盘形态高度相关切成2D后模型只能看到单层灰度很容易把椎间盘和椎骨边界搞混。3D卷积核在体积内同时聚合三个方向的信息输出也是完整的三维体素标签这是3D分割在MRI脊椎任务上的常规选择。但3D分割真正的代价是显存和训练时间。一个全尺寸的3D MRI脊椎体数据可能是320×320×30直接塞进3D U-Net几乎放不下所以必然要裁剪、重采样、限制patch size。这些操作不是随便做做而是要在「保留解剖结构」和「符合显存边界」之间找平衡。之前有个项目里同事把原始数据直接resize到128×128×128结果椎间盘边界全糊了——因为z方向原本只有30层强行插值到128层会制造大量假信息。基本原则是能在3D空间解决的问题不降成2D能用小patch跑通的不盲目加大patch需要重采样时先想清楚目标spacing。3. 把nii.gz的3D MRI脊椎分割数据集整理成可训练样本重采样、裁剪与标签核对3.1 重采样与裁剪统一spacing和体素尺寸预处理的第一刀通常是重采样。不同设备、不同序列出来的spacing差异很大统一到目标spacing后再进模型才能让卷积核在不同样本上学到物理尺度一致的语义。我一般会先把图像和标签都重采样到各向同性1mm如果显存紧张第一个妥协方案是z轴放宽到2mmx/y保留1mm。from scipy.ndimage import zoom import numpy as np def resample_to_spacing(data, old_spacing, new_spacing, is_labelFalse): factor np.array(old_spacing) / np.array(new_spacing) order 0 if is_label else 1 return zoom(data, factor, orderorder) # 图像用线性插值标签用最近邻 old_spacing np.array(img.header.get_zooms()) new_spacing np.array([1.0, 1.0, 1.0]) resampled_img resample_to_spacing(data, old_spacing, new_spacing, is_labelFalse) resampled_lbl resample_to_spacing(label, old_spacing, new_spacing, is_labelTrue)核心点是order0。标签用最近邻插值保证输出还是0、1、2这样的整数避免线性插值产生0.6之类的伪标签图像用一阶线性插值就够不要用三阶样条因为MRI噪声本身较大过高阶插值只会放大伪影。zoom的factor是旧spacing除以新spacing比如z轴从3mm变1mm就是3这个操作会直接把数组在z方向放大三倍接着再做裁剪时要注意体素对应的物理区域没有漂移。裁剪是为了把脊柱区域从大体积背景里提出来。MRI图像里背景和软组织占比很高直接全图训练会让网络花大量容量学背景。常见做法是先用标签的nonzero体素算一个包围盒bounding box再向外膨胀20~30个像素既保留上下文又去掉空背景。def bbox_from_label(label, margin20): idx np.argwhere(label 0) mins idx.min(axis0) - margin maxs idx.max(axis0) margin mins np.maximum(mins, 0) maxs np.minimum(maxs, np.array(label.shape)) return mins, maxs mins, maxs bbox_from_label(resampled_lbl, margin20) cropped_img resampled_img[mins[0]:maxs[0], mins[1]:maxs[1], mins[2]:maxs[2]] cropped_lbl resampled_lbl[mins[0]:maxs[0], mins[1]:maxs[1], mins[2]:maxs[2]]这段代码的问题是它切在数组索引空间而不是物理空间。如果只是训练用没问题但推理时要保存原始空间的预测必须把mins和maxs映射回原始affine坐标系。我的习惯是每个样本预处理后只存一张nii.gz和一个同名的npy把affine、spacing、bbox坐标打包进一个json免得后面推理还原时猜参数。不少项目就是在这里翻车训练时crop了推理时没还原预测mask直接少了一大块。3.2 灰度归一化与窗宽窗位CT有固定的亨氏单位窗宽窗位是确定的MRI没有这种统一量纲T1加权、T2加权、STIR序列的灰度值范围完全不同同一个序列在不同设备上的信号强度也可能差很多。所以MRI预处理里最稳妥的灰度归一化是逐样本的百分位截断加z-score而不是用全局的均值和方差。def normalize_mri(data): p_low, p_high np.percentile(data, (0.5, 99.5)) data np.clip(data, p_low, p_high) mean data.mean() std data.std() return (data - mean) / (std 1e-8) # 1e-8 防 std0 的边界情况百分位选择有讲究。0.5%和99.5%是比较常见的组合能把血管、脂肪等强信号压住又不会让低噪声主导归一化。如果背景比例特别大可以把下限提到1%上限保持99.5%否则z-score后软组织对比度不够。注意这里每个volume独立计算不能拿训练集的全局参数去归一化测试集因为MRI本身就是相对成像没有标准标度。如果数据里有T1和T2两种序列最佳做法是分开处理分别统计各自的均值和方差或者干脆在输入通道上额外传一个序列类型标签。数据增强方面3D MRI分割可用的方法比CT多但要克制。随机翻转沿z轴要谨慎因为颈椎和腰椎的解剖方向有临床意义绕z轴旋转90度是安全的其他角度在spacing各向异性下会造成物理变形。灰度扰动可以适当做随机对比度、随机偏置、伪影模拟能提升模型对MRI采集参数变化的鲁棒性。3.3 标签核对区分椎骨、椎间盘与背景类别不平衡预处理完不要立刻开训先花十分钟把标签统计一遍。脊椎SPINE分割数据集的标签设计并不统一有的是二类0背景、1椎骨有的三类0背景、1椎骨、2椎间盘还有的每个椎体一个ID比如T1~L5按level编号。不同设计对损失函数的影响很大。label cropped_lbl.astype(np.uint8) vals, counts np.unique(label, return_countsTrue) print(label values:, vals) print(pixel counts:, counts)如果看到vals里只有0和255说明标签没转好——很多标注工具导出的mask是0/255要除以255映射成1。如果某个类别的counts占比低于5%像椎间盘在整卷里往往只占很小比例直接跑标准Dice Loss会出现「大类别主导梯度、小类别永远学不对」的现象。我的习惯是给每个类别算一个权重背景权重设为0目标类别权重按频率倒数归一化然后在Dice Loss里加权。处理多类别时建议把脊椎解剖先分组。椎骨和椎间盘是两类完全不同组织的结构椎骨内部还有皮质骨和松质骨的信号差异如果数据集标注的是「整个脊柱」而不是「每块椎骨」那模型的输出规则需要重新定义。对于医生来说他们更关心的是椎体压缩性骨折、椎间盘突出区域是否被正确分割单纯一个二值spine mask很难满足临床诊断需要的边界精度。所以动手前最好和提供数据的人确认标注的单位是什么是椎体、椎间盘还是包括椎弓根和棘突在内。这一条直接决定后处理逻辑和评估口径。4. 从3D U-Net到nnU-NetMRI脊椎分割训练管线与关键参数4.1 为什么3D U-Net是MRI分割的默认起点3D U-Net并不是什么新鲜结构但它确实是最稳的起点。编码器逐级下采样得到语义特征解码器逐级上采样恢复分辨率跳跃连接把编码器每层的空间细节并回解码器正好匹配医学图像里「病灶/器官边界需要高分辨率信息、区域判别需要全局语义信息」这一对矛盾。对MRI脊椎分割椎间盘和椎骨边界在多个序列里对比度不同跳跃连接能帮模型同时利用浅层的边缘特征和深层的类别语义。网络参数上我建议初期保持经典结构编码器四层每层两个3x3x3卷积加ReLU再加stride为2的3D池化底层的通道数从32起步逐层翻倍到256。输入用patch-based训练PyTorch里的tensor形状是(B, C, D, H, W)分别对应batch、通道、深度、高度和宽度。MRI脊椎数据D方向通常是重采样后的z轴层数H和W对应轴位面的两个方向。设计patch size时先问显存。以12GB显存为例(1, 1, 64, 128, 128)配合四层U-Net可以训练如果数据已经crop到脊柱附近patch可以再小一点。关键是z方向不要小于32否则3D卷积在z方向上几乎没有上下文退化成伪2.5D。4.2 最小训练管线数据加载、损失函数、评估指标Dice下面这套是我经常用来验证数据质量的最小管线不追求SOTA但足以暴露数据问题。Dataset负责从预处理好的npy里裁剪patch训练时80%的概率在标签附近采样20%随机采样全图这样不会出现一个batch里全是背景。import torch from torch.utils.data import Dataset class SpinePatchDataset(Dataset): def __init__(self, image_npy, mask_npy, patch_size(32, 96, 96), foreground_prob0.8): self.image torch.from_numpy(image_npy).float() self.mask torch.from_numpy(mask_npy).long() self.patch_size patch_size self.foreground_prob foreground_prob def __len__(self): return 1024 # 每个epoch采样张数可根据数据量调整 def __getitem__(self, idx): d, h, w self.patch_size if torch.rand(1).item() self.foreground_prob: # 从标签前景点随机取一个作为patch中心 foreground torch.nonzero(self.mask 0) center foreground[torch.randint(len(foreground), (1,))][0] else: center torch.tensor([ torch.randint(d // 2, self.mask.shape[0] - d // 2), torch.randint(h // 2, self.mask.shape[1] - h // 2), torch.randint(w // 2, self.mask.shape[2] - w // 2) ]) slice_d slice(center[0] - d // 2, center[0] d // 2) slice_h slice(center[1] - h // 2, center[1] h // 2) slice_w slice(center[2] - w // 2, center[2] w // 2) return self.image[slice_d, slice_h, slice_w].unsqueeze(0), \ self.mask[slice_d, slice_h, slice_w]这个代码的关键是前景采样。脊椎MRI中前景体素占比通常不到5%纯随机采样会浪费大量iter在空patch上。foreground_prob0.8表示80%的patch中心取自标注区域20%随机保证模型见过背景防止推理时把噪声误判为目标。如果你的标注类别不平衡特别严重可以再加一个类别轮转保证每个batch里椎间盘这类小目标不被漏掉。损失函数我用的是Dice Loss和CrossEntropy的组合。Dice Loss对类别比例不敏感但单独用容易让训练早期梯度不稳组合损失可以加速收敛def combined_loss(pred, target, alpha0.5): ce torch.nn.functional.cross_entropy(pred, target) # pred_bg 是背景类概率只对前景类计算 Dice pred_softmax torch.softmax(pred, dim1)[:, 1:] target_onehot torch.nn.functional.one_hot(target, num_classespred.size(1))[:, :, :, :, 1:].permute(0, 4, 1, 2, 3).float() intersection (pred_softmax * target_onehot).sum() dice 1.0 - (2.0 * intersection 1.0) / (pred_softmax.sum() target_onehot.sum() 1.0) return alpha * ce (1.0 - alpha) * dicealpha0.5表示两项各占一半。如果发现椎间盘类别始终分不出来可以增大alpha降低Dice的平滑作用或者按类别独立算Dice再取平均。优化器我用AdamW学习率3e-4weight decay 1e-4配合cosine退火。MRI数据量通常不大过拟合比欠拟合更常见所以验证集Dice在训练集Dice到达0.95后开始下降时要果断加早停。4.3 nnU-Net作为开箱即用方案参数怎么改、patch size和spacing怎么设如果不想从零调网络直接把数据按nnU-Net要求的目录结构放好用它做预处理和训练是业界很常见的做法。nnU-Net会自动分析spacing和label分布输出一份plans.json里面包括重采样目标spacing、patch size、网络拓扑、batch size等。MRI数据处理上它默认的灰度归一化就是z-score和上一节讲的一致。# 按 nnU-Net 的 DATASET 结构放置 nii.gz 后 nnUNetv2_plan_and_preprocess -d 1 -c 3d_fullres nnUNetv2_train 1 3d_fullres 0这两行命令里-d 1是数据集ID-c 3d_fullres表示在原始分辨率上做3D全分辨率训练。nnU-Net规划的patch size通常基于GPU显存12GB显存下可能给出32x128x128之类的结果。如果这个patch size在z方向太小我一般会在plans.json里手动把D方向调大同时把batch size降为1。另外建议检查nnU-Net自动重采样时的插值顺序它的label插值用的是最近邻这是正确的但如果你自己先做了预处理必须把图像和标签的spacing填准确否则nnU-Net的planner会被错误spacing误导。nnU-Net还有个很容易被忽略的价值它的predict阶段会自动执行与训练完全一致的预处理和后处理包括重采样回原始空间。这省掉了很多手写管线的bug。手写方案里容易出问题的部分正是nnU-Net已经解决了很多次的部分。当然它的代价是训练时间较长、需要按它的目录规范组织数据且对显存要求不低。如果只做一次验证我建议至少先跑通nnU-Net拿到一个可信的Dice基线再回头手写模型优化特定环节。5. 脊椎分割常见问题与避坑nii.gz读取、训练与推理的血泪经验5.1 现象训练loss下降但Dice始终在0附近原因图像和标签的affine方向不一致或者重采样时图像用了线性插值、标签用了最近邻但两边的坐标原点没有对齐导致网络在学一个乱码对应关系。另一个常见原因是标签值域是0/255网络把255当作一个类别而目标mask里只有0和1Dice按前景计算自然全是0。解决训练前打印每个样本的方向码和label unique值确认aff2axcodes完全一致把255的标签映射成1。图像和标签用同一套affine做重采样不能一个用原始spacing一个用resample后的spacing。最后可视化重叠几张图看边界是否align上肉眼确认比任何指标都靠得住。5.2 现象推理结果整体偏移半个椎体原因训练时做了crop或resample推理时没有把预测结果映射回原始spacing和bbox位置。模型输出是在预处理空间的预测直接保存成nii.gz预测体素坐标和原始图像坐标是两套系统偏半个椎体是很常见的。解决保存预测前用预处理时记录的affine和bbox参数做逆变换。如果是resample要先记录旧spacing-新spacing的factor推理完再用zoom的逆操作把mask还原如果是crop把预测补回原数组的对应位置。最稳的做法是把预测写nii.gz前调用nib.Nifti1Image并传入原始图像的affine和header。5.3 现象标签文件读出来全是0或255mask可视化一片黑原因数据集的标签可能以uint8、int16甚至float32存储有些工具用255代表目标有些把标注文件里的背景写成0、目标写成255直接读入网络训练等价于只有背景类。还有一种情况是标签文件里的值在0~1之间比如0.5被astype(np.uint8)截断成0。解决读标签后立刻打印np.unique。看到255就用// 255映射成1看到小数就在转整型前round。所有样本的标签约定统一后再进预处理管道。不要指望网络去自动学一种「把255识别为目标但输出1」的非线性关系。5.4 现象显存足够但patch设不大椎间盘边缘断裂原因patch太小感受野不足以覆盖椎间盘和邻近椎骨的关系另一个隐蔽原因是3D BatchNorm在小patch上统计不稳定batch里方差估计不准导致输出边界抖动。解决显存允许时优先加大z方向patch而不是无脑加大batch size。如果batch size只有1把BatchNorm换成InstanceNorm或GroupNorm能明显稳定训练。还可以加deep supervision让解码器中间层也能参与loss计算浅层特征对边缘恢复有帮助。MRI脊椎分割对边界要求高patch边缘的预测通常可靠性低推理时可以采用带overlap的滑窗并把重叠区加权平均减小边缘断裂。5.5 现象训练Dice接近0.95但临床医生认为分割结果没用原因Dice对体积重叠高度敏感对边界距离不敏感。脊椎分割里医生关心的是某个椎体是否被裁掉半截、椎间盘是否少了一段而Dice在小结构上的微小偏移就会被背景体积稀释指标好看但解剖不可用。解决在Dice之外加一个边界指标比如Hausdorff距离95%HD95同时把可视化结果按冠状位最大密度投影导出成gif或视频让医生直接看连续断层。Dice高、HD95差的情况通常要回到数据预处理检查z方向重采样是否过度或标注本身在z方向就有粗插值。不要迷信单一指标也不要迷信高分模型。6. 用Dice与HD95验证分割结果并保存成和原图对齐的nii.gz验证阶段最常做的事是把预测mask和原始图像叠加计算Dice、IoU、HD95然后把预测按原始affine保存。Dice看体积重叠HD95看最大边界偏差两者一起看才能反映边界质量。计算HD95用SimpleITK比较省事import SimpleITK as sitk import numpy as np def dice_score(pred, label): inter np.logical_and(pred, label).sum() return 2 * inter / (pred.sum() label.sum() 1e-6) def hd95(pred, label): pred_sitk sitk.GetImageFromArray(pred.astype(np.uint8)) label_sitk sitk.GetImageFromArray(label.astype(np.uint8)) hd sitk.HausdorffDistanceImageFilter() hd.Execute(pred_sitk, label_sitk) return hd.GetHausdorffDistance()注意SimpleITK的GetImageFromArray默认不做方向对齐如果pred和label来自相同预处理空间可以用如果来自不同空间要改成先归一化到同一affine坐标。实际操作里我见过不少团队直接对两个重采样后的数组算HD95但两个空间不一致数值完全失真。保存预测nii.gz时最关键的是用原始图像的affine和header。如果你在推理阶段只拿到一个numpy数组没有原始NIfTI对象等于把自己放在猜测方向的危险位置def save_prediction(pred_mask, reference_img, output_path): pred pred_mask.astype(np.uint8) out nib.Nifti1Image(pred, affinereference_img.affine, headerreference_img.header) nib.save(out, output_path)这样保存出来的文件才能直接被医生的工作站打开并自动对齐到原图。如果预测是在重采样空间生成的保存前要做反重采样用最近邻插值把预测恢复到原始shape再传入这个函数。反向重采样的插值顺序不能错预测mask只能是最近邻不能因为追求平滑用线性插值否则会出现非整数的类别边界临床工具会直接报错或者把0.6当背景。我的习惯是把预测保存成与原图同名的_pred.nii.gz同时输出一张冠状位叠加图。有一次因为忘了把crop的bbox补偿回去预测mask比原图小了一大圈肉眼看起来只是「缩小版」Dice却低得离谱事后排查发现就是在save前没有恢复数组位置。这个教训让我把「affine bbox spacing」三件套写成了固定的预处理注释块谁拿到这份数据都不会猜。希望帮到你。本文还有配套的精品资源点击获取

关于恒美微站

恒美微站专注于为个体商户、工作室提供极简自助建站服务,让每个人都能轻松拥有专业网站。

快速链接

  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心

服务项目

  • 可视化建站
  • 拖拽编辑
  • 主题定制
  • SEO 优化
  • 网站托管

联系方式

  • 📍 地址:北京市朝阳区建国路 88 号
  • 📞 电话:400-888-8888
  • ✉️ 邮箱:info@hmyw.cn
  • 🕐 时间:周一至周日 9:00-18:00

© 2024 恒美微站 hmyw.cn 版权所有 | 京 ICP 备 12345678 号