NiBabel 是 Python 中用于处理神经影像格式(如 NIfTI、Analyze、MINC 等)的核心库。它广泛应用于脑成像数据的读取、写入、转换和分析。本教程将带你快速掌握其核心功能。

📦 1. 安装 NiBabel

1.1 使用 pip 安装

pip install nibabel

1.2 使用 conda 安装

conda install -c conda-forge nibabel

🧩 2. 核心概念

2.1 NIfTI 文件结构

  • Header:包含元数据(如维度、数据类型、仿射变换矩阵等)。
  • Data:多维数组(如 3D 脑部图像或 4D 时间序列)。
  • Affine:4x4 矩阵,定义体素坐标到世界坐标的映射。

2.2 数据维度

  • 3D 图像:(x, y, z),如 T1 加权解剖图。
  • 4D 图像:(x, y, z, t),如 fMRI 时间序列。

📖 3. 基础操作

3.1 读取 NIfTI 文件

import nibabel as nib

# 加载图像
img = nib.load('data/example.nii.gz')

# 获取数据(返回 numpy 数组)
data = img.get_fdata()

# 查看形状和数据类型
print(data.shape)  # 例如 (128, 128, 64)
print(data.dtype)  # 例如 float32

3.2 写入 NIfTI 文件

# 创建新的 NIfTI 图像
new_img = nib.Nifti1Image(data, affine=img.affine)

# 保存到文件
nib.save(new_img, 'output/new_image.nii.gz')

3.3 访问元数据

# 获取仿射矩阵
affine = img.affine

# 获取 Header 信息
header = img.header

# 打印所有元数据
print(header)

🛠️ 4. 数据处理

4.1 提取单个体素时间序列(4D 数据)

# 假设 data 是 4D 数组 (x, y, z, t)
x, y, z, t = 60, 60, 30, 100  # 指定体素坐标
time_series = data[x, y, z, :]
print(time_series.shape)  # 输出 (t,)

4.2 切片可视化(使用 matplotlib)

import matplotlib.pyplot as plt

# 取一个中间切片(如 Z=30)
slice_data = data[:, :, 30]

plt.imshow(slice_data, cmap='gray')
plt.title("Axial Slice (Z=30)")
plt.axis('off')
plt.show()

4.3 数据归一化

import numpy as np

# 对每个体素进行 Z-score 归一化
mean = np.mean(data, axis=-1, keepdims=True)
std = np.std(data, axis=-1, keepdims=True)
normalized_data = (data - mean) / (std + 1e-6)  # 防止除零

📈 5. 进阶功能

5.1 格式转换(NIfTI → Numpy)

# 保存为 .npy 文件
np.save('data.npy', data)

# 从 .npy 加载
loaded_data = np.load('data.npy')

5.2 仿射变换(坐标映射)

# 将体素坐标 (i, j, k) 转换为世界坐标
voxel_coords = [60, 60, 30, 1]  # 注意末尾的 1
world_coords = img.affine @ voxel_coords  # 矩阵乘法
print(world_coords[:3])  # 输出世界坐标 (x, y, z)

5.3 合并多个 NIfTI 文件

from nilearn.image import concat_imgs

# 合并多个 3D 图像为 4D 图像
img1 = nib.load('img1.nii.gz')
img2 = nib.load('img2.nii.gz')
combined_img = concat_imgs([img1, img2])
nib.save(combined_img, 'combined.nii.gz')

📌 6. 常见问题

Q1: 为什么 img.get_data() 报错?

  • 原因:NiBabel 3.0+ 已弃用 .get_data(),改用 .get_fdata()。
  • 解决方案:升级代码使用 img.get_fdata()。

Q2: 如何修复仿射矩阵不一致?

  • 问题:多个图像的 affine 矩阵不匹配导致配准失败。
  • 解决:使用 nilearn.image.resample_img 统一分辨率:
  from nilearn.image import resample_img

  # 将 img2 重采样到 img1 的空间
  resampled_img = resample_img(img2, target_affine=img1.affine, target_shape=img1.shape)
  

📚 7. 学习资源