1.摘要
创建将 nifti
文件转换为 dicom
系列的函数的概念很简单;所需要的只是从 nifti
文件中返回帧数据,将其划分为切片,然后将每个切片转换为一个 dicom
。
这种转换的灵感来自将 JPG 或 PNG 图像转换为 dicoms的函数。
2.步骤
- 使用预先存在的
dicom
文件。 - 安装需要的包。
- 从
nifti
文件中提取帧数据。 - 准备要转换的数组。
- 将一个
nifti
文件转换为dicom
系列。 - 将多个
nifti
文件转换为多个dicom
系列。
2.1使用预先存在的 dicom 文件
如果我们尝试转换为 dicom
,您可能想知道为什么我们需要 dicom
文件。答案可以在我们从 将 JPG 或 PNG 图像转换为 dicoms的博客上找到。因为当我们想要创建一个dicom
文件时,我们不能仅仅将像素数据放入其中,dicom
文件还包含除了像素值以外的其他更多的信息。如果没有另一个dicom
文件的帮助,我们无法提供这些信息。因此,我们必须使用现有的dicom
文件并修改其信息以匹配我们所拥有(需要)的内容。
2.2我们需要的包
与任何其他程序一样,我们需要一些包来完成此转换,因此在此项目中,您需要单独安装以下包。
- nibabel:
pip install nibabel
- pydicom:
pip install pydicom
- numpy:
pip install numpy
- tqdm:
pip install tqdm
(这个只是打印转换的进度)
2.3从 nifti 文件中提取帧数据
首先,我们必须从 nifti
文件中提取帧数据(像素数组)以便对其进行转换。这个数组是一个矩阵,每一行都有一个切片。最终,我们将每个切片(行)转换为 dicom
。
为此,您可以使用 nibabel
库加载 nifti
文件,然后调用get_fdata
函数,该函数将提取像素数组(它将是一个 numpy
数组)。
import nibabel
nifti_file = nibabel.load(nifti_dir)
nifti_array = nifti_file.get_fdata()
2.4准备要转换的数组
提取帧数据后,我们必须对其进行准备,以便将其转换为 dicom
。我们必须首先将像素值转换为 16 位的无符号整数,然后再获取一个预先存在的 dicom
文件并填写一些参数来匹配我们的参数(宽度、高度……)。
def convertNsave(arr,file_dir, index=0):
"""
`arr`: parameter will take a numpy array that represents only one slice.
`file_dir`: parameter will take the path to save the slices
`index`: parameter will represent the index of the slice, so this parameter will be used to put
the name of each slice while using a for loop to convert all the slices
"""
dicom_file = pydicom.dcmread('images/dcmimage.dcm')
arr = arr.astype('uint16')
dicom_file.Rows = arr.shape[0]
dicom_file.Columns = arr.shape[1]
dicom_file.PhotometricInterpretation = "MONOCHROME2"
dicom_file.SamplesPerPixel = 1
dicom_file.BitsStored = 16
dicom_file.BitsAllocated = 16
dicom_file.HighBit = 15
dicom_file.PixelRepresentation = 1
dicom_file.PixelData = arr.tobytes()
就是这样,设置这些参数后,我们可以使用 pydicom
库中的 save
函数保存数组。
dicom_file.save_as(os.path.join(file_dir, f'slice{index}.dcm'))
注意:此函数只会转换一个切片,因此要转换单个 nifti
文件,我们必须通过所有切片传递此函数(在下一步中)。
2.5将一个 nifti 文件转换为 dicom 系列
正如我在上一段中提到的,函数convertNsave
将只转换一个切片。
为此,我创建了函数nifti2dicom_1file
,以便可以使用它直接转换一个 nifti
文件,在下一步中,我将向您展示如何对多个 nifti
文件进行转换。
这是nifti2dicom_1file
转换一个文件的函数:
def nifti2dicom_1file(nifti_dir, out_dir):
"""
This function is to convert only one nifti file into dicom series
`nifti_dir`: the path to the one nifti file
`out_dir`: the path to output
"""
nifti_file = nibabel.load(nifti_dir)
nifti_array = nifti_file.get_fdata()
number_slices = nifti_array.shape[2]
for slice_ in tqdm(range(number_slices)):
convertNsave(nifti_array[:,:,slice_], out_dir, slice_)
如您所见,函数convertNsave
是该函数的核心。我只是在这个函数中添加了一个循环来传递所有的切片(我知道这很容易,但我想让它准备好以便你可以直接使用它)
2.6将多个 nifti 文件转换为多个 dicom 系列
现在要转换多个 nifti
文件,我们将只使用该函数nifti2dicom_1file
,但我们使用循环多次调用它。这是执行此操作的脚本:
def nifti2dicom_mfiles(nifti_dir, out_dir=''):
"""
This function is to convert multiple nifti files into dicom files
`nifti_dir`: You enter the global path to all of the nifti files here.
`out_dir`: Put the path to where you want to save all the dicoms here.
PS: Each nifti file's folders will be created automatically, so you do not need to create an empty folder for each patient.
"""
files = os.listdir(nifti_dir)
for fileName in files:
in_path = os.path.join(nifti_dir, fileName)
out_path = os.path.join(out_dir, fileName)
os.mkdir(out_path)
nifti2dicom_1file(in_path, out_path)
2.7完整代码
# coding=utf-8
# /usr/bin/env python
'''
Author:David Xu
Blog: https://blog.csdn.net/weixin_43229348
date: 2022/1/17 13:11
'''
import nibabel
import numpy as np
import pydicom
import os
from tqdm import tqdm
def convertNsave(arr, file_dir, index=0):
"""
`arr`: parameter will take a numpy array that represents only one slice.
`file_dir`: parameter will take the path to save the slices
`index`: parameter will represent the index of the slice, so this parameter will be used to put
the name of each slice while using a for loop to convert all the slices
"""
dicom_file = pydicom.dcmread('images/dcmimage.dcm')
arr = arr.astype('uint16')
dicom_file.Rows = arr.shape[0]
dicom_file.Columns = arr.shape[1]
dicom_file.PhotometricInterpretation = "MONOCHROME2"
dicom_file.SamplesPerPixel = 1
dicom_file.BitsStored = 16
dicom_file.BitsAllocated = 16
dicom_file.HighBit = 15
dicom_file.PixelRepresentation = 1
dicom_file.PixelData = arr.tobytes()
dicom_file.save_as(os.path.join(file_dir, f'slice{index}.dcm'))
def nifti2dicom_1file(nifti_dir, out_dir):
"""
This function is to convert only one nifti file into dicom series
`nifti_dir`: the path to the one nifti file
`out_dir`: the path to output
"""
nifti_file = nibabel.load(nifti_dir)
nifti_array = nifti_file.get_fdata()
number_slices = nifti_array.shape[2]
for slice_ in tqdm(range(number_slices)):
convertNsave(nifti_array[:, :, slice_], out_dir, slice_)
def nifti2dicom_mfiles(nifti_dir, out_dir=''):
"""
This function is to convert multiple nifti files into dicom files
`nifti_dir`: You enter the global path to all of the nifti files here.
`out_dir`: Put the path to where you want to save all the dicoms here.
PS: Each nifti file's folders will be created automatically, so you do not need to create an empty folder for each patient.
"""
files = os.listdir(nifti_dir)
for file in files:
in_path = os.path.join(nifti_dir, file)
out_path = os.path.join(out_dir, file)
os.mkdir(out_path)
nifti2dicom_1file(in_path, out_path)
if __name__ == '__main__':
if 0:
# 将单个nifti文件转为dicom序列
input_image = "18mask.nii.gz"
output_path = "dicom_output"
os.makedirs(output_path, exist_ok=True)
nifti2dicom_1file(input_image, output_path)
if 1:
# 将多个nifti文件转为多个dicom序列
input_image_dir = "test_dir"
output_path = "dicom_output"
os.makedirs(output_path, exist_ok=True)
nifti2dicom_mfiles(input_image_dir, output_path)