nnUNet V2代码——数据预处理(二)

前文请看nnUNetv2_plan_and_preprocess命令

阅读nnUNet\nnunetv2\preprocessing\preprocessors\default_preprocessor.py文件

文件内有一个DefaultPreprocessor类和example_test_case_preprocessing函数(测试用的,跳过)。

在DefaultPreprocessor类内涉及的其他函数都在文章后半部分说明。

数据预处理共两篇:

nnUNet V2代码——数据预处理(一)

nnUNet V2代码——数据预处理(二)

文章内提及的ConfigurationManager类和PlansManager类nnUNet V2代码——数据预处理(一)

DefaultPreprocessor

1. __init__函数

定义verbose,该变量决定是否打印额外的信息

2. run函数

参数

  • dataset_name_or_id:数据集名称或id
  • configuration_name:配置名称,例如2d
  • plans_identifier:默认nnUNetPlans
  • num_processes:进程数

过程

配置必要的文件名称、目录结构、文件路径,读取nnUNetPlans.json文件,实例化PlansManager类,读取配置信息(get_configuration函数)等。

最后使用多进程运行类内函数run_case_save

代码结构清晰,不做粘贴

3. run_case_save函数

本函数主要调用类内函数run_case,获取需要数据(此处的data和seg压缩保存为npz文件,npy文件在run_case函数内保存),参数也和它基本一致;保存相关数据。代码清晰,不做粘贴。

代码里的data变量是医学待分割图像,所以本文用图像代替data,便于阅读

4. run_case函数

参数

  • image_files:待分割图像路径
  • seg_file:掩码图像路径
  • plans_manager:PlansManager类
  • configuration_manager:ConfigurationManager类
  • dataset_json:配置nnUNet_raw文件夹时创建的,内容需要用户自己写

过程

读取文件,运行类内函数run_case_npy,并返回处理后(处理过程见run_case_npy函数)的数据 。代码清晰,不做粘贴

5. run_case_npy函数

参数

  • properties:医学图像的相关信息,例如体素间距
  • 其他参数和run_case函数一致

过程

预处理具体过程
首先复制一份图像和seg;查看是否有seg,存入has_seg变量。代码清晰,不做粘贴。

接下来依照nnUNetPlans.json确定的前向转置数组(transpose_forward)对图像、seg和原始图像的spacing前向转置

data = data.transpose([0, *[i + 1 for i in plans_manager.transpose_forward]])
if seg is not None:
    seg = seg.transpose([0, *[i + 1 for i in plans_manager.transpose_forward]])
original_spacing = [properties['spacing'][i] for i in plans_manager.transpose_forward]

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

先看一遍上面三张图,方便理解接下来的裁剪操作

1️⃣获取原始图像的大小(shape_before_cropping )。
2️⃣根据crop_to_nonzero函数去除图像(data)和seg中多余的无效区域(上面第一张图中的区域),再将seg中剩余的无效区域赋值为-1,这些-1值在归一化时可能使用,在训练时则会被去除。
3️⃣再将裁剪后图像在原图像中的位置(bbox)以及裁剪后的图像大小,存入properties字典中:

shape_before_cropping = data.shape[1:]
properties['shape_before_cropping'] = shape_before_cropping
data, seg, bbox = crop_to_nonzero(data, seg)
properties['bbox_used_for_cropping'] = bbox
properties['shape_after_cropping_and_before_resampling'] = data.shape[1:]

接下来提取体素间距,if语句用来判断当前配置是否为2d,2d配置下不改变各个切片间的体素间距

根据体素间距计算重采样后的图像大小(由compute_new_shape函数获取,代码清晰):

target_spacing = configuration_manager.spacing
 
if len(target_spacing) < len(data.shape[1:]):
    target_spacing = [original_spacing[0]] + target_spacing
new_shape = compute_new_shape(data.shape[1:], original_spacing, target_spacing)

接下来对图像进行归一化操作、对图像seg进行重采样操作,查询nnUNetPlans.json文件获取之前确定的归一化函数和重采样函数,依次执行。nnUNet作者强调,归一化操作必须在重采样前执行。再根据self.verbose决定是否打印更多信息:

