基于多模板配准的心腔分割算法

????作者主页:点击! 

????编程探索专栏:点击!

⏰️创作时间:2024年11月18日20点09分


神秘男子影,
  秘而不宣藏。
泣意深不见,
男子自持重,
   子夜独自沉。

论文链接

点击开启你的论文编程之旅https://www.aspiringcode.com/content?id=17102812998312

概述

本文复现论文 Automatic Whole Heart Segmentation in CT Images Based on Multi-atlas Image Registration[1] 提出的心腔分割算法。

整个心脏子结构的准确分割、建模和分析对于临床应用的开发非常重要。然而,对全部心脏子结构的分割十分具有挑战性,且目前仍然依赖手动操作。为了解决这一难题,该论文提出了一种基于多模板图像配准的自动全心分割算法

论文所提出的方法对患者CT图像中心脏部分的七个子结构进行图像分割。子结构包含:左心室腔、右心室血液腔、左心房腔、右心房血液腔、左心室心肌、从主动脉瓣到心房上部水平的上行主动脉干、从肺动脉瓣到分叉点的肺动脉干。

论文提出的算法主要包含三个步骤:感兴趣区域获取、精确分割、结果融合。

该论文基于多模态全心脏分割挑战赛(MM-WHS 2017)数据集进行测试。该数据集包含:训练数据(20张CT图像)和测试数据(40张CT图像),且所有数据均为从真实的临床环境中获取。其中每张CT图像附带了一张标记了七个心脏子结构的标签图像。

算法原理

论文提出的算法主要包含三步:

  • 第一步,获取感兴趣区域ROI(Region of Interest)。首先,将患者CT图像与模板图像统一下采样为低清晰度图像;然后,使用仿射配准(Affine registration)将患者图像与模板图像配准;最后,使用输出的配准参数对模板的心脏标签图像进行变换,获取ROI。
  • 第二步,对心脏进行精确分割。首先,利用ROI对原始的患者CT图像进行裁剪;然后,基于两步配准(仿射配准、B-样条配准)将裁剪后图像与模板图像进行配准;最后,使用输出的配准参数对模板的各标签图像进行变换,获取对患者CT图像中心脏的精确分割。
  • 第三步,筛选模板并集成结果。首先,基于两步配准中仿射配准结果的互信息MI(Mutual Information)对模板进行排序和过滤,并选择一定数量的模板参与后序步骤;然后,重新使用B-样条非刚性配准获取对患者CT图像中心脏的精确分割;最后,将各个模板的互信息作为权重,利用投票对分割结果进行融合,获取最终结果。

核心逻辑

由于官方数据集并没有提供全心脏标签,原文也未对全心脏标签的获取方法进行解释,故本文删去了原算法的裁剪步骤,具体的核心逻辑如下所示:

from utils import config_read
from heart_seg import affine_registration, bspline_registration, label_transform
import os
import itk
import numpy as np
from sklearn.metrics import mutual_info_score
from datetime import datetime

if __name__ == "__main__":
    # 读取配置
    args = config_read("./config.json")
    # 新建结果目录
    result_path = os.path.join(args.result_path, datetime.now().strftime("%Y%m%d_%H%M%S"))
    if not os.path.exists(result_path):
        os.mkdir(result_path)
    # 测试样本地址
    test_path_list = [os.path.join(args.test_path, "ct_test_%s_image.nii.gz"%str(i+2001)) for i in range(args.test_num)]
    for test_id in range(len(test_path_list)):
        # 读取测试图像
        test_path = test_path_list[test_id]
        test_image = np.asarray(itk.imread(test_path, itk.F))
        # 训练样本地址
        train_path_list = [os.path.join(args.train_path, "ct_train_%s_image.nii.gz"%str(i+1001)) for i in range(args.train_num)]
        atlas_mi = []
        for train_path in train_path_list:
            # 读取训练图像
            train_image = np.asarray(itk.imread(train_path, itk.F))
            # 利用仿射配准对齐患者CT与模板图像
            train_image_affine, _ = affine_registration(test_image, train_image)
            # 计算患者图像与变换后模板图像的互信息
            mi = mutual_info_score(test_image.ravel(), train_image_affine.ravel())
            atlas_mi.append(mi)
        # 筛选模板
        choosed_ids = sorted(range(len(atlas_mi)), key=lambda i: atlas_mi[i], reverse=True)[:args.atlas_num]
        logits = np.zeros((test_image.shape[0], test_image.shape[1], test_image.shape[2], 7), dtype=np.float32)
        for id in choosed_ids:
            train_image = np.asarray(itk.imread(train_path_list[id], itk.F))
            # 利用B-样条配准对齐患者CT与模板图像
            _, transform_parameters = bspline_registration(test_image, train_image)
            # 读取模板标签
            label_image = np.asarray(itk.imread(os.path.join(args.train_path, "ct_train_%s_label.nii.gz"%str(id+1001)), itk.F))
            # 利用B-样条配准结果的变换参数对模板图像的子结构标签图像进行变换,获得对患者心脏的精确分割。
            transformed_labels = label_transform(label_image, transform_parameters)
            # 利用之前获取的互信息作为权重,以投票的方式融合各个模板的精确分割结果。
            logits = logits + transformed_labels * atlas_mi[id]
        predicted = np.argmax(logits, dim=-1)
        # 存储最终的分割结果
        np.save(os.path.join(result_path, "ct_test_%s_predicted.npy"%str(test_id+2001)), predicted)

