软件版本:5.6.2
问题描述:请问各位老师,3D Slicer能否批量导入nii.gz文件并导出为dicom文件?如何实现?是否需要通过Python console编写脚本?
3D Slicer确实可以批量导入 .nii.gz
文件并将其导出为 DICOM 文件。实现这个功能需要编写一个Python脚本,并在 3D Slicer 的 Python Console(Python交互窗口)中运行该脚本。下面是具体的操作步骤和示例代码,帮助您实现批量导入和导出。
实现步骤
-
准备
.nii.gz
文件:将所有需要转换的.nii.gz
文件放入同一个文件夹中,例如C:/Users/Administrator/Desktop/test
。 -
打开3D Slicer的Python Console:
- 在3D Slicer主界面上,点击
View -> Python Interactor
打开 Python Console。在这个窗口中,您可以粘贴并运行 Python 脚本。
- 在3D Slicer主界面上,点击
-
编写Python脚本:
- 使用以下Python脚本,它会自动读取指定文件夹中的
.nii.gz
文件,逐个加载每个文件并将其转换为 DICOM 格式。导出的 DICOM 文件将被保存在与原始.nii.gz
文件同名的文件夹中。
- 使用以下Python脚本,它会自动读取指定文件夹中的
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)
代码解释
-
输入和输出目录:
input_dir
是.nii
或.nii.gz
文件所在的文件夹路径。output_dir
是DICOM文件的输出路径。每个文件的转换结果会保存在一个单独的文件夹中,文件夹名称与文件名一致。
-
批量处理
.nii
和.nii.gz
文件:nii_files
列表包含了input_dir
中所有以.nii
或.nii.gz
结尾的文件。- 脚本遍历
nii_files
列表,并逐个处理每个文件。
-
加载Volume数据:
volume_node = slicer.util.loadVolume(nii_path)
加载每个.nii
或.nii.gz
文件,并将其转换为Volume节点。- 如果加载失败(例如文件路径不正确或文件损坏),脚本会跳过该文件。
-
设置DICOM导出参数:
- 参数
parameters
中指定了Create DICOM Series
模块的参数,包括输入Volume节点、输出目录、文件前缀、编号格式等。
- 参数
-
运行 DICOM 导出模块:
slicer.cli.run(slicer.modules.createdicomseries, None, parameters, wait_for_completion=True)
运行Create DICOM Series
模块,将Volume节点导出为DICOM格式。- 使用
wait_for_completion=True
确保在当前文件导出完成后再处理下一个文件。
-
检查导出状态:
- 通过
cli_node.GetStatus()
检查是否导出成功。如果导出成功,则会在控制台打印成功消息;如果失败,打印导出失败的消息。
- 通过
-
清理内存:
- 使用
slicer.mrmlScene.RemoveNode(volume_node)
卸载当前的Volume节点,以释放内存,为下一个文件的加载做好准备。
- 使用
注意事项
- 确保路径正确:请确认
input_dir
和output_dir
的路径是有效的,并具有读写权限。 - 模块依赖:此脚本依赖于
Create DICOM Series
模块,请确保3D Slicer的版本包含此模块。 - 文件格式支持:该脚本支持
.nii
和.nii.gz
格式的批量转换。
运行步骤总结
- 打开3D Slicer并加载 Python Console(
View -> Python Interactor
)。 - 将以上脚本复制并粘贴到Python Console中,按Enter键执行。
- 观察控制台输出,转换成功的DICOM文件会被保存到
test
文件夹中的对应文件夹内。
通过这种方式,您可以批量将 .nii.gz
文件转换为DICOM格式,并将它们保存到指定的文件夹中,方便后续使用。
非常感谢您的回复!经过尝试后代码可以成功运行,并且出现了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 时,参数设置对于输出的图像质量有很大影响。以下是代码中各个关键参数的含义和可选项:
主要参数说明
inputVolume
- 描述:指定要导出的图像 Volume 节点 ID。
- 设置:通过
volume_node.GetID()
获取每个加载图像的节点 ID。
dicomDirectory
- 描述:输出 DICOM 文件的目录路径。
- 设置:指定 DICOM 文件将被保存的文件夹路径。脚本会自动为每个
.nii.gz
文件创建一个对应的文件夹。
dicomFilePrefix
- 描述:导出 DICOM 文件的前缀名称。
- 设置:例如
"IMG"
,导出的文件名将以此前缀开头,然后附加编号。
dicomNumberFormat
- 描述:导出文件的编号格式。
- 设置:
"%04d"
表示 4 位数编号,例如IMG0001.dcm
。可以根据需要更改为其他格式。
outputType
- 描述:设置导出 DICOM 图像的像素数据类型。
- 可选项:
Short
:16 位有符号整型(常用于医学图像),是默认设置。UnsignedShort
:16 位无符号整型,适用于一些无需负值的影像数据。Float
:32 位浮点型,能存储更大范围的数据,但会增加文件大小,通常不常用于 DICOM。Double
:64 位浮点型,适用于需要极高精度的图像数据,同样会显著增加文件大小。
- 推荐设置:
Short
或UnsignedShort
通常能够满足大多数医学图像需求。如果需要更高精度(例如 PET/MR 图像中的低对比度区域),可以尝试Float
。
windowLevelPresets
- 描述:在导出 DICOM 图像时应用特定的窗口和层级(window and level)设置。
- 设置:
True
表示启用窗口和层级设置,确保导出的 DICOM 文件保留正确的图像亮度和对比度。 - 推荐设置:若输出图像亮度和对比度与原始图像差别较大,启用此参数可以改善图像的显示效果。
dynamicRangeMode
- 描述:控制导出图像的动态范围。
- 可选项:
Auto
:自动调整动态范围,适用于大部分情况。Manual
:用户手动指定动态范围。如果原始图像的亮度范围超出 DICOM 支持的范围,可以手动设定上下限。
- 推荐设置:
Auto
,确保导出图像的亮度和对比度最佳。
进一步提升图像质量的建议
- 选择合适的
outputType
:如果导出图像出现亮度或对比度不足,可以考虑Float
类型,这将使图像数据保留更多细节。 - 调整窗口和层级:在导出前对每个 Volume 节点进行窗口和层级调整,以便图像能在导出后保持相对一致的显示效果。
感谢老师的回复!后来在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)