# normalize
data = self._normalize(data, seg, configuration_manager,
                        plans_manager.foreground_intensity_properties_per_channel)

old_shape = data.shape[1:]
data = configuration_manager.resampling_fn_data(data, new_shape, original_spacing, target_spacing)
seg = configuration_manager.resampling_fn_seg(seg, new_shape, original_spacing, target_spacing)
if self.verbose:
    print(f'old shape: {old_shape}, new_shape: {new_shape}, old_spacing: {original_spacing}, '
            f'new_spacing: {target_spacing}, fn_data: {configuration_manager.resampling_fn_data}')

⭐️⭐️归一化时,nnU-Net V2会根据上面的裁剪结果判定归一化是否包含seg中值为-1的区域,如果因为裁剪操作导致图像不足原来的3/4,则只对有效区域(seg中值不为-1的区域)进行归一化;如果并未小于原来的3/4,那么对图像(data)的所有区域进行归一化。

多一步判定的原因:在一些特定的医学图像处理任务中(比如脑瘤分割 BraTS 任务),输入的图像(如 MRI 图像)通常包含某些没有意义的无效区域(比如背景区域,如空气),而其他区域(例如脑组织)是需要分割的有效区域。在对这些图像进行归一化时,如果整个图像的强度分布都参与归一化计算,可能会受到无效区域的强烈干扰。例如,背景区域的像素值可能非常低(接近 0),而脑组织区域的像素值相对较高。如果不对这些背景区域进行掩码处理,归一化时会根据整个图像的像素值分布来计算统计量(比如均值和标准差),而这些统计量可能会严重偏向背景区域

接下来对seg内前景像素值采样,获取这些像素值的坐标:如果有seg(has_seg变量为True),实例化LabelManager类,用于处理类别(在dataset.json里用户定义的前景类别,例如A:1);获取前景类别,之后调用 _sample_foreground_locations 函数,从 seg 中采样像素值,获取这些像素值的坐标,并存入properties[‘class_locations’] 中(这些坐标在训练过程中会用到,目的是保证一个batch中有三分之一以上的batch有前景区域)。
再调用 modify_seg_fn 函数(nnUNet作者调试用的,不做说明)对 seg 进行修改:

if has_seg:
    label_manager = plans_manager.get_label_manager(dataset_json)
    collect_for_this = label_manager.foreground_regions if label_manager.has_regions \
        else label_manager.foreground_labels
 
    # 使用忽略标签时,我们希望仅从标注区域采样。因此,我们还需要从所有类(包括背景)中均匀采样
    if label_manager.has_ignore_label:
        collect_for_this.append(label_manager.all_labels)
 
    # 无需在区域中过滤背景,因为它已在 handle_labels 中过滤
    properties['class_locations'] = self._sample_foreground_locations(seg, collect_for_this,
                                                                            verbose=self.verbose)
    seg = self.modify_seg_fn(seg, plans_manager, dataset_json, configuration_manager)

最后根据 seg 中的数值大小选择合适的数据类型。如果最大值超过127,则转换为 int16 类型;否则转换为 int8 类型(计组还在追我)。代码清晰,不做粘贴。

6. _normalize函数

查询当前配置的归一化函数,并运行它,具体执行不在这里,以后阅读到了再说明。

7. _sample_foreground_locations函数

对区域内所有像素值位置采样,将其存入class_locs字典中,例如,对seg前景中类别为1(数值为1)的区域采样,获取坐标(3,115,210),存入class_locs中。

8. 涉及的函数

get_filenames_of_train_images_and_targets

超链接

