在Slicer中如何批量将nii.gz文件转为dicom文件

软件版本:5.6.2
问题描述:请问各位老师,3D Slicer能否批量导入nii.gz文件并导出为dicom文件?如何实现?是否需要通过Python console编写脚本?

3D Slicer确实可以批量导入 .nii.gz 文件并将其导出为 DICOM 文件。实现这个功能需要编写一个Python脚本,并在 3D Slicer 的 Python Console(Python交互窗口)中运行该脚本。下面是具体的操作步骤和示例代码,帮助您实现批量导入和导出。

实现步骤

  1. 准备 .nii.gz 文件:将所有需要转换的 .nii.gz 文件放入同一个文件夹中,例如 C:/Users/Administrator/Desktop/test

  2. 打开3D Slicer的Python Console

    • 在3D Slicer主界面上,点击 View -> Python Interactor 打开 Python Console。在这个窗口中,您可以粘贴并运行 Python 脚本。
  3. 编写Python脚本

    • 使用以下Python脚本,它会自动读取指定文件夹中的 .nii.gz 文件,逐个加载每个文件并将其转换为 DICOM 格式。导出的 DICOM 文件将被保存在与原始 .nii.gz 文件同名的文件夹中。

Python脚本:批量导入 .nii.gz 并导出为 DICOM

import os
import slicer

# 输入和输出目录
input_dir = r"C:/Users/Administrator/Desktop/test"  # .nii 或 .nii.gz 文件所在的目录
output_dir = r"C:/Users/Administrator/Desktop/test"  # DICOM 文件的输出目录

# 获取输入目录中的所有 .nii 或 .nii.gz 文件
nii_files = [f for f in os.listdir(input_dir) if f.endswith('.nii') or f.endswith('.nii.gz')]

for nii_file in nii_files:
    # 加载 .nii 或 .nii.gz 文件
    nii_path = os.path.join(input_dir, nii_file)
    volume_node = slicer.util.loadVolume(nii_path)
    if not volume_node:
        print(f"加载 {nii_file} 失败,跳过...")
        continue
    
    # 去除文件名中的空格,并创建输出的 DICOM 文件夹
    file_name = os.path.splitext(os.path.splitext(nii_file.strip())[0])[0]  # 去掉 .nii.gz 或 .nii 扩展名并去掉空格
    dicom_output_folder = os.path.join(output_dir, file_name)
    if not os.path.exists(dicom_output_folder):
        os.makedirs(dicom_output_folder)
    
    # 设置 DICOM 导出参数
    parameters = {
        "inputVolume": volume_node.GetID(),
        "dicomDirectory": dicom_output_folder,
        "dicomFilePrefix": "IMG",
        "dicomNumberFormat": "%04d",  # 文件名编号格式
        "outputType": "Short"  # 设置导出的DICOM图像类型为Short
    }

    # 运行 Create DICOM Series 模块
    cli_node = slicer.cli.run(slicer.modules.createdicomseries, None, parameters, wait_for_completion=True)
    
    # 检查是否运行成功
    if cli_node.GetStatus() & cli_node.Completed:
        print(f"{nii_file} 已成功导出为 DICOM 格式,并保存到文件夹: {dicom_output_folder}")
    else:
        print(f"{nii_file} 导出失败")

    # 清理并卸载当前的 Volume 节点,准备下一个文件
    slicer.mrmlScene.RemoveNode(volume_node)

