如何从ITK注册中获得变换仿射?

2023-12-31

进行 3D MRI 扫描A, B, and C我想执行仿射(联合)配准B onto A,取配准的变换仿射矩阵并将其应用于C.

我的问题是配准变换的仿射矩阵的符号错误。也许是因为方向错误?

The TransformParameters包含 12 个值,其中前 9 个是行优先顺序的旋转矩阵,后 3 个是平移值。

TransformParameters = [R1, R2, R3, R4, R5, R6, R7, R8, R9, Tx, Ty, Tz]

registration_affine = [[R1, R2, R3, Tx],
                       [R4, R5, R6, Ty],
                       [R7, R8, R9, Tz],
                       [0,  0,  0,  1 ]]

我知道 ITK 将图像保存在LPS方向和尼巴贝尔RAS。 所以我尝试对方向差异进行更改transform_affine但这并没有成功。

我无法获得与 ITK 相同的注册输出,下面我将展示一些数字示例和我的最小代码示例。


为了测试这一点,我对现有图像应用了仿射变换。该变换矩阵的逆矩阵是配准可以找到的真实仿射。

array([[ 1.02800583,  0.11462834, -0.11426342, -0.43383606],
       [ 0.11462834,  1.02800583, -0.11426342,  0.47954143],
       [-0.11426342, -0.11426342,  1.02285268, -0.20457054],
       [ 0.        ,  0.        ,  0.        ,  1.        ]])

但是按照上面解释的方式构建的仿射会产生:

array([[ 1.02757335,  0.11459412,  0.11448339,  0.23000557],
       [ 0.11410441,  1.02746452,  0.11413955, -0.20848751],
       [ 0.11398788,  0.11411115,  1.02255042, -0.04884404],
       [ 0.        ,  0.        ,  0.        ,  1.        ]])

您可以看到这些值非常接近,但只有符号错误。 事实上,如果我手动设置与“真实”矩阵中相同的符号,则变换矩阵是好的。

在 MONAI 的 ITK 加载器中,我发现建议执行以下操作以将 ITK 仿射转换为 nibabel 仿射的代码:

np.diag([-1, -1, 1, 1]) @ registration_affine

如果我使用 nibabelsornt_transform从中获取 ornt 变换的方法LPS to RAS,这返回[-1, -1, 1]并与 MONAI 的 ITK 加载器中所做的匹配。

但是将其应用于上面的仿射实际上并不会产生正确的符号(仅在平移位中):

array([[-1.02757335, -0.11459412, -0.11448339, -0.23000557],
       [-0.11410441, -1.02746452, -0.11413955,  0.20848751],
       [ 0.11398788,  0.11411115,  1.02255042, -0.04884404],
       [ 0.        ,  0.        ,  0.        ,  1.        ]])

所以我有点卡在这里。


这是一个完整的最小代码示例来运行我正在做/尝试做的事情。另请参阅下面的示例数据和包版本。

import nibabel
import numpy as np
from monai.transforms import Affine
from nibabel import Nifti1Image
import itk

# Import Images
moving_image = itk.imread('moving_2mm.nii.gz', itk.F)
fixed_image = itk.imread('fixed_2mm.nii.gz', itk.F)

# Import Default Parameter Map
parameter_object = itk.ParameterObject.New()
affine_parameter_map = parameter_object.GetDefaultParameterMap('affine', 4)
affine_parameter_map['FinalBSplineInterpolationOrder'] = ['1']
parameter_object.AddParameterMap(affine_parameter_map)

# Call registration function
result_image, result_transform_parameters = itk.elastix_registration_method(
    fixed_image, moving_image, parameter_object=parameter_object)
parameter_map = result_transform_parameters.GetParameterMap(0)
transform_parameters = np.array(parameter_map['TransformParameters'], dtype=float)

itk.imwrite(result_image, 'reg_itk.nii.gz', compression=True)

# Convert ITK params to affine matrix
rotation = transform_parameters[:9].reshape(3, 3)
translation = transform_parameters[-3:][..., np.newaxis]
reg_affine: np.ndarray = np.append(rotation, translation, axis=1)  # type: ignore
reg_affine = np.append(reg_affine, [[0, 0, 0, 1]], axis=0)  # type: ignore