<think>嗯,用户想了解nnUNet预处理方法和流程,并提供了四个相关引用。从引用内容看,信息主要集中在裁剪、重采样、标准化等核心步骤,还涉及版本兼容性问题(V2)和预测结果处理。 用户可能是医学影像领域的研究者或工程师,需要具体的技术细节而非概念性介绍。ta特意强调"不是用户真正需求",暗示希望跳过引用中的冗余信息,直接获取结构化流程。考虑到医学图像预处理直接影响分割效果,用户可能需要实操指导。 梳理引用中的关键点:引用[1][3][4]形成了完整流程链——格式转换→裁剪→重采样→标准化,引用[2]补充了环境配置要求,引用[4]特别强调了归一化必须在重采样前执行的顺序约束。需要重点解释这些环节的物理意义,比如裁剪为什么用非零像素而非固定尺寸。 验证环节的缺失值得注意。引用提到可视化预测结果但未说明训练过程中如何验证预处理效果,可能需要补充数据校验机制。另外引用[3]的版本警告提示用户需注意代码兼容性,这点在回答中应强调。 三维医学图像的特殊性需突出:比如各向异性分辨率处理(引用[4]的original_spacing)、多模态配准问题(引用未提及但nnUNet实际支持)。最后要关联到分割性能,说明预处理如何解决医学图像常见噪声、形变等问题。 </think>nnUNet预处理流程是其自动化医学图像分割框架的核心环节,主要围绕**三维医学图像的特性**进行优化。核心流程如下: --- ### 📊 1. **数据格式标准化** - **目的**: 统一不同来源数据的格式(如DICOM→NIfTI) - **操作**: - 转换图像为`*.nii.gz`格式 - 检查图像与标签的空间对齐 - 提取元数据(分辨率、方向矩阵) - *引用[1]明确提到需先完成基础格式转换[^1]* --- ### ✂️ 2. **智能裁剪(Crop)** - **策略**: 基于 **非零像素区域** 动态裁剪 - **优势**: - 去除无效背景(如CT图像的黑色边缘) - 减少显存占用,加速训练 - *引用[1][3]强调裁剪是降低计算资源消耗的关键步骤[^1][^3]* --- ### 🔄 3. **重采样(Resample)** - **目标分辨率**: 由nnUNet自动分析数据集决定 - **执行顺序**: ```mermaid graph LR A[原始图像] --> B[归一化] --> C[重采样] ``` - **注意事项**: - 图像与分割标签**同步重采样**(标签用最近邻插值) - **归一化必须优先于重采样**(引用[4]特别警告顺序不可颠倒[^4]) --- ### 📏 4. **强度归一化(Normalization)** - **常用方法**: - **CT图像**: `Z-score标准化` 或 `裁剪到特定百分位(如0.5%-99.5%)` - **MRI图像**: `均值方差归一化` 或 `直方图匹配` - **特性**: - 自适应选择归一化策略(依赖图像模态) - 通道独立处理(多模态数据) --- ### ⚙️ 5. **实验计划生成(`nnUNet_plan_experiment`)** - **自动化决策**: - 分析数据集统计量(分辨率分布、类别比例) - 确定最优网络结构(2D/3D全卷积或级联模型) - 生成配置文件`nnUNetPlans.json` - **版本兼容性**: - V2版本需重新生成计划文件(引用[3]提示旧版本兼容问题[^3]) --- ### 💡 预处理设计思想 1. **数据驱动**:所有参数(如目标分辨率、裁剪尺寸)由数据集统计特征自动推导 2. **流程标准化**:强制固定执行顺序确保可复现性 3. **模态无关性**:通过归一化策略自适应支持CT/MRI/PET等多模态数据 > ⚠️ **关键提示**:预处理流程被封装在`nnUNetv2_plan_and_preprocess`命令中,需在训练前**完整执行一次**以生成预处理结果和实验计划[^2][^3]。 --- ### ❓相关问题 1. nnUNet如何自动确定重采样的目标分辨率? 2. 处理多模态医学图像(如CT+MRI融合)时归一化策略有何特殊设计? 3. 若数据集包含各向异性分辨率(如0.5×0.5×2mm³),nnUNet预处理如何优化? 4. 如何扩展nnUNet预处理流程以支持自定义模态的医学图像? [^1]: 聚焦裁剪策略的核心价值 [^2]: 环境配置与基础命令 [^3]: 新版计划文件的重要性 [^4]: 归一化与重采样的强制顺序
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

十凯

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值