以上代码仅作展示,更详细的代码文件请参见附件。

效果演示

配置环境并下载示例后,运行附件目录中的example.py脚本,效果如下:

使用方式

  • 代码的运行环境可通过如下命令进行配置:
pip install numpy
pip install itk-elastix
pip install scikit-learn
pip install matplotlib
pip install tqdm
  • 解压附件压缩包并进入。如果是Linux系统,请使用如下命令:
unzip Multi-Atlas-Registration.zip
cd Multi-Atlas-Registration
  • 实验数据可通过如下链接进行下载:
    • 训练数据图像、训练数据标签、测试数据图像下载链接见附件READ.ME
    • 测试数据标签下载链接见附件READ.ME(非必要)
  • 将下载好的数据放置在Multi-Atlas-Registration/dataset目录下的合适位置,完整的目录结构应当如下图所示:
Multi-Atlas-Registration
│
├──datasets
│    │
│    ├── ct_train
│    │   ├── ct_train_1001_image.nii.gz
│    │   ├── ct_train_1001_label.nii.gz
│    │   ├── ct_train_1002_image.nii.gz
│    │   ├── ct_train_1002_label.nii.gz
│    │   └── ...
│    │
│    └── ct_test
│        ├── ct_test_2001_image.nii.gz
│        ├── ct_test_2002_image.nii.gz
│        └── ...
│
├──results
│    │
│    └── example
│        ├── example_image.nii.gz
│        └── example_predicted.npy
├──config.json
├──heart_seg.py
├──utils.py
├──main.py
├──example.py
└──README.md
  • 为了节约时间,我提供了一个已完成分割的测试样例(请从附件下载)并放到results/example/目录下。若想要查看它,请运行如下命令:
python example.py
  • 如果希望测试完整的算法(时间很长),请运行如下命令:
python main.py
  • 结果将保存在目录Multi-Atlas-Registration/results下,并以程序开始的时间(年月日_时分秒)作为名称。
  • 如果希望使用自己的文件路径或改动其他实验设置,请在文件Multi-Atlas-Registration/config.json中修改对应参数。以下是参数含义对照表:

参数名

含义

train_path

训练(模板)图像、标签目录

test_path

测试(患者CT)图像目录

train_num

训练图像数

test_num

测试图像数

result_path

结果存储目录

example_path

样例目录

atlas_num

筛选模板数

(以上内容皆为原创,请勿转载)

参考文献

[1] Yang G, Sun C, Chen Y, et al. Automatic whole heart segmentation in CT images based on multi-atlas image registration[C]//International Workshop on Statistical Atlases and Computational Models of the Heart. Cham: Springer International Publishing, 2017: 250-257.

成功的路上没有捷径,只有不断的努力与坚持。如果你和我一样,坚信努力会带来回报,请关注我,点个赞,一起迎接更加美好的明天!你的支持是我继续前行的动力!"

"每一次创作都是一次学习的过程,文章中若有不足之处,还请大家多多包容。你的关注和点赞是对我最大的支持,也欢迎大家提出宝贵的意见和建议,让我不断进步。"

神秘泣男子

上一篇:IDEA如何导入项目,包括从git仓库(github)导入项目


下一篇:opencv图片明暗度判断方法