# Apply affine transform matrix via MONAI
moving_image_ni: Nifti1Image = nibabel.load('moving_2mm.nii.gz')
fixed_image_ni: Nifti1Image = nibabel.load('fixed_2mm.nii.gz')
moving_image_np: np.ndarray = moving_image_ni.get_fdata()  # type: ignore

LPS = nibabel.orientations.axcodes2ornt(('L', 'P', 'S'))
RAS = nibabel.orientations.axcodes2ornt(('R', 'A', 'S'))
ornt_transform = nibabel.orientations.ornt_transform(LPS, RAS)[:, -1]  # type: ignore

affine_transform = Affine(affine=np.diag([*ornt_transform, 1]) @ reg_affine, image_only=False)
out_img, out_affine = affine_transform(moving_image_np[np.newaxis, ...])
reg_monai = np.squeeze(out_img)

out = Nifti1Image(reg_monai, fixed_image_ni.affine, header=fixed_image_ni.header)

nibabel.save(out, 'reg_monai.nii.gz')

输入数据:

  • 固定_2mm.nii.gz https://github.com/InsightSoftwareConsortium/ITKElastix/files/8226904/fixed_2mm.nii.gz
  • moving_2mm.nii.gz https://github.com/InsightSoftwareConsortium/ITKElastix/files/8226905/moving_2mm.nii.gz

输出数据:

  • reg_itk.nii.gz https://github.com/InsightSoftwareConsortium/ITKElastix/files/8226906/reg_itk.nii.gz
  • reg_monai.nii.gz https://github.com/InsightSoftwareConsortium/ITKElastix/files/8226907/reg_monai.nii.gz

封装版本:

itk-elastix==0.12.0
monai==0.8.0
nibabel==3.1.1
numpy==1.19.2

我之前确实在 GitHub 上的 ITKElastix 项目上问过这个问题#145 https://github.com/InsightSoftwareConsortium/ITKElastix/issues/145但无法解决我的问题。感谢 dzenanz 和 mstaring 试图在那里提供帮助。


经过与我的团队进行大量尝试和讨论后,我们意识到正在发生的事情。

我们已经确定了如何阅读 ITKTransformParameters前 9 个数字是按行优先顺序读取的旋转矩阵的一部分,最后三个数字是平移矩阵的一部分。

rot00, rot01, rot02, rot10, rot11, rot12, rot20, rot21, rot22, tx, ty, tz = parameter_map['TransformParameters']
affine = np.array([
    [rot00, rot01, rot02, tx],
    [rot10, rot11, rot12, ty],
    [rot20, rot21, rot22, tz],
    [    0,     0,     0,  1],
], dtype=np.float32)  # yapf: disable

我们已经知道 nibabel 具有 RAS 方向的图像和 LPS 方向的 ITK 图像。

我们也已经知道,如果我们想要改变图像的方向,我们需要翻转相应的轴。 LPS 到 RAS 意味着翻转 L->R 和 P->A。 所以翻转前两个轴。 Flip由此表示为-1并且没有翻页1。因此前两个轴的翻转可以描述为[-1, -1, 1]。 我们可以为这次翻转构造一个仿射变换矩阵np.diag([-1, -1, 1, 1])(最后1仅用于计算目的)。 因此,在 LPS 和 RAS 之间翻转的仿射变换矩阵为:

flip_LPS_RAS = np.array([[-1,  0,  0,  0],
                         [ 0, -1,  0,  0],
                         [ 0,  0,  1,  0],
                         [ 0,  0,  0,  1]])

请注意,这种翻转是双向的。 LPS -> RAS 和 RAS -> LPS。

如果您有 3D 图像和相应的仿射矩阵,则可以通过应用“flip_LPS_RAS”来翻转该图像中的轴。 如果你想计算该图像的新仿射,你可以这样做:

flipped = flip_LPS_RAS @ image_affine

既然我们已经奠定了基础,那么现在让我们看看我们未能弄清楚的内容。

我们知道配准变换的仿射矩阵基于 LPS 方向的图像,并且我们知道 nibabel 图像位于 RAS。 思路是,我们需要将仿射变换从 LPS 方向转换为 RAS 方向,类似于上面提到的图像重新定向。 所以我们应用了flip_LPS_RAS仿射于registration仿射。 我们的错误在于,这并没有使仿射变换成为面向 RAS 的变换。

