合并两个nii.gz
def merge_nii_gz(file1_path, file2_path, output_path):
"""
将两个 .nii.gz 文件合并为一个,保持与原文件相同的尺寸,进行标签的并集操作,并保存为新的 .nii.gz 文件。
:param file1_path: 第一个 .nii.gz 文件路径
:param file2_path: 第二个 .nii.gz 文件路径
:param output_path: 输出合并后的 .nii.gz 文件路径
"""
# 加载第一个 .nii.gz 文件
nii1 = nib.load(file1_path)
data1 = nii1.get_fdata()
# 加载第二个 .nii.gz 文件
nii2 = nib.load(file2_path)
data2 = nii2.get_fdata()
# 检查两个文件的维度是否匹配
if data1.shape != data2.shape:
raise ValueError("两个 .nii.gz 文件的维度不一致,无法合并。")
# 进行标签的并集操作 (按位逻辑或)
merged_data = np.logical_or(data1, data2).astype(np.float32)
# 使用第一个 NIfTI 文件的仿射矩阵和头信息
merged_nii = nib.Nifti1Image(merged_data, nii1.affine, nii1.header)
# 保存合并后的 NIfTI 图像为 .nii.gz 文件
nib.save(merged_nii, output_path)
print(f"标签并集后的 .nii.gz 文件已保存为 {output_path}")
Dicom转nii.gz
def dicom_to_nii_gz(dicom_dir, output_path):
"""
使用 SimpleITK 将 DICOM 文件夹中的所有 DICOM 文件转换为 nii.gz 格式并保存,
并保留原始 DICOM 的 spacing, direction 等信息。
:param dicom_dir: 包含 DICOM 文件的文件夹路径
:param output_path: 输出的 nii.gz 文件路径
"""
# 读取 DICOM 文件夹中的 DICOM 图像
reader = sitk.ImageSeriesReader()
dicom_series = reader.GetGDCMSeriesFileNames(dicom_dir)
reader.SetFileNames(dicom_series)
# 读取 DICOM 切片并组合成 3D 图像
image = reader.Execute()
# 获取原始的 spacing 和 direction
spacing = image.GetSpacing()
direction = image.GetDirection()
origin = image.GetOrigin()
print(f"Spacing: {spacing}")
print(f"Direction: {direction}")
print(f"Origin: {origin}")
# 保存为 NIfTI 格式,SimpleITK 会保留这些信息
sitk.WriteImage(image, output_path)
print(f"DICOM 文件已成功转换并保存为 {output_path}")
按比例缩小bbox
def shrink_bbox_in_mask(mask_path, output_path, shrink_percentage):
"""
函数功能:缩小给定nii.gz掩码文件中的边界框(bbox)
参数:
mask_path (str): 输入nii.gz掩码文件的路径
output_path (str): 保存修改后掩码文件的路径
shrink_percentage (float): 缩小边界框的百分比,例如 0.1 表示缩小10%
返回:
无(将处理结果保存为新的nii.gz文件)
"""
# 第1步: 加载nii.gz掩码文件
img = nib.load(mask_path)
mask_data = img.get_fdata()
# 第2步: 获取掩码中非零区域的bounding box
mask_nonzero = np.argwhere(mask_data > 0)
min_coord = mask_nonzero.min(axis=0) # 获取非零体素的最小坐标
max_coord = mask_nonzero.max(axis=0) # 获取非零体素的最大坐标
# 第3步: 计算bbox的中心和尺寸
center = (min_coord + max_coord) / 2 # bbox中心坐标
bbox_size = max_coord - min_coord # bbox的尺寸
# 第4步: 根据给定的百分比缩小bbox
shrink_factor = (1 - shrink_percentage) # 缩小因子
new_bbox_size = bbox_size * shrink_factor # 缩小后的bbox尺寸
new_min_coord = np.round(center - new_bbox_size / 2).astype(int) # 新的最小坐标
new_max_coord = np.round(center + new_bbox_size / 2).astype(int) # 新的最大坐标
# 确保新的bbox在原始mask的维度范围内
new_min_coord = np.maximum(new_min_coord, 0)
new_max_coord = np.minimum(new_max_coord, mask_data.shape)
# 第5步: 创建包含缩小后的bbox的新掩码
new_mask_data = np.zeros_like(mask_data) # 初始化新的掩码
new_mask_data[new_min_coord[0]:new_max_coord[0],
new_min_coord[1]:new_max_coord[1],
new_min_coord[2]:new_max_coord[2]] = mask_data[
new_min_coord[0]:new_max_coord[0],
new_min_coord[1]:new_max_coord[1],
new_min_coord[2]:new_max_coord[2]] # 填充缩小后的bbox区域
# 第6步: 将新的掩码保存为nii.gz文件
new_img = nib.Nifti1Image(new_mask_data, img.affine)
nib.save(new_img, output_path)
print(f'缩小后的掩码已保存到 {output_path}')
3维前缀和
def prefix_sum_3d(arr):
# 创建一个和原数组大小相同的数组来存储前缀和
prefix_sum = np.zeros_like(arr)
# 使用三重循环计算每个位置的前缀和
for i in range(arr.shape[0]):
for j in range(arr.shape[1]):
for k in range(arr.shape[2]):
# 计算前缀和
prefix_sum[i, j, k] = arr[i, j, k]
if i > 0:
prefix_sum[i, j, k] += prefix_sum[i - 1, j, k]
if j > 0:
prefix_sum[i, j, k] += prefix_sum[i, j - 1, k]
if k > 0:
prefix_sum[i, j, k] += prefix_sum[i, j, k - 1]
if i > 0 and j > 0:
prefix_sum[i, j, k] -= prefix_sum[i - 1, j - 1, k]
if i > 0 and k > 0:
prefix_sum[i, j, k] -= prefix_sum[i - 1, j, k - 1]
if j > 0 and k > 0:
prefix_sum[i, j, k] -= prefix_sum[i, j - 1, k - 1]
if i > 0 and j > 0 and k > 0:
prefix_sum[i, j, k] += prefix_sum[i - 1, j - 1, k - 1]
return prefix_sum