关于.nii文件的一些处理函数

文章介绍了如何使用Python库SimpleITK进行nii和dicom文件之间的转换,包括将dicom文件堆叠成nii文件,将nii文件转换为jpg和png格式。同时,文章讨论了nii文件的空间和尺寸概念,以及重采样技术在CT图像处理中的应用,确保体素大小一致。最后,提供了数据集处理和重命名的辅助函数。
摘要由CSDN通过智能技术生成

图像处理tool

寒假的时候主要用到的工具是SimpleITK这个python库,可以直接在pytorch中找到下载

nii文件

相信大家已经了解了nii文件,我个人的理解,nii文件就是dicom文件的多层堆叠,最后可以通过不同的工具可以得到3D的模型。但是我们一般在处理图像的用到的网络大多数都是二维输入,特别是jpg和png格式的图片最多。

dicom->nii

import SimpleITK as sitk
def dcm2nii(path_read, path_save): 
                    # GetGDCMSeriesIDs读取序列号相同的dcm文件
        series_id = sitk.ImageSeriesReader.GetGDCMSeriesIDs(path_read)
                    # GetGDCMSeriesFileNames读取序列号相同dcm文件的路径
        series_file_names=sitk.ImageSeriesReader.GetGDCMSeriesFileNames(path_read, series_id[0])
                    # print(len(series_file_names))  
        series_reader = sitk.ImageSeriesReader()
        series_reader.SetFileNames(series_file_names)
        image3d = series_reader.Execute()
        sitk.WriteImage(image3d, path_save)

有些同学可能需要最后结果是nii的,可以采用上述代码,具体实现就是把所有读到的dicom文件叠起来成为一个nii文件

nii->jpg

import SimpleITK as sitk
def single_make_datalist(image_path, label_path, file_list, image_name):
    save_path = r"xxx"
​
    image = sitk.ReadImage(image_path)
    label = sitk.ReadImage(label_path)
    slice_num = image.GetDepth()
    image_array = sitk.GetArrayFromImage(image)
    label_array = sitk.GetArrayFromImage(label)
    print(len(image_array))
    image_name = image_name.replace(" ", "_")
    if not slice_num == label.GetDepth():
        raise "image's slice num is not equal to label's slice num"
    for index in range(0,slice_num,1):
        image_dicom = image_array[index]
        label_dicom = label_array[index]
        image_save_path = 'E:\\FengRu2023\\valDataList\\image\\' + image_name + '_{:0>3d}'.format(index) + '.jpg'
        label_save_path = 'E:\\FengRu2023\\valDataList\\label\\' + image_name + '_{:0>3d}'.format(index) + '.png'
        # print(image_save_path)
        # print(label_save_path)
        # plt.imsave(image_save_path, image_dicom, cmap='gray')
        # plt.imsave(label_save_path, label_dicom, cmap='gray')
        line = image_save_path + " " + label_save_path
        file_list.append("xxxxx" + image_name+ '_{:0>3d}'.format(index) + '.png')
    return

这个是比较用的多的代码,因为nii大家好像都用不了,所以可能需要转成jpg,我这里写的并不好,没有做到面向对象的标准,比如image_save_path之类的路径其实更应该写在方法的参数里,大家记得改一下哈。我这里注释了几个plt的方法,其实是为了看看做的灰度图的效果图。最后的输出结果是为了得到一个所有图片路径的list,因为可能在把数据集喂进去的时候需要一个这样的list

值得注意的是image用jpg格式,mask用png格式(虽然不知道为什么)

nii的space

图像各维度上像素之间的距离,但是,是物理层面的,有单位,一般为mm。

咱们可以设想一个魔方,这个魔方是有好多好多小块。一个小块他是有长宽高三个尺度的。那么space就是他们在现实中的尺度大小。

那么我们可以想象一个器官,他被切成了n层,每一层都是一样厚度的。space_depth就是他的物理厚度,那么n*space_depth就是它的真实的厚度了。

需要注意的是nii文件默认保存数据的顺序是[x, y, z]

nii的size

如果你懂了上面我说的space,那么你很容易就懂了我这里的size就是我的切片的数量了,很明显,这是一个三维的参量

用的方法是 image.GetSize()

nii重采样

CT图像的重采样是为了使体数据中大小不同的体素变得大小相同

def single_resample(itk_image, out_spacing=None, is_label=False):
    if out_spacing is None:
        out_spacing = [1.0, 1.0, 1.0]
    original_spacing = itk_image.GetSpacing()
    original_size = itk_image.GetSize()
​
    out_size = [
        int(np.round(original_size[0] * (original_spacing[0] / out_spacing[0]))),
        int(np.round(original_size[1] * (original_spacing[1] / out_spacing[1]))),
        int(np.round(original_size[2] * (original_spacing[2] / out_spacing[2])))
    ]
​
    resample = sitk.ResampleImageFilter()
    resample.SetOutputSpacing(out_spacing)
    resample.SetSize(out_size)
    resample.SetOutputDirection(itk_image.GetDirection())
    resample.SetOutputOrigin(itk_image.GetOrigin())
    resample.SetTransform(sitk.Transform())
    resample.SetDefaultPixelValue(itk_image.GetPixelIDValue())