问题是registrationaffine 期望应用于 LPS 方向的图像并输出 LPS 方向的图像。 让我们回顾一下,图像仿射具有 RAS 方向,并且registration仿射期望应用于 LPS 方向的图像。 现在更容易看出,要在 RAS 方向的图像上应用配准变换,我们首先需要将图像的方向更改为 LPS,然后在配准后返回 RAS。

image -> flip_LPS_RAS -> registration_lps -> flip_LPS_RAS 

我们只对配准变换的仿射矩阵感兴趣,所以让我们忽略上面变换链中的图像。 用代码编写这个仿射变换链:

registration_ras = flip_LPS_RAS @ registration_lps @ flip_LPS_RAS

这将产生一个仿射矩阵,它接受面向 RAS 的图像,将其更改为 LPS 方向,以 LPS 方向执行配准,然后将方向更改回 RAS - 为我们提供一个仿射变换,在面向 RAS 上执行 ITK 配准图像。

从上面的最小代码示例来看,以下内容现在应该可以工作:

affine_transform = Affine(affine=registration_ras, image_only=True)
out_img = affine_transform(moving_image_np[np.newaxis, ...])
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何从ITK注册中获得变换仿射? 的相关文章

  • ITK——3. 编译remote库

    文章目录 1 在线编译 2 离线编译 2 1 下载对应的github库 2 2 编译 2 3 一点疑问 以ITKMinimalPathExtraction库为例 对应的github链接是 https github com InsightSo
  • ITK——5. 利用ITK自身的多线程加速filter计算

    文章目录 1 ITK多线程简介 1 1 平台多线程 1 1 1 基本内容 1 1 2 Intel的TBB 1 2 典型例子 执行原理 1 3 5 X版本之后的变动 1 4 ITK多线程整体认识 1 4 1 基本内容 1 4 2 过滤器级别的
  • itk registration 1

    参考 xff1a https itk org ITKSoftwareGuide html Book2 ITKSoftwareGuide Book2ch3 html x26 1740003 18 图像配准是确定将一幅图像上的点映射到另一幅图像
  • VTK与ITK的详细安装指南

    1 说明 本文来自一个付费下载文档 xff0c 好像是一本图书的第一章的部分内容 感觉比网上很多指南写的要详细 特整理出来和大家分享 xff0c 向原作者表示感谢 xff01 2 获取安装资源 xff08 1 xff09 CMake 安装资
  • dicom信息+dcmtk使用

    dcmtk使用 常见错误 错误 E can t load data dictionary W Monochrome encoder No data dictionary 解决 https forum dcmtk org viewtopic
  • Qt VTK ITK安装与测试(三)ITK的安装与测试

    ITK的安装与测试 安装简介 本部分讲述使用cmake加VS2010编译 安装ITK库 基本步骤和VTK安装时相同 而后测试VTK与ITK的联合开发 VTK安装步骤 1 资源下载 资源下载网址 http www itk org ITK re
  • AffineTransform:从中心缩放形状

    我正在尝试使用 AffineTransform 从中心缩放矩形 我确信解决方案是显而易见的 但我无法使其发挥作用 这是我迄今为止测试过的 import java awt Color import java awt Dimension imp
  • 如何使用python进行坐标仿射变换?第2部分

    我有与这里描述的相同的问题 如何使用python进行坐标仿射变换 我试图使用所描述的方法 但由于某些原因我会收到错误消息 我对代码所做的更改是替换主系统和辅助系统点 我通过使用不同的原点创建了辅助坐标点 在我正在研究这个主题的实际情况中 测
  • 旋转后图像不在正确的位置(图形)

    我试图以不同的速率显示两个直径为 512untis 的旋转轮 但我无法删除以前绘制的图像图形并将旋转的图形设置在正确的位置 现在我正在以任意角度进行旋转 我尝试了 affineTransform 并获得了旋转 但很奇怪 就像所有像素都散开一
  • 在任意角绘制图像

    所以我有一个正常的形象 我在矩形图像的每个角上定义了单击监听器和拖动监听器 我想自由地变换每个角并将其绘制在屏幕上 AffineTransform 类提供了转换的可能性 但我找不到实现这一点的方法 我已经使用 Matrix setPolyt
  • AffineTransform 截断图像

    我有一个图像 我必须将其旋转 45 90 135 180 度 我在做什么 try BufferedImage src ImageIO read new File src png double ang Math toRadians 90 Af
  • JComponent JPanel 缩放、平移和坐标问题

    我有一个JPanel带有用户可以缩放和平移的矢量图像 覆盖此图像的是 透明 JComponent 我允许用户注释底层图像 这在全尺寸下效果很好 但是如果我放大 使用AffineTransform 重叠坐标也会受到影响 因此 如果用户在图像上
  • 在Java中如何确定仿射变换的矩形是否包含某个点?

    我正在尝试制作一个交互式 GUI 但每当单击 拖动该矩形时 我都需要移动某个对象 基本上我想知道一个经过仿射变换的矩形是否包含一个特定的点 x y 有没有办法做到这一点 我尝试过使用contains 方法 但它不适用于已进行仿射变换的矩形
  • 如何在java中弯曲图像

    有什么办法可以弯曲BufferedImage在Java中 我认为如果我将图像裁剪成更小的部分并旋转它们 那么我基本上会弯曲图像 但它似乎不起作用 这是我创建的方法 This is a recursive method that will a
  • 从 3 个点生成 AffineTransform

    给定坐标系 A 中的 3 个点 x 和 y 坐标 和坐标系 B 中的 3 个对应点 我如何导出将从 A 转换为 B 的 AffineTransform 我的问题类似于创建变换以从一个矩形映射到另一个矩形 https stackoverflo
  • 在哪里可以找到 SimpleITK 文档和参考信息?

    我有兴趣尝试使用 SimpleITK 来解决我的成像问题 您能告诉我文档和培训材料在哪里吗 SimpleITK 已记录here http www itk org SimpleITKDoxygen html annotated html 并且
  • 计算图像特征配准中的仿射变换矩阵

    我有两张图像 一张是对另一张应用仿射变换的结果 我可以通过使用 OpenCV 中的 ORB create 函数提取点来使用单应性注册它们 但是 我想计算此变换所需的仿射矩阵 有什么方法可以简单地通过两张图像来做到这一点吗 检测旋转的矩形并使
  • Matlab中如何imwarp转点?

    我正在使用 Matlab 将图像转换为目标图像 我有几何变换 tform 例如这是我的 tform 1 0235 0 0022 0 0607 0 0 0276 1 0002 0 0089 0 0 0170 0 0141 1 1685 0 1
  • 在java中旋转图像

    我正在寻找旋转图像 我有一个JInternalFrame其中包含一个JLabel 标签包含图像 旋转图像后 我需要调整内部框架的大小 我当前的代码旋转图像 但图像边缘周围有黑色并且偏离中心 对于如何解决这个问题 有任何的建议吗 public
  • Qt 创建者 + MITK (Linux)

    我正在尝试使用MITK 与 Qt Creator 我已经通过 ccmake 成功编译并使用了 VTK 和 ITK 我已经编译了 MITK超级建造模式 它下载 CTK VTK ITK 等 然后我就配置好了 我已经用 make 编译了 大约两个