代码解释

  1. 输入和输出目录

    • input_dir.nii.nii.gz 文件所在的文件夹路径。
    • output_dir 是DICOM文件的输出路径。每个文件的转换结果会保存在一个单独的文件夹中,文件夹名称与文件名一致。
  2. 批量处理 .nii.nii.gz 文件

    • nii_files 列表包含了 input_dir 中所有以 .nii.nii.gz 结尾的文件。
    • 脚本遍历 nii_files 列表,并逐个处理每个文件。
  3. 加载Volume数据

    • volume_node = slicer.util.loadVolume(nii_path) 加载每个 .nii.nii.gz 文件,并将其转换为Volume节点。
    • 如果加载失败(例如文件路径不正确或文件损坏),脚本会跳过该文件。
  4. 设置DICOM导出参数

    • 参数 parameters 中指定了 Create DICOM Series 模块的参数,包括输入Volume节点、输出目录、文件前缀、编号格式等。
  5. 运行 DICOM 导出模块

    • slicer.cli.run(slicer.modules.createdicomseries, None, parameters, wait_for_completion=True) 运行 Create DICOM Series 模块,将Volume节点导出为DICOM格式。
    • 使用 wait_for_completion=True 确保在当前文件导出完成后再处理下一个文件。
  6. 检查导出状态

    • 通过 cli_node.GetStatus() 检查是否导出成功。如果导出成功,则会在控制台打印成功消息;如果失败,打印导出失败的消息。
  7. 清理内存

    • 使用 slicer.mrmlScene.RemoveNode(volume_node) 卸载当前的Volume节点,以释放内存,为下一个文件的加载做好准备。

注意事项

  • 确保路径正确:请确认 input_diroutput_dir 的路径是有效的,并具有读写权限。
  • 模块依赖:此脚本依赖于 Create DICOM Series 模块,请确保3D Slicer的版本包含此模块。
  • 文件格式支持:该脚本支持 .nii.nii.gz 格式的批量转换。

运行步骤总结

  1. 打开3D Slicer并加载 Python Console(View -> Python Interactor)。
  2. 将以上脚本复制并粘贴到Python Console中,按Enter键执行。
  3. 观察控制台输出,转换成功的DICOM文件会被保存到 test 文件夹中的对应文件夹内。

通过这种方式,您可以批量将 .nii.gz 文件转换为DICOM格式,并将它们保存到指定的文件夹中,方便后续使用。

1 个赞

如果失败请在3DSlicer设置进行如下设置

非常感谢您的回复!经过尝试后代码可以成功运行,并且出现了dicom结果文件,但是发现部分文件的图片与原来的nii文件中的影像有较大差别,出现了较多白色区域,失去了许多信息,请问这个情况是什么原因导致的呢?

在脚本中可以通过调整 parameters 参数来确保更好的图像导出质量:

# 设置 DICOM 导出参数
parameters = { 
    "inputVolume": volume_node.GetID(), 
    "dicomDirectory": dicom_output_folder, 
    "dicomFilePrefix": "IMG", 
    "dicomNumberFormat": "%04d",  # 文件名编号格式 
    "outputType": "Short",        # 设置导出的DICOM图像类型为Short
    "windowLevelPresets": True,   # 尝试设置窗口和层级
    "dynamicRangeMode": "Auto"    # 自动动态范围模式
}

在 3D Slicer 中使用 Create DICOM Series 模块导出 DICOM 时,参数设置对于输出的图像质量有很大影响。以下是代码中各个关键参数的含义和可选项:

主要参数说明

  1. inputVolume
  • 描述:指定要导出的图像 Volume 节点 ID。
  • 设置:通过 volume_node.GetID() 获取每个加载图像的节点 ID。
  1. dicomDirectory
  • 描述:输出 DICOM 文件的目录路径。
  • 设置:指定 DICOM 文件将被保存的文件夹路径。脚本会自动为每个 .nii.gz 文件创建一个对应的文件夹。
  1. dicomFilePrefix
  • 描述:导出 DICOM 文件的前缀名称。
  • 设置:例如 "IMG",导出的文件名将以此前缀开头,然后附加编号。
  1. dicomNumberFormat
  • 描述:导出文件的编号格式。
  • 设置"%04d" 表示 4 位数编号,例如 IMG0001.dcm。可以根据需要更改为其他格式。
  1. outputType
  • 描述:设置导出 DICOM 图像的像素数据类型。
  • 可选项
    • Short:16 位有符号整型(常用于医学图像),是默认设置。
    • UnsignedShort:16 位无符号整型,适用于一些无需负值的影像数据。
    • Float:32 位浮点型,能存储更大范围的数据,但会增加文件大小,通常不常用于 DICOM。
    • Double:64 位浮点型,适用于需要极高精度的图像数据,同样会显著增加文件大小。
  • 推荐设置ShortUnsignedShort 通常能够满足大多数医学图像需求。如果需要更高精度(例如 PET/MR 图像中的低对比度区域),可以尝试 Float
  1. windowLevelPresets
  • 描述:在导出 DICOM 图像时应用特定的窗口和层级(window and level)设置。
  • 设置True 表示启用窗口和层级设置,确保导出的 DICOM 文件保留正确的图像亮度和对比度。
  • 推荐设置:若输出图像亮度和对比度与原始图像差别较大,启用此参数可以改善图像的显示效果。
  1. dynamicRangeMode
  • 描述:控制导出图像的动态范围。
  • 可选项
    • Auto:自动调整动态范围,适用于大部分情况。
    • Manual:用户手动指定动态范围。如果原始图像的亮度范围超出 DICOM 支持的范围,可以手动设定上下限。
  • 推荐设置Auto,确保导出图像的亮度和对比度最佳。

