MINC/软件开发/MINC2.0 用户指南
MINC 是一个用于存储和处理医学图像的软件系统,最初由麦吉尔脑成像中心的彼得·尼林于 1993 年开发。MINC 的名字是医学成像网络通用数据格式 (Medical Imaging NetCDF) 的缩写。MINC 的构想是允许研究人员使用一组通用的工具和文件来处理各种模态的医学图像。该文件格式最初被定义为由 UCAR (大学大气研究公司) 的 Unidata 项目中心创建的 NetCDF (网络通用数据格式) 文件格式的专门形式。NetCDF 格式、库和工具旨在存储任意维度的通用数据集。选择 NetCDF 是因为它实现了为 MINC 系统设想的许多功能。
与大多数其他医学图像数据格式一样,MINC 允许医学图像数据采用各种数据类型或范围,并定义一组标准支持数据来描述图像采集参数或患者详细信息。
然而,MINC 在几个方面不同于大多数其他医学图像格式
- MINC 本质上是N 维的。MINC 数据可以采用任意数量的空间、时间或其他维度进行结构化,并且这些维度可以按任意顺序组织。实际上,NetCDF 将数据限制为最多 100 个维度,但这并没有被证明是一个有意义的限制。
- MINC 是多模态的。MINC 已被用于存储 CT、MRI、PET、EEG 和其他医学图像数据。
- MINC 是可扩展的。MINC 文件可以包含任意数量的支持属性和数据。如果您的研究要求您跟踪患者的血压或精神病史,则可以将这些信息添加到您的 MINC 文件的标题中,而无需担心
- MINC 是自描述的。MINC 中使用的大多数属性和变量都具有描述性名称和值,用户可以轻松解释。
- MINC 允许基于每个图像或每个切片的体素数据的缩放。
- MINC 定义了体素和世界坐标系。MINC 文件有效地存储了一个线性变换,该变换定义了文件中体素的逻辑布局与某个参考物理坐标系之间的关系。物理坐标系可以是扫描仪的本机坐标,也可以是更通用的坐标空间,例如 Talairach 系统。
与许多专业计算术语一样,“MINC”一词多年来以多种不同的方式使用。它可以指文件格式本身,即 MINC 文件中数据的物理和逻辑布局的定义。它也被应用于编程环境,该环境存在于提供对 MINC 格式文件的访问。最后,该术语有时指快速发展的分析、修改或显示 MINC 文件的程序和脚本集。
“核心”MINC 系统可以被认为包括以下内容
- 文件格式本身
- “libminc”编程接口,允许程序员完全访问格式。
- “volume_io”编程接口,它提供了一个简化的但受限的编程接口来访问 MINC 格式。
- 使用这些库编写的一组工具。
除了核心 MINC 工具之外,还存在大量额外的应用程序,它们对 MINC 文件执行更复杂的操作。这些包括用于可视化、图像增强或校正、自动组织分类和图像配准的程序。
MINC 2 的设计旨在解决在 MINC 1 中发现的几个特定问题。
- 文件大小限制。使用的 NetCDF 文件格式使用 32 位指针来寻址文件中的对象。这有效地将文件限制为最大 2 GB 的大小。随着非常高分辨率的大脑图谱数据 (来自宏观切片机或其他来源) 和大型 fMRI 数据集的出现,很明显这种限制可能会成为一个严重问题。
- 数据类型限制。NetCDF 格式定义了一组小的固定数据类型 - 整数、浮点数和 ASCII 字符串。NetCDF 不支持聚合数据 (数组或结构) 或带标签 (枚举) 的数据作为基本数据类型。
- 存储选项有限。NetCDF 文件将数据存储在一个连续的数组中。这会阻止在 NetCDF 格式中添加块可寻址数据或内部数据压缩。
由于大多数这些问题都存在于 MINC 1 文件格式中,因此很明显 MINC 2 的设计将需要对文件格式进行重大修改。开发 MINC 2 的团队选择用 HDF5 库替换 NetCDF,作为 MINC 2 格式的基础。HDF5 提供了许多 NetCDF 中不可用的高级功能。
- 超立方体 - N 维数据块。如果所有维度都相等,则称为“超立方体”。
- 不透明数据类型 - 面向对象的概念,用于引用其实现细节对程序员明确隐藏的数据类型。
- 矢量维度 - 维度 (必须始终是最快变化的维度),它指定图像中特定点的数值,例如 RGB 图像。在 MINC2.0 中,向量被认为是记录类型,可以通过为卷设置 flatten_flag (卷将有一个额外的维度,该维度将被设置为记录) 来创建。
- 卷 - MINC 文件。卷和文件可以互换使用,因为使用卷用于超过 3 个维度并不常见,而 MINC 2 是 N 维的。
- 体素 - 体积元素,类似于“像素”表示“图像元素”。多维图像中的单个数据点。
- 体素和世界坐标系 - MINC 2 定义了“体素”和“世界”空间坐标系。
对于每个维度,世界坐标转换由以下属性指定:step、start 和 direction_cosines,因为 MINC 文件允许具有非正交轴,维度与命名轴不完全对齐。例如,xspace 世界坐标使用 x = (v*step + start) * direction_cosines 计算,其中 x 是 x 世界坐标,v 是体素计数 (从零开始)。假设 xspace 维度与世界 x 轴一致,即 direction_cosine = (1,0,0),则 step 属性的大小指定体素之间的距离,step 属性的符号指定轴的方向。否则,direction_cosines 确定数据相对于世界坐标系的定向,即 direction_cosine 为 (0.9, 0.43589, 0)。有关详细公式,请参考 Robert D. Vincent 撰写的《MINC 2.0 文件格式》第 2.1 节。
基本 MINC 软件发行版中包含的核心工具具有一些共同的特点。首先,它们都可以在任何 MINC 文件上正常运行,无论其维度或数据类型如何。其次,它们作为 UNIX “命令行” 工具实现,没有图形用户界面。虽然这可能会使工具学习起来有些困难,但它也具有易于构建更复杂的应用程序的优势,这些应用程序可以在脚本语言或批处理编程环境中调用这些工具。最后,这些工具的设计使得输入文件永远不会被修改:任何 MINC 工具的结果,如果适用,总是会生成一个或多个新的 MINC 文件。
MINC 工具使用大量有时令人困惑的命令行选项来控制工具的行为。本节将尝试解释一些更常见的命令行选项,而不是单独处理每个工具。
大多数选项以单个“破折号”字符开头。
这些命令行选项中的许多都有默认值,因此,如果您没有显式指定值,程序将假设您希望使用“正常”行为。下面每个条目中以粗体显示的都是默认选项。
-version
- 此选项将导致工具打印其版本号并退出。不会执行其他操作。-help
- 此选项要求工具打印其识别的所有选项的摘要,并简要描述每个选项。-noclobber
和-clobber
- 这些选项控制 MINC 工具是否会覆盖现有的输出文件。所有 MINC 工具的正常行为是拒绝替换现有文件。
例如,如果您已经在与 'input.mnc' 相同的目录中有一个名为 'test.mnc' 的文件,并且您键入以下内容
mincreshape -transverse -noclobber input.mnc test.mnc
程序将拒绝运行,因为这样做会破坏现有的 test.mnc
文件。如果您指定 -clobber
选项,程序将用新的输出文件替换现有文件。
-quiet
和-verbose
- 指定 '-verbose' 将导致程序打印更广泛的中间操作和计算列表,这可能有助于调试。指定 '-quiet' 将抑制大多数这些消息。-2
- 此选项告诉程序生成 MINC 2 格式的输出文件。
新工具 'mincconvert' 已创建用于在 MINC 1 和 MINC 2 格式之间进行转换。要将 MINC 1 文件转换为 MINC 2 文件,您可以像这样使用 mincconvert
mincconvert -2 input.mnc output.mnc
要从 MINC 2 转换回 MINC 1 格式,请省略 '-2' 选项
mincconvert input.mnc output.mnc
对于从 Analyze 或 DICOM 等其他格式转换为 MINC 2,可能需要先转换为 MINC 1 格式,然后使用 mincconvert 从 MINC 1 转换为 MINC 2。此限制将在这些转换脚本的未来版本中删除。
每个核心 MINC 工具现在都会自动检测 MINC 1 或 MINC 2 文件作为输入文件,并且在任一情况下都能正常工作。
此外,每个可以生成 MINC 文件作为输出的核心 MINC 工具现在都接受 '-2' 选项来指示需要 MINC 2 格式的输出。
图像几何和离散化
mincreshape
- 此工具用于重新构造 MINC 文件中的数据。它可以用于提取数据的子集,或重新排序数据中的维度。它不会修改数据的缩放,也不会更改文件的世界坐标系。执行维度长度更改,但是这些更改是使用非常简单的体素平均或加倍来实现的。对于更复杂的 文件重塑,请参见mincresample
。mincresample
- 此工具用于在 MINC 文件上应用任意坐标转换。可以执行三三次、三线性或最近邻插值。mincconcat
- 此工具将沿特定轴连接任意数量的 MINC 文件,生成单个输出文件。
体素计算
mincmath
- 对一个或多个 MINC 文件执行简单的“体素”数学运算。例如,mincmath
可用于将两个体积相加,将常数添加到体积,计算体积的平方或倒数等。mincstats
- 计算 MINC 文件的一些基本统计特征。这些包括体素计数、体积、全局最小值和最大值、总和、方差、标准差等。mincstats
还可以计算和保存直方图以及与直方图相关的统计数据。minccalc
- 与mincmath
类似,minccalc
可以执行更广泛、更复杂的涉及一个或多个 MINC 文件的体素数学运算。mincaverage
- 从多个输入体积计算平均 MINC 体积。minclookup
- 对 MINC 文件执行“查找表”转换,根据任意函数将值替换为新值。例如,文件可以转换为灰度、光谱 RGB 值。mincmakescalar
- 通过选择或组合矢量元素将矢量图像转换为标量图像。mincmakevector
- 将一组标量图像转换为单个矢量图像。
实用函数
mincinfo
- 从 MINC 文件打印任意一组标头字段。mincheader
- 打印 MINC 文件的所有标头信息。minc_modify_header
- 更改 MINC 文件中的单个属性。这对于添加或更改支持信息或更正坐标信息而不更改数据很有用。但是,此工具应谨慎使用,因为它会直接更改文件的标头,并且不会创建备份。mincedit
- 编辑 MINC 文件。MINC 文件被转换为文本表示形式,该表示形式会自动加载到文本编辑器中。当用户完成编辑会话时,文本表示形式将转换回 MINC 格式。原始文件的备份副本将被保留。mincview
- 查看 MINC 文件。minchistory
- 打印 MINC 文件的“历史记录”属性,该属性提供用于生成此文件的命令的审计跟踪。mincdiff
- 显示两个 MINC 文件之间的差异。minccopy
- 将数据从一个 MINC 文件复制到另一个文件。
基本文件格式转换
mincconvert
- 用于将 MINC 1 文件转换为 MINC 2 文件,反之亦然。minctoraw
- 将 MINC 文件转换为原始数据文件。原始数据文件是一个仅包含体素值的文件,这些值存储在井然有序的排列中。rawtominc
- 将原始数据文件转换为 MINC 文件。mincextract
- 提取 MINC 文件数据的任意块。mincpik
- 从 MINC 文件生成图形图像。
扩展文件格式转换
ecattominc
- 将 ECAT 图像数据转换为 MINC 格式。minctoecat
- 将 MINC 图像数据转换为 ECAT 格式。nii2mnc
- 将 NIfTI-1 和 Analyze 图像数据转换为 MINC 格式。mnc2nii
- 将 MINC 图像数据转换为 NIfTI-1 或 Analyze 格式。upet2mnc
- 将微型 PET 图像数据转换为 MINC 格式。
可视化
MNI Register
- 一个可视化程序,支持通过对两个显示图像上的同源点进行标记来进行图像配准。MNI Display
- 一个复杂的可视化程序,支持显示体素和 3D 表面图像数据。xdisp
- 用于可视化动态图像的程序。postf
- 用于可视化动态图像的非常简单的程序。
数据模拟
mrisim
- 用于生成高度逼真的模拟解剖学 MRI 图像的工具。
图像配准
mni_autoreg
- 用于计算变换以将两个 MRI 体积配准或将一个 MRI 体积配准到标准坐标空间的工具。
强度归一化
N3
- 非参数非均匀强度归一化提供了一种方法,用于自动校正由于射频场不均匀性、涡流和/或患者解剖结构导致的 MRI 图像强度平滑变化。
组织分类
classify
- 分类提供各种基于图像强度的体素级标签算法。包含有监督和无监督分类器。
其他可用的工具仍在开发中
mincdti
- 从 MINC 图像计算扩散张量。mincfft
- MINC 图像的快速傅里叶变换。mincmorph
- 执行标准图像处理操作:膨胀、腐蚀、高通、低通、钳位、二值化、卷积等。mincsample
- 在可选掩模体积的情况下,从一个或多个 MINC 文件中提取随机子样本。volregrid
-
哪里可以获得更多信息
[edit | edit source]您可以从两个来源获得有关每个核心 MINC 工具的更多信息。每个工具都有一个 UNIX 'man' 页面,它对工具的功能以及控制其行为的选项进行了详细的解释。
要查看工具选项的简要列表,请在命令中使用 -help
选项。
使用 MINC 2 库
[edit | edit source]程序员可以使用 MINC 2 库来创建操作 MINC 文件的新程序。该库是为与 'C' 编程语言一起使用而设计和编写的。无需了解 HDF5 或 NetCDF 即可使用 MINC 2 库。
本文档无法全面解释库的所有功能。有关 MINC 2 编程接口的详尽参考,请参阅文档 MINC 2.0 Programmer's Reference Manual。
头文件和库文件
[edit | edit source]通过在源文件中包含文件 'minc2.h' 并在 libminc2.a 库中链接,MINC 2 库可以包含在任何 C 或 C++ 程序中。这可以通过大多数 UNIX 链接工具完成,方法是在编译器的链接选项中添加以下内容
-lminc2 -lhdf5 -lnetcdf
要构建 MINC 2 程序,必须显式地与 HDF5 库和 NetCDF 库链接。
函数返回值
[edit | edit source]大多数 MINC 2 库函数返回一个带符号的整数值,该值报告操作是成功(MI_NOERROR
)还是失败(MI_ERROR
)。更一般地说,负返回值被解释为错误结果,而零或正返回值被解释为表示操作成功。
打开和关闭体积
[edit | edit source]可以使用函数调用打开 MINC 2 体积
miopen_volume(const char *path, int mode, mihandle_t *hvol)
;
path
参数给出要访问的文件的绝对或相对路径名。
mode
参数控制文件是仅以只读方式打开(MI2_OPEN_RDONLY
)还是以读写方式打开(MI2_OPEN_RDWR
)。
文件 'handle' 在后续文件操作中必须使用,它在 hvol
参数中返回。程序使用完文件后,应通过调用关闭文件并释放文件句柄
miclose_volume(mihandle_t hvol);
以下是一个展示这两个函数用法的示例
#include <minc2.h>
main() {
int result;
mihandle_t hvol;
result = miopen_volume("/home/sparky/test.mnc",
MI_OPEN_RDONLY, &hvol);
if (result != MI_NOERROR) {
fprintf(stderr, "Error opening the input file.\n");
}
/* Work with the file here. */
miclose_volume(hvol);
}
数据类型
[edit | edit source]类型
[edit | edit source]这些类型指的是数据在文件中的存储格式。在某些情况下,可能会应用额外的缩放或其他转换,具体取决于体积的类别。
- MI_TYPE_BYTE - 8 位带符号整数。
- MI_TYPE_SHORT - 16 位带符号整数。
- MI_TYPE_INT - 32 位带符号整数。
- MI_TYPE_FLOAT - 32 位浮点数。
- MI_TYPE_DOUBLE - 64 位浮点数。
- MI_TYPE_STRING - ASCII 字符串。
- MI_TYPE_UBYTE - 8 位无符号整数。
- MI_TYPE_USHORT - 16 位无符号整数。
- MI_TYPE_UINT - 32 位无符号整数。
- MI_TYPE_SCOMPLEX - 16 位带符号整数复数
- MI_TYPE_ICOMPLEX - 32 位带符号整数复数
- MI_TYPE_FCOMPLEX - 32 位浮点数复数
- MI_TYPE_DCOMPLEX - 64 位浮点数复数
- MI_TYPE_UNKNOWN - 用于记录或数组类型。
类别
[edit | edit source]体积的类别描述了如何解释体素数据。最典型的情况是体积具有整数类型,但类别值为 'real'。这对应于典型的 MINC 1 文件,该文件定义了缩放
- MI_CLASS_REAL - 浮点数。数据将被解释为浮点数,无论存储类型如何。可用于任何整数或浮点数类型。
- MI_CLASS_INT - 整数。数据将被解释为整数值。可用于任何整数类型。
- MI_CLASS_LABEL - 标记或枚举数据。假设体素的值来自一个离散集。这些值可以分配符号名称来澄清数据的解释。可用于任何整数类型。
- MI_CLASS_COMPLEX - 具有实部和虚部的复数数据。只能用于复数类型(整数或浮点数)之一。
- MI_CLASS_UNIFORM_RECORD - 统一记录结构,本质上是一个带有命名条目的数组。
- MI_CLASS_NON_UNIFORM_RECORD - 非统一记录结构。这尚未实现。
维度和坐标系
[edit | edit source]维度定义
[edit | edit source]维度只是一个轴或索引,数据沿其存储。典型的扫描可能是二维或三维,而功能数据可能存储在一个四维文件中,其中包含三个空间维和一个时间维。
MINC 2.0 维度
[edit | edit source]MINC 图像体积/文件的每个维度都由其 name
指定。MINC2 定义了标准命名约定,例如 xspace, yspace, zspace
(空间维度)、xfrequency, yfrequency, zfrequency
(空间频率维度)、tfrequency
(时间频率维度)、time
(时间维度)以及最后 vector-dimension
(请参阅第 1.2 节)。
重要的是要注意,在 MINC 2 中,某些默认解释和属性与标准命名维度相关联。但是,这不会对 MINC 2 维度定义施加任何限制,因为用户可以自由地为每个维度定义新的名称、解释和属性。
维度属性
[edit | edit source]每个维度都有一个 class
,它指定其整体解释:空间、时间、空间频率、时间频率或用户定义(即任意)维度。以下是 minc 2 中定义的维度类别列表。
- MI_DIMCLASS_ANY - 不关心(或未知)
- MI_DIMCLASS_SPATIAL - 空间
- MI_DIMCLASS_TIME - 时间
- MI_DIMCLASS_SFREQUENCY - 空间频率
- MI_DIMCLASS_TFREQUENCY - 时间频率
- MI_DIMCLASS_USER - 用户定义的任意轴
- MI_DIMCLASS_RECORD - 记录作为维度
以上定义还创建了一个更灵活的命名约定,其中任何名称都可以定义为任何维度类别。
除了name
和class
,MINC 2 还为每个维度定义了许多其他属性,这些属性指定了数据的解释方式。
description
属性用于指定人类可读的文本,该文本提供有关维度解释的一些信息。例如,它通常用于描述维度的方向相对于患者。description
属性仅针对命名维度xspace
、yspace
、zspace
设置为默认文本,但用户可以为任何维度设置该属性。例如,xspace
定义为从患者的左侧增加到右侧。
unit
属性也是人类可读的文本,它定义了沿每个维度采样数据点之间的距离单位。默认的unit
属性设置为毫米(即“mm”)。
spacing
维度属性是人类可读的文本,它定义了采样数据点在空间中彼此之间的间隔是恒定的还是随机的(即规则的与不规则的)。spacing
属性默认设置为'regular__'。
start
属性是一个数字,它指定了第一个采样数据点在世界坐标系中的位置(参考体素与世界子节)。此属性默认设置为零。step
属性是一个正数,表示沿规则采样维度的采样数据点之间的间隔大小。负值仅表示采样数据点具有相反的方向。此属性默认设置为 1。不规则采样维度必须定义为每个采样数据点对定义的间隔值列表,这在 MINC 2 中定义为offset
属性。
length
属性是一个数字,定义了沿维度的采样数据点的总数。direction_cosines
属性是一组与空间维度关联的三个向量,定义了轴相对于“真实” x、y 或 z 坐标的精确方向。有关维度属性的完整列表,请参阅MINC2.0 PI,网址为http://www.bic.mni.mcgill.ca/software/minc2/api_doc/minc_20.html
MINC 2 文件可以定义任意数量的维度。在 MINC 2 库中,维度由一个称为维度句柄的不透明数据类型表示,它由'C' typedef midimhandle_t
定义。通过使用维度句柄,用户可以访问和修改所有维度属性。
在创建新维度之前,必须指定四个基本属性。其他属性将设置为默认值,这些默认值可以在创建维度后单独更改。
micreate_dimension(const char *name, midimclass_t class,
midimattr_t attr,unsigned long length,
midimhandle_t *new_dim_ptr);
访问或修改任何维度属性都是通过使用以下方法完成的
miget_dimension_ property()
miset_dimension_ property()
其中'property'可以替换为任何维度属性。例如,
miget_dimension_units(midimhandle_t dimension,
char **units_ptr);
miset_dimension_units(midimhandle_t dimension,
const char *units);
可以使用以下函数检索与打开的 MINC 文件关联的维度
miget_volume_dimensions(mihandle_t hvol, midimclass_t class,
midimattr_t attr, miorder_t order,
int max_dims, midimhandle_t dims[]);
其中 miorder_t
是一个枚举类型标志,它确定维度顺序是通过文件(即维度创建的顺序)还是通过明显顺序(即除文件顺序之外的任何顺序)来确定的,必须由用户设置。
最后,要释放与维度关联的内存,必须将维度句柄传递给mifree_dimension_handle()
。请注意,对与体积关联的维度调用mifree_dimension_handle()
会导致错误。
mifree_dimension_handle(midimhandle_t dim_ptr)
由于 MINC 文件可以任意组织数据,因此 MINC 2.0 编程接口允许程序员指定维度的明显顺序和每个维度的明显方向。这使程序能够以最方便的方式指定排序,以便数据可以以任何方式呈现。
程序员可以为给定体积设置“明显”维度顺序。指定明显维度顺序会导致库将所有坐标和数据转换为数据存储在明显顺序中的样子。如果一组必须同时处理的三个体积的维度分别是 x、y、z、z、y、x 和 y、z、x,那么程序将它们都视为数据以 z、y、x 顺序存储可能会很有用。
转换数据块的维度会导致数据块在读取后或写入之前在内存中重新构造。显然,这种重新构造需要时间,会影响数据吞吐量。
如果明显的维度顺序恰好与体积的文件维度顺序匹配,则不会执行任何特殊处理。
对于每个维度,程序员还可以指定一个明显方向。此明显方向可以通过以下四种方式之一来指定
- 原生文件顺序 - 维度的方向与其在文件中的显示方式完全相同。
- 反文件顺序 - 维度的方向与文件顺序相反。
- 正向顺序 - 世界坐标系中维度的方向保证沿增加的体素坐标为正。此模式仅在步长为负时反转维度。
- 负向顺序 - 世界坐标系中维度的方向保证沿增加的体素坐标为负。此模式仅在步长为正时反转维度。
属性是小型数据集、文本或数字,用于描述附加到它们的变量的额外信息,并且不包含有关医学图像本身的任何信息。
history
和title
等属性包含有关整个 MINC 文件的信息,并附加到“minc-2.0”组本身。其他属性(如vartype
和version
)不包含有关图像的任何信息,但支持它们附加到的变量,例如/minc-2.0/dimensions/xpsace/vartype。最后,属性(如valid_range
)提供有关图像数据的其他信息,例如/minc-2.0/image/0/image/valid_range。有关属性及其定义的完整列表,请参阅 Robert D. Vincent 编写的MINC 2.0 文件格式的第 4 节。
MINC 2 库定义了一组用于操作属性的函数。要设置属性的值并创建它(如果它尚不存在),请使用以下方法
miset_attr_values(mihandle_t volume,
mitype_t attr_data_type,
const char *path,
const char *name,
int length, void *values)
其中文件句柄、数据类型、属性路径(即在层次结构中创建此属性的位置,/minc-2.0/history)、属性的名称、其长度(即 100 个字符)以及属性的值作为参数传递。属性的值使用以下方法检索,
miget_attr_values(mihandle_t volume,
mitype_t attr_data_type,
const char *path,
const char *name,
int length, void *values)
最后,要删除属性,请使用
midelete_attr(mihandle_t volume,
const char *path, const char *name)
提供了几个用于在 MINC 文件中读取和写入数据的函数。
函数可以根据两组标准分为四类。
首先,某些函数操作单个体素,而其他函数操作“超立方体”数据,该数据可以是任何大小和维数,直至整个文件大小。
其次,某些函数读取或写入“原始”或“体素”数据,而其他函数操作“真实”数据。真实数据是根据图像的体素和真实范围缩放的数据。
通常,以大块而不是单个体素读取和写入文件效率更高,因此,如果速度对您的应用程序很重要,最好避免使用单个体素函数。
所有超立方体操作都需要程序员指定超立方体的起点和大小。这些参数以数组形式传递。start[]
(有时称为voxel_offsets[]
)数组指定超立方体的起点。它可以被认为是体素维度中距离真实起点(0,0,0)最近的点。count[]
(有时称为sizes[]
)数组指定沿每个维度所需超立方体的长度。
逻辑上,count[]
数组中的任何值都不应该为零,因为这会导致超立方体总体积为零。换句话说,你将不会读取任何数据。
另一个约束是 start
值加上 count
值必须始终小于或等于体素维度中的长度。
每个体素读写函数都假设 start[]
和 count[]
数组中指定的坐标和长度以“表观”顺序排列。默认情况下,表观顺序与文件顺序相同。
举个例子,假设你有一个四维文件,其结构根据维度 xspace
、time
、zspace
、yspace
组织,它们的长度分别设置为 X、T、Z 和 Y。
我们使用 miset_apparent_dimension_order_by_name
为这些维度分配一个更传统的顺序
static char *dimorder[] = { "time", "zspace","yspace","xspace" }
miset_apparent_dimension_order_by_name(hvolume, 4, dimorder);
现在假设我们想在一个操作中读取整个文件。为此,我们可以设置以下内容
unsigned long start[4], count[4];
short buffer[T][Z][Y][X];
start[0] = start[1] = start[2] = start[3] = 0;
count[0] = T;
count[1] = Z;
count[2] = Y;
count[3] = X;
miget_voxel_value_hyperslab(hvolume, MI_TYPE_SHORT, start, count, buffer);
或者,我们可能只想要将来自一个时间位置的数据读入一个三维数组
unsigned long start[4], count[4];
short buffer[Z][Y][X];
start[0] = t; /* The desired time value */
start[1] = start[2] = start[3] = 0;
count[0] = 1;
count[1] = Z;
count[2] = Y;
count[3] = X;
miget_voxel_value_hyperslab(hvolume, MI_TYPE_SHORT, start, count, buffer);
另一种可能性是读取特定空间位置的整个时间序列
unsigned long start[4], count[4];
short buffer[T];
start[0] = 0; /* Start at time=0 */
start[1] = z; /* z,y,x = spatial coordinate */
start[2] = y;
start[3] = x;
count[0] = T;
count[1] = count[2] = count[3] = 1;
miget_voxel_value_hyperslab(hvolume, MI_TYPE_SHORT, start, count, buffer);
体素转换的详细信息
[edit | edit source]从真实数据到体素数据的转换,或从体素数据到真实数据的转换,可以用以下关系表示
其中 R(c) 是图像在坐标位置 c 的真实值,而 V(c) 是图像在相同坐标位置的体素值。 和 值对应于最大和最小真实值,它们也可能是位置的函数,尽管在更低维度上是如此。 和 对整个体积是全局的,不会随位置而变化。
有关这些缩放值的更多信息,请参阅以下函数
int miget_volume_valid_range(mihandle_t volume,
double *valid_max,
double *valid_min);
int miget_slice_range(mihandle_t volume,
const unsigned long location[],
double *slice_max,
double *slice_min);
单个体素,体素数据函数
[edit | edit source] miget_voxel_value(mihandle_t volume,
const unsigned long location[],
double *voxel_ptr);
miset_voxel_value(mihandle_t volume,
const unsigned long location[],
double voxel);
这两个函数读取或写入单个体素,坐标由 location
数组给出。location
数组的长度必须等于体积中的维度数量。对数据执行的唯一转换将是值保留的表示形式更改。如果实际存储类型无法表示传递给 miset_voxel_value()
函数的值,则存储的值将是未定义的。
单个体素,真实数据函数
[edit | edit source] int miget_real_value(mihandle_t volume,
const unsigned long location[],
double *value_ptr);
int miset_real_value(mihandle_t volume,
const unsigned long location[],
double value);
这两个函数读取和写入单个体素,同时执行上述数据转换。
超立方体,体素数据函数
[edit | edit source] int miget_voxel_value_hyperslab(mihandle_t volume,
mitype_t buf_type,
const unsigned long start[],
const unsigned long count[],
void *buf_ptr);
int miset_voxel_value_hyperslab(mihandle_t volume,
mitype_t buf_type,
const unsigned long start[],
const unsigned long count[],
const void *buf_ptr);
这两个函数从文件中读取和写入一个超立方体数据,对单个体素不执行任何数据转换。坐标转换可能会执行,具体取决于体积维度和体素的表观方向和顺序。
超立方体,真实数据函数
[edit | edit source] int miget_real_value_hyperslab(mihandle_t volume,
mitype_t buf_type,
const unsigned long start[],
const unsigned long count[],
void *buf_ptr);
miget_real_value_hyperslab
从 MINC 文件中检索选定的超立方体数据。如果文件的类是“real”,则每个体素都会通过使用存储的图像最小值和最大值对其进行缩放来转换。如果文件的类不是“real”,则不会执行任何转换。
int miset_real_value_hyperslab(mihandle_t volume,
mitype_t buf_type,
const unsigned long start[],
const unsigned long count[],
const void *buf_ptr);
miset_real_value_hyperslab
将选定的超立方体数据保存到 MINC 文件。如果文件的类是“real”,则每个体素都会通过使用存储的图像最小值和最大值对其进行缩放来转换。如果文件的类不是“real”,则不会执行任何转换。
int miget_hyperslab_normalized(mihandle_t volume,
mitype_t buffer_data_type,
const unsigned long start[],
const unsigned long count[],
double min,
double max,
void *buffer);
miget_hyperslab_normalized
从文件中读取数据超立方体。除了执行标准转换之外,数据还被规范化,使得值被映射到指定 buffer_data_type
的完整范围内,使得小于或等于 min
的真实体素值将被映射到数据类型可能的最低值,而大于或等于 max
的真实体素值将被映射到数据类型可能的最高值。
在所有必需的维度句柄被定义/分配了它们适当的类别和属性之后,可以通过调用以下函数创建 MINC 2.0 文件
micreate_volume(const char *filename,
int number_of_dimensions,
midimhandle_t dimensions[],
mitype_t volume_type,
miclass_t volume_class,
mivolumeprops_t create_props,
mihandle_t *volume)
其中 filename、维度数量、维度句柄数组、体积类型、体积类别和最后体积属性是给定的参数,文件句柄将在文件成功创建后作为检索参数。micreate_volume
创建文件模板(即关于实际图像、其维度等的全部信息),但不创建实际的图像文件本身。要为文件创建实际图像,在创建文件模板后使用以下函数
micreate_volume_image(mihandle_t volume)
其中句柄是由调用前一个函数检索到的。以下是一个展示这两个函数用法的示例
#include <minc2.h>
main() {
int result;
mihandle_t hvol;
midimhandle_t dim[3];
mivolumeprops_t props;
result = minew_volume_props(&props);
result = miset_props_compression_type(props,
MI_COMPRESS_ZLIB);
result = miset_props_zlib_compression(props, 3);
result = miset_props_multi_resolution(props, 1, 3);
if (result < 0) {
TESTRPT("failed", result);
}
result = micreate_dimension("xspace",MI_DIMCLASS_SPATIAL,
MI_DIMATTR_REGULARLY_SAMPLED,
10,&dim[0]);
if (result < 0) {
TESTRPT("failed", result);
}
result = micreate_dimension("yspace",MI_DIMCLASS_SPATIAL,
MI_DIMATTR_REGULARLY_SAMPLED,
10,&dim[1]);
if (result < 0) {
TESTRPT("failed", result);
}
result = micreate_dimension("zspace",MI_DIMCLASS_SPATIAL,
MI_DIMATTR_REGULARLY_SAMPLED,
6,&dim[2]);
if (result < 0) {
TESTRPT("failed", result);
}
result = micreate_volume("test_multi_h5.mnc", 3, dim,
MI_TYPE_UINT, MI_CLASS_REAL,
props,&hvol);
if (result < 0) {
TESTRPT("failed", result);
}
result = micreate_volume_image(hvol);
if (result < 0) {
TESTRPT("failed", result);
}
}
分块,也称为分块,是指组织图像数据存储的另一种方法。大多数标准操作系统将文件表示为一个一维的八位字节数组。在传统的文件中,多维数据存储在一个简单的连续值数组中。每个连续的值与前一个值相关联,通过文件“变化最快”的维度的增量来确定,该维度通常是最后一个维度。第一个维度是文件“变化最慢”的维度。例如,给定一个具有维度,,和 的三维图像,长度为 , , 和 ,任何位于位置 的体素的正确存储索引可以计算为
这种存储方法具有简单性的优点,并且也方便地模拟了“C”编程语言中数组的内存组织。但是,它有两个主要缺点。首先,它假设所有数据都存储在一个连续的块中。这降低了灵活性,例如,使得实现数据压缩变得极其困难,因为压缩可能会消除相邻数据值之间可预测的关系。其次,这种存储方法本质上有利于沿变化最快维度读取整个部分的输入和输出。在上面的示例中,如果你的程序想要读取一个在 $x$ 和 $y$ 中变化但在固定 $z$ 处的切片数据,它必须读取大部分文件以收集所需数据。
在启用“阻塞”的文件中,数据以更复杂的方式存储。定义了一个与整个文件具有相同维度的块,每个块包含整个数据中的固定大小的块。例如,如果一个文件的总体维度为,而块大小为,则文件的数据将被分组到 1000 个数据块中,每个块包含 1000 个值。第一个块包含所有数据点 ,,和 。在块内,存储布局与上述连续情况相同。
为了使事情更复杂,文件可能包含某种转换表,该表定义了每个块的物理存储位置,因此块可能不会按特定顺序存储。
块结构文件的优点是,通过使系统摆脱严格排序的存储方式,每个块的位置和大小可以有所不同。如果应用压缩算法,一些块将被证明是高度可压缩的,因此会非常小,而相对不可压缩的块将相对较大。在稀疏数组的情况下,可能可以避免为仅包含默认值的块分配空间。
作者
[edit | edit source]John G. Sled, Robert D. Vincent, Leila Baghdadi