​
    if is_label:
        resample.SetInterpolator(sitk.sitkNearestNeighbor)
    else:
        resample.SetInterpolator(sitk.sitkBSpline)
​
    return resample.Execute(itk_image)

重采样的意思就是将nii图片分割不同的“刀数”其实就是切的薄厚的问题,有这个函数的原因是我看有些网络好像需要输入的每一组的切片的数量是一定的。当然,你可以选择直接扔掉一部分的图片。

上述我们提到的重采样的方法是需要直接设置的,但是这里介绍的是将一个文件夹下的所有nii图片都重采样归一化到一个space。

nii重采样的归一化

def twinning_getSpace(image_path, label_path):
    image = sitk.ReadImage(image_path)
    label = sitk.ReadImage(label_path)
    image_space = image.GetSpacing()
    label_space = label.GetSpacing()
    # print(image_space)
    # print(label_space)
    # print("*************************")
    return image_space, label_space
​
def twinning_resample(data_root):
    save_folder = "E:\\FengRu2023\\nii_depth\\"
    file_list = os.listdir(data_root)
    for i in range(0, len(file_list) - 1, 2):
        print(i)
        tmp_image_path = data_root + "\\" + file_list[i + 1]
        tmp_label_path = data_root + "\\" + file_list[i]
        tmp_image = sitk.ReadImage(tmp_image_path)
        tmp_label = sitk.ReadImage(tmp_label_path)
        tmp_image_space, tmp_label_space = twinning_getSpace(tmp_image_path, tmp_label_path)
        print("tmp_info follow")
        print(tmp_label_space[2])
        print(tmp_label.GetDepth())
        print(tmp_image.GetDepth())
        print("**************")
        if not tmp_image.GetDepth() == tmp_label.GetDepth():
            target_depth = (tmp_label_space[2] * tmp_label.GetDepth()) / tmp_image.GetDepth()
            target_space = [tmp_image_space[0], tmp_image_space[1], target_depth]
            result_label = single_resample(tmp_label, target_space, True)
            image_array = sitk.GetArrayFromImage(tmp_image)
            label_array = sitk.GetArrayFromImage(result_label)
            sitk.WriteImage(tmp_image, save_folder + file_list[i + 1])
            sitk.WriteImage(result_label, save_folder + file_list[i])
        else:
            image_array = sitk.GetArrayFromImage(tmp_image)
            label_array = sitk.GetArrayFromImage(tmp_label)
            sitk.WriteImage(tmp_image, save_folder + file_list[i + 1])
            sitk.WriteImage(tmp_label, save_folder + file_list[i])
    return

这里写的主要是辨别label和image它们的重采样归一化,但是我发现似乎数据集大部分都是正确的,除非像一些网上的数据集是没有归一化的。

获得最终的数据集list

def single_make_datalist(image_path, label_path, file_list, image_name):
    save_path = r"xxx"
​
    image = sitk.ReadImage(image_path)
    label = sitk.ReadImage(label_path)
    slice_num = image.GetDepth()
    image_array = sitk.GetArrayFromImage(image)
    label_array = sitk.GetArrayFromImage(label)
    print(len(image_array))
    image_name = image_name.replace(" ", "_")
    if not slice_num == label.GetDepth():
        raise "image's slice num is not equal to label's slice num"
    for index in range(0,slice_num,1):
        image_dicom = image_array[index]
        label_dicom = label_array[index]
        image_save_path = 'E:\\FengRu2023\\valDataList\\image\\' + image_name + '_{:0>3d}'.format(index) + '.jpg'
        label_save_path = 'E:\\FengRu2023\\valDataList\\label\\' + image_name + '_{:0>3d}'.format(index) + '.png'
        # print(image_save_path)
        # print(label_save_path)
        # plt.imsave(image_save_path, image_dicom, cmap='gray')
        # plt.imsave(label_save_path, label_dicom, cmap='gray')
        line = image_save_path + " " + label_save_path
        file_list.append("xxxxx" + image_name+ '_{:0>3d}'.format(index) + '.png')
    return
​
​
def p_make_datalist(data_root):
    file_list = []
    file_line = os.listdir(data_root)
    file_line.sort()
    for i in range(0,len(file_line) - 1,2):
        image_name = file_line[i + 1]
        label_name = file_line[i]
        label_path = data_root + "\\" + label_name
        image_path = data_root + "\\" + image_name
        image_name = image_name.strip('.nii')
        label_name = label_name.strip('.nii')
        # print(image_name)
        # print(label_name)
        single_make_datalist(image_path,label_path,file_list,image_name)
    for k in file_list:
        k = k.strip("\n")
        print(k)
    return

这里调用了之前的单个nii的代码。做了一个小小的批处理

重命名

def rename(data_root):
    old_list = os.listdir(data_root)
    for old_name in old_list:
        print(old_name)
        old_name = data_root + "\\" + old_name
        new_name = old_name.replace(' ','_')
        os.rename(old_name, new_name)
        print(new_name)
    return

这里用了一个os库,因为我们组的同学说我们组的代码不能出现下划线,所以进行了一个重命名的操作。其实就是一个循环。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值