进一步提升图像质量的建议

  • 选择合适的 outputType:如果导出图像出现亮度或对比度不足,可以考虑 Float 类型,这将使图像数据保留更多细节。
  • 调整窗口和层级:在导出前对每个 Volume 节点进行窗口和层级调整,以便图像能在导出后保持相对一致的显示效果。
1 个赞

感谢老师的回复!后来在3D Slicer的脚本储存库中找到了导出为dicom格式的脚本(https://slicer.readthedocs.io/en/latest/developer_guide/script_repository.html#export-a-volume-to-dicom-file-format),将其修改为循环后可以成功将nii.gz文件批量导出为dicom文件,并且影像质量较为良好,没有出现之前损失较多信息的情况。
以下是所采用的代码,前期需要将所有需要转换的 .nii.gz 文件放入同一个文件夹中,并在3D Slicer的Python Console中运行代码。

import os
import glob
import DICOMScalarVolumePlugin
import re

设置包含.nii.gz文件的输入目录和输出目录

inputFolder = “c:/tmp/nii-input”
outputFolder = “c:/tmp/dicom-output”

获取所有.nii.gz文件

niiFiles = glob.glob(os.path.join(inputFolder, ‘*.nii.gz’))# 遍历所有.nii.gz文件
for niiFile in niiFiles:
# 提取文件名中的case和五位数字
filename = os.path.basename(niiFile)
match = re.search(r’case_(\d{5})', filename)
if match:
patientID = match.group(1) # 提取五位数字作为PatientID
patientStudyID = f"case_{patientID}" # 使用case和五位数字作为患者和研究ID
else:
print(f"Filename {filename} does not match expected pattern. Skipping.")
continue

# 加载.nii.gz文件到Slicer
volumeNode = slicer.util.loadVolume(niiFile)

# 创建患者和研究,并把体积放在研究下
shNode = slicer.vtkMRMLSubjectHierarchyNode.GetSubjectHierarchyNode(slicer.mrmlScene)
patientItemID = shNode.CreateSubjectItem(shNode.GetSceneItemID(), patientStudyID)
studyItemID = shNode.CreateStudyItem(patientItemID, patientStudyID)
volumeShItemID = shNode.GetItemByDataNode(volumeNode)
shNode.SetItemParent(volumeShItemID, studyItemID)

# 创建导出器对象
exporter = DICOMScalarVolumePlugin.DICOMScalarVolumePluginClass()

# 检查哪些项目可以被导出
exportables = exporter.examineForExport(volumeShItemID)

# 设置DICOM标签和输出目录
for exp in exportables:
    # 创建输出文件夹,如果不存在
    expDirectory = os.path.join(outputFolder, patientStudyID)
    if not os.path.exists(expDirectory):
        os.makedirs(expDirectory)
    exp.directory = expDirectory
    exp.setTag('PatientID', patientID)  # 设置PatientID为五位数字
    exp.setTag('StudyID', patientStudyID)

# 导出DICOM文件
exporter.export(exportables)

# 清除当前加载的体积节点,以便加载下一个.nii.gz文件
slicer.mrmlScene.Clear(0)
1 个赞