如何具体实现registration
0. 心得
一开始其实根本没理解配准是具体需要做什么,只是一味的vibe coding,什么重采样,刚性配准什么的,最后生成出来的图像全是噪声,第二周感觉把这些放一起就没问题了,结果惊奇的发现人体直接错位了,锁骨来到了人体的中间地方,经过重新认真严谨思考,才意识到配准的真正含义,接下来是对具体配准过程的学习笔记。
完整代码见 GitHub:registration-scripts
1. 任务目标
当前任务是多期相 CT 图像配准。
对于同一个病例,可能存在多个期相或序列,例如:
平扫期
动脉期
门静脉期
延迟期
std5mm
lung5mm
这些序列的原始 DICOM 可能存在:
切片数量不同
扫描起始位置不同
spacing 不同
origin 不同
扫描范围不同
呼吸状态导致器官位置轻微变化
因此,不能直接认为不同期相中相同编号的 DICOM 切片对应同一个身体位置。
当前目标是:
以一个期相作为 fixed image,将其他期相作为 moving image,通过配准和重采样,使不同期相在统一空间中具有一一对应的切片关系。
最终输出为 nnU-Net 多通道输入格式。
2. 大体流程
当前采用的整体流程为:
读取同一病例下的 DICOM 文件;
根据 SeriesInstanceUID 区分不同序列;
排除 localizer、scout、切片数过少、不同部位的序列;
选择一个序列作为 fixed image;
其他序列作为 moving image;
对 moving image 进行配准;
将 moving image 重采样到 fixed image 的空间;
根据共同有效扫描范围进行统一裁剪;
检查同编号切片是否对应同一部位;
保存为 nnU-Net 多通道 NIfTI 格式。
简化表示为:
fixed image
↓
提供统一空间标准
moving image
↓
配准到 fixed image
↓
重采样到 fixed image 空间
↓
裁剪共同覆盖区域
↓
输出 nnU-Net 多通道图像
3. 多期相 CT 配准脚本实现与流程说明
3.1 参数设置部分
脚本开头需要设置几个关键参数。
fixed_dir 表示基准期相的 DICOM 文件夹路径,例如门静脉期、std5mm,或者老师指定的标准期相。
moving_dir 表示待配准期相的 DICOM 文件夹路径,例如动脉期、延迟期、lung5mm 等。
output_dir 表示输出文件夹。
case_id 表示 nnU-Net 中的病例编号,例如 case_001。
最终会输出:
case_001_0000.nii.gz:fixed 通道case_001_0001.nii.gz:moving 配准后的通道
此外,还有三个重要参数:
default_pixel_value = -1024.0body_threshold = -500crop_margin = 10
其中,default_pixel_value 是 moving 重采样到 fixed 空间后,moving 原本没有覆盖到的区域所填充的默认值。对于 CT 图像,空气区域通常接近 -1000 HU,因此使用 -1024 比使用 0 更合理。
body_threshold 用于粗略区分身体区域和空气背景。CT 中空气大约是 -1000 HU,而人体软组织、骨骼等通常大于 -500 HU,因此可以用 image > -500 粗略提取人体区域。
crop_margin 表示裁剪时额外保留的边缘范围,避免裁剪过紧导致身体边缘被切掉。
3.2 读取 DICOM 序列
脚本通过 read_dicom_series() 函数读取一个 DICOM 序列文件夹。
需要注意的是,一个 DICOM 序列通常不是一个文件,而是一组 .dcm 切片。SimpleITK 会把这一组 DICOM 文件读取成一个三维图像。
读取过程大致为:
使用
ImageSeriesReader创建读取器;在文件夹中查找 DICOM series ID;
根据 series ID 获取该序列下的所有 DICOM 文件;
将多张 DICOM 切片读取为一个 3D 图像。
如果一个文件夹中存在多个 series,脚本会给出提示,并默认读取第一个 series。实际处理时,最好保证一个文件夹中只放一个 series,或者在后续批量化脚本中手动选择正确的 series。
3.3 打印图像空间信息
脚本中使用 print_image_info() 函数打印图像的空间信息,包括:
Size
Spacing
Origin
Direction
PixelType
这些信息分别表示:
Size:图像尺寸,例如512 × 512 × 140Spacing:体素间距,例如0.97 × 0.97 × 5.0Origin:图像原点坐标Direction:图像方向矩阵PixelType:像素类型,例如32-bit float
打印这些信息的作用是:
检查 fixed 和 moving 原始空间信息是否一致;
检查 moving 配准重采样后是否已经进入 fixed 空间;
检查裁剪后的 fixed 和 moving 是否仍然保持空间一致;
判断结果是否符合 nnU-Net 多通道输入要求。
3.4 刚性配准:求 moving 到 fixed 的空间变换
脚本中的 rigid_registration() 是核心函数之一。
刚性配准的目标是求出 moving image 到 fixed image 的空间变换,即 moving 应该如何平移和旋转,才能和 fixed 对齐。
刚性配准允许:
x、y、z 方向平移
绕 x、y、z 轴旋转
不允许:
缩放
拉伸
局部形变
这对于医学分割任务比较安全,因为它不会改变器官和病灶的真实形态。
在配准前,脚本会先将 fixed 和 moving 转换为 Float32 类型。因为 DICOM CT 原图常常是 int16,而 SimpleITK 的配准算法通常需要浮点图像,否则可能报像素类型不支持的错误。
接着,脚本使用 Euler3DTransform 初始化一个 3D 刚性变换,并用 CenteredTransformInitializer 将 fixed 和 moving 的几何中心先大致对齐。这样可以为后续优化提供一个较好的初始位置。
3.5 相似性指标:互信息
配准时,算法需要判断 fixed 和 moving 当前是否对齐,这就需要相似性指标。
脚本中使用的是 Mattes Mutual Information,也就是互信息。
使用互信息的原因是:当前任务是多期相 CT 配准。不同期相虽然都是 CT,但由于增强时间不同,灰度分布可能不同。例如:
动脉期血管更亮
门静脉期肝实质强化不同
延迟期病灶表现不同
如果直接使用 MSE 这类灰度差异指标,可能会因为灰度变化而误判配准效果。
互信息不要求两个图像灰度值完全一致,而是衡量两幅图像之间的统计相关性,因此更适合多期相 CT 配准。
3.6 优化器与多分辨率策略
脚本使用梯度下降优化器来寻找最优的刚性变换参数。
优化器的作用是不断调整 transform 的参数,使相似性指标逐渐变好。简单来说,算法会不断尝试不同的平移和旋转参数,并判断哪一种变换能让 moving 更接近 fixed。
脚本中的关键参数包括:
learningRate:每次更新参数的步长numberOfIterations:最大迭代次数convergenceMinimumValue:收敛判断阈值convergenceWindowSize:用于判断是否收敛的窗口大小
此外,脚本使用了多分辨率策略:
先在低分辨率图像上粗配准
再在中等分辨率图像上细化
最后在原始分辨率图像上微调
对应参数为:
shrinkFactors = [4, 2, 1]smoothingSigmas = [2, 1, 0]
这样做的好处是可以减少噪声干扰,提高配准稳定性,也能让优化过程更容易收敛。
3.7 重采样到 fixed 空间
刚性配准得到的结果是一个 transform。这个 transform 只是描述 moving 应该如何变换,还没有真正生成最终图像。
因此,脚本下一步使用 resample_moving_to_fixed() 将 moving image 真正重采样到 fixed image 的空间中。
重采样后,moving_registered 会继承 fixed image 的空间网格,包括:
size
spacing
origin
direction
也就是说,从空间坐标上看,moving_registered 已经进入 fixed 的空间。
这一步完成后,fixed 和 moving_registered 的同一个 slice index 才可能对应同一个物理位置。
需要注意的是,重采样过程中,如果 moving 原本没有覆盖 fixed 的某些区域,这些区域会使用默认值填充。对于 CT 图像,脚本使用 -1024 作为默认填充值,以接近空气背景。
3.8 计算共同有效区域
配准和重采样后,moving_registered 会被放到 fixed 的完整空间中。但如果两个期相的原始扫描范围不同,就可能出现某些区域 fixed 有内容,而 moving 没有内容。
例如:
fixed 从锁骨扫到腹部
moving 从肺部扫到腹部
此时,moving_registered 在 fixed 前面锁骨区域可能是空白或默认填充值。
因此,脚本使用 get_common_body_bbox() 计算 fixed 和 moving_registered 的共同有效区域。
具体做法是:
对 fixed 使用阈值
fixed > -500得到 fixed 的身体区域;对 moving_registered 使用阈值
moving_registered > -500得到 moving 的身体区域;对两个 mask 取交集,得到两个期相都具有身体内容的共同区域;
使用连通域分析保留最大连通区域;
计算该区域的 bounding box;
在 bounding box 外额外加 margin,避免裁剪过紧。
这样得到的 bbox 就是两个期相共同覆盖的有效扫描区域。
3.9 统一裁剪与 nnU-Net 输出
脚本使用 crop_image() 对 fixed 和 moving_registered 进行裁剪。
关键点是:
fixed 和 moving_registered 必须使用同一个 start 和 crop_size。
也就是说:
fixed_cropped 使用共同 bbox 裁剪;
moving_cropped 使用同一个共同 bbox 裁剪。
不能让 fixed 和 moving 分别自己计算 bbox 后单独裁剪。否则两个图像的起点和范围可能不同,导致多通道之间空间错位。
裁剪完成后,脚本将结果保存为 nnU-Net 双通道格式:
case_001_0000.nii.gzcase_001_0001.nii.gz
其中:
0000是 fixed 图像;0001是 moving 配准并裁剪后的图像。
最后脚本会检查两个输出文件的空间信息是否一致,包括:
size
spacing
origin
direction
如果这些全部一致,说明从空间网格上看,它们已经可以作为 nnU-Net 的多通道输入。
但最终仍然需要用 ITK-SNAP 或 3D Slicer 进行 overlay 检查,确认图像内容上也真正对齐。
3.10 脚本解决的问题总结
这个脚本主要解决了多期相 CT 配准中的几个实际问题。
第一,解决了两个期相切片数不同的问题。
moving 可以被重采样到 fixed 的空间中,从而获得与 fixed 一致的空间网格。
第二,解决了同编号切片不对应的问题。
通过配准和重采样,使 fixed 与 moving_registered 的同一个 slice index 对应相同物理位置。
第三,解决了扫描范围不同的问题。
通过共同有效区域裁剪,去掉某一期相原本没有扫描到的空白区域。
第四,解决了 nnU-Net 多通道输入的空间一致性问题。
最终输出的 case_001_0000.nii.gz 和 case_001_0001.nii.gz 具有相同的 size、spacing、origin 和 direction。
4. 当前方法的不足与后续改进方向
虽然当前脚本已经实现了“刚性配准 + 重采样 + 共同有效区域裁剪”的基本流程,并且能够输出 nnU-Net 所需的多通道 NIfTI 文件,但该方法仍然存在一些不足。
4.1 目前只使用刚性配准,无法处理明显局部形变
当前脚本采用的是刚性配准,只允许 moving image 发生整体平移和旋转。
这种方法的优点是稳定、安全,不会改变器官和病灶形态。但它的缺点是无法处理局部形变。
在多期相 CT 中,不同期相之间可能存在呼吸状态差异。例如,肝脏、膈肌、胃肠道等腹部结构可能发生局部位置变化。此时,仅靠刚性配准可能无法让所有局部结构都完全对齐。
因此,当前方法更适合处理整体位置偏移,而不适合处理明显的局部器官变形。
后续可以考虑:
在刚性配准基础上尝试仿射配准;
对明显局部形变的样本谨慎尝试非刚性配准;
但非刚性配准可能改变病灶形态,因此需要严格验证。
4.2 互信息指标虽然稳妥,但不一定适合所有情况
当前脚本使用 Mutual Information 作为相似性指标。
互信息适合多期相 CT,因为不同期相的灰度分布可能不同。但是互信息也不是万能的。
如果两个序列重叠区域较少、扫描范围差异较大,或者图像中存在大量空白区域,互信息可能受到干扰,导致配准结果不稳定。
后续可以尝试比较不同 metric 的效果,例如:
Mutual Information
Normalized Mutual Information
NCC
MSE
对于多期相 CT,互信息通常更稳妥,但仍然需要通过可视化检查验证。
4.3 共同有效区域裁剪依赖阈值,可能不够精确
当前脚本使用 image > -500 来粗略判断身体区域,并据此计算 fixed 和 moving_registered 的共同有效区域。
这种方法简单有效,但它本质上是一个经验阈值方法。
可能的问题包括:
阈值设置不合适时,可能漏掉部分低密度组织;
床板、伪影或增强区域可能被错误纳入身体区域;
对不同扫描协议、不同窗宽窗位、不同部位的数据适应性有限;
如果图像噪声较多,mask 可能不稳定。
后续可以改进为:
根据 CT HU 值范围做更稳定的身体 mask;
结合形态学操作去除小噪声区域;
只保留最大连通区域;
对不同部位设置不同阈值;
或结合已有器官分割结果进行更精确裁剪。
4.4 当前方法默认两个期相具有足够重叠区域
当前流程的前提是 fixed 和 moving 至少有较大的共同扫描区域。
如果两个序列本身不是同一部位,或者共同区域太少,即使运行成功,配准结果也没有实际意义。
例如:
fixed 是胸腹部;
moving 是盆腔;
或者 moving 只是 localizer/scout;
或者两个期相扫描范围重叠很少。
这种情况下,脚本可能仍然输出文件,但结果不适合作为 nnU-Net 输入。
因此,后续批量化时必须加入序列筛选机制:
排除 localizer / scout;
排除切片数过少的序列;
检查 BodyPartExamined、SeriesDescription、ProtocolName;
检查 ImageOrientationPatient 是否一致;
检查 z 方向扫描范围是否有足够重叠。
4.5 当前脚本只处理两个期相,还没有完全扩展到多期相批量处理
当前脚本主要验证了一个 fixed image 和一个 moving image 的配准流程。
但实际数据中,一个病例可能包含多个期相或多个序列,例如:
平扫期;
动脉期;
门静脉期;
延迟期;
std5mm;
lung5mm。
后续还需要扩展为:
一个 fixed image;
多个 moving image;
每个 moving image 分别配准到 fixed;
最后统一裁剪共同有效区域;
输出
case_001_0000.nii.gz、case_001_0001.nii.gz、case_001_0002.nii.gz等多通道文件。
也就是说,目前只是单病例、双期相流程,后续还需要做多期相和多病例批量化。
4.6 目前主要依赖可视化检查,缺少定量评价指标
当前配准效果主要通过 overlay 或人工观察判断,例如:
肺是否对肺;
肝是否对肝;
骨骼轮廓是否重合;
同编号切片是否对应同一部位。
这种方式直观,但主观性较强。
后续可以增加定量评价指标,例如:
Mutual Information 配准前后变化;
NCC;
Dice;
Hausdorff Distance;
器官边界重合程度。
如果有器官或病灶标签,可以用标签重叠程度评价配准效果。但需要注意,标签重采样必须使用最近邻插值。
4.7 重采样仍然会引入插值误差
无论是刚性配准还是仿射配准,最终都需要进行重采样。
重采样过程中使用线性插值,会重新计算体素灰度值,可能导致:
边缘轻微模糊;
灰度分布轻微变化;
小结构细节损失;
病灶边界不如原图锐利。
因此,重采样次数应尽量减少。
当前方法中,应避免对同一图像反复重采样。比较合理的做法是:
先求最终 transform;
再一次性 resample 到 fixed 空间;
不要多次中间保存再重复 resample。
4.8 当前没有专门处理标签文件
当前脚本主要处理 CT 原图。
如果后续需要把分割标签也变换到同一空间,需要额外处理标签文件。
标签文件不能使用线性插值,而必须使用最近邻插值。
否则标签值可能从整数类别变成小数,导致类别错误。
例如:
原标签 0 = background;
1 = liver_cyst;
2 = liver_hemangioma;
3 = tumor。
如果线性插值,可能出现 1.3、2.6 这种无意义标签值。
因此,后续处理标签时应使用:
图像:线性插值;
标签:最近邻插值。
4.9 配准失败时缺少自动报警机制
目前脚本可以输出结果,但如果某个样本配准失败,脚本不一定能自动判断。
例如:
图像被转歪;
共同区域过小;
输出大面积空白;
fixed 和 moving 实际不是同一部位;
optimizer 收敛到错误位置。
这些情况可能需要人工打开图像才能发现。
后续批量化时可以加入自动检查机制,例如:
检查共同有效区域体积是否过小;
检查裁剪后 z 层数是否太少;
检查 moving_registered 中有效体素比例;
检查配准前后 metric 是否明显改善;
记录每个 case 的日志。
4.10 当前流程还没有完全封装成 nnU-Net 数据集格式
当前脚本已经可以输出:
case_001_0000.nii.gzcase_001_0001.nii.gz
但完整 nnU-Net 数据集还需要:
imagesTr/labelsTr/dataset.json正确的通道名称;
正确的标签定义;
训练集/测试集划分。
因此,配准只是 nnU-Net 输入准备的一部分。
后续还需要把配准结果进一步整理成标准 nnU-Net 数据集结构。
4.11 当前不足总结
当前方法已经完成了多期相 CT 配准的基本流程,但仍然存在以下不足:
只使用刚性配准,难以处理局部形变;
互信息指标不一定适合所有异常情况;
共同区域裁剪依赖阈值,鲁棒性有限;
默认两个期相有足够重叠区域,不适合不同部位数据;
当前只验证了双期相,还未完全扩展到多期相批量处理;
配准效果主要依赖人工可视化检查,缺少定量评价;
重采样会引入插值误差;
标签文件需要单独使用最近邻插值处理;
缺少配准失败的自动报警机制;
还需要进一步整理为完整 nnU-Net 数据集格式。
后续改进方向是:
在当前刚性配准流程稳定的基础上,进一步实现多期相批量处理、自动质量检查、共同区域裁剪优化,以及 nnU-Net 数据集格式自动生成。