随机推荐

  • 将 NSDecimalNumber 转为负数

    我正在寻找一种方法来扭转NSDecimalNumber乘以负数 1 decNumber is the one I would like to turn negative NSDecimalNumber decNumber values ob
  • getter 是否应该返回对象实例的副本以避免副作用?

    我想获取从类的函数返回的值 在我的班级里 public class MyClass private Color color new Color 0f 0f 0f 1f public Color getColor return this co
  • 多维 np.argmax?

    我有一个形状为 n n g 的 3D 数组 并且我需要每个 n n argmax 即结果应该是每个长度为 g 的两个索引向量 x y 直观的解决方案是 array np random uniform size 5 5 1000 np arg
  • Node.js、(Hi)Redis 和 multi 命令

    我正在使用 node js 和 redis 并通过此命令安装了hiredis 库 npm install hiredis redis 我在这里查看了多个示例 https github com mranney node redis blob
  • 使用调查权重时如何为 Logit 模型生成边际效应?

    我通常使用 mfx 包和 logitmfx 函数生成 logit 模型边际效应 然而 我当前使用的调查具有权重 由于某些人群中的过度采样 这对样本中 DV 的比例有很大影响 而 logitmfx 似乎没有任何方法包含权重 我已经用 svyg
  • PhantomJs 脚本中的 Ajax 请求

    Problem phantomJs 脚本中对本地页面的 Ajax 请求不起作用 无响应 问题 我怎样才能让它发挥作用 有什么想法或可能的解决方案吗 描述 我正在运行 phantomJs 脚本 我需要访问另一个页面 本地 中的 php 函数提
  • 如何从 Java Web Start (JDK 8) 升级到 jlink (JDK 9+) 以实现自动更新应用程序?

    Java 8 及之前的版本有Java网络启动 https www java com en download faq java webstart xml 当我们更改应用程序时 它会自动更新应用程序 Oracle 建议用户迁移到jlink ht
  • 网络模拟器? [关闭]

    Closed 这个问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 您是否知道能够模拟网络条件 例如带宽受限 延迟 端口关闭 拥塞 冲突 的软件 特定于平台很好 但我希望
  • Facebook JavaScript SDK 是否有 TypeScript 接口定义

    TypeScript 包包含 Node js 和 jQuery 的接口定义 我想知道是否有人已经为 Facebook JavaScript SDK 编写了定义 你可以用tsd https github com DefinitelyTyped
  • Eclipse RCP 应用程序:如何禁用特定扩展?

    我正在使用 Eclipse HELIOS 编写富客户端应用程序 以下条目会自动添加到我的应用程序 视角菜单 中 Java Java 浏览 Java 类型层次结构 团队同步 我需要摆脱他们 我正在使用扩展点 org eclipse ui ac
  • SQL Server SP_SEND_DBMAIL 图像文件附件

    我正在表上使用触发器来使用 sp send dbmail 发送电子邮件 我想在图像类型的电子邮件中包含文件附件 jpeg 的原始数据存储在二进制类型的 ndl Image 列中 我有以下代码 DECLARE ReferenceID varc
  • 使用适用于 Windows 的 Git 推送到 GitHub 时出错

    我已经在 GitHub 上创建了一个 Git 存储库 也创建了一个本地存储库 首先 我将远程存储库拉入本地存储库 然后我添加了一个文件 暂存该文件 提交了它 现在我尝试再次推送到远程存储库 但失败并显示以下消息 Pushing to htt
  • 在 Flutter 中隐藏滚动条上的底部导航栏

    我在正文和底部导航栏中有一个博客文章列表 我想在帖子列表向下滚动时使用向下滑动动画隐藏底部导航栏 并在向上滚动时使用向上滑动动画可见 怎么做 此解决方案只是解决此问题的方法 可能会发生一些有害的变化 import package flutt
  • Linq to NHibernate 与 ICriteria

    我通常经常使用 LINQ 尤其是 LINQ to Objects 因此我对 LINQ 相当熟练 我正在考虑使用 LINQ to NHibernate 作为我的 NHibernate 项目的查询语言 当我编写一些测试时 我注意到 LINQ t
  • 使用 Spring Kafka 添加自定义标头

    我计划使用 Spring Kafka 客户端在 Spring Boot 应用程序中使用 kafka 设置并生成消息 我看到 Kafka 0 11 中对自定义标头的支持详情here https issues apache org jira b
  • ionic 2 - inappbrowser“browser.on(...).subscribe 不是函数”错误

    我遵循这个http ionicframework com docs native in app browser http ionicframework com docs native in app browser 在appbrowser中使
  • Ruby 解压数组以阻止

    settings 127 0 0 1 80 0 0 0 0 443 我能怎么做 settings each do ip port end 代替 settings each do config ip port config end 您的第一个
  • 为什么我的图标不会在新的 Chrome 网上应用店中显示为完整尺寸?

    我在 Chrome 应用商店中发布了一个扩展程序 昨晚 网上商店的外观焕然一新 现在我的图标看起来非常小 位于拼图游戏的内部 我跟着指示 https developer chrome com extensions manifest icon
  • iPhone - 是否不可能获取 CALayers 组合的内容?

    我在屏幕外 UIView 比 320x480 大得多 上有一个 CALayer 进行 3D 转换 如何将 UIView 上看到的内容转储到 UIImage 中 注意 我已经编辑了问题以包含此代码 这就是我创建图层的方式 CGRect are
  • 如何从ITK注册中获得变换仿射?

    进行 3D MRI 扫描A B and C我想执行仿射 联合 配准B onto A 取配准的变换仿射矩阵并将其应用于C 我的问题是配准变换的仿射矩阵的符号错误 也许是因为方向错误 The TransformParameters包含 12 个