Python将nii图像进行padding扩充以及crop裁剪,以及最终将图片保存为pickle(pkl)或者png格式

padding扩充

import nibabel as nib
import numpy as np
from scipy import ndimage


def pad_nii(img_path, padded_shape):
    img = nib.load(img_path)
    data = img.get_fdata()

    current_shape = np.array(data.shape)

    pad_widths = [(max(0, padded_shape[i] - current_shape[i]) // 2, (padded_shape[i] - current_shape[i] + 1) // 2) for i in range(3)]
    pad_widths = tuple(pad_widths)

    padded_data = np.pad(data, pad_width=pad_widths, mode='constant')

    zoom_factors = tuple(padded_shape[i] / current_shape[i] for i in range(3))

    # 使用高质量的三次插值进行插值
    padded_data = ndimage.zoom(padded_data, zoom_factors, order=3)

    padded_image = nib.Nifti1Image(padded_data, img.affine)
    return padded_image

看完是不是有一些疑问:
1.我还是不太清楚pad_widths 这里做了什么,能详细解释吗,还有后面对它进行了tuple
2. padded_image = nib.Nifti1Image(padded_data, img.affine) 这里是干什么
回答1: pad_widths 是一个整数或由长度为轴数的元组(tuple)组成的序列,用于指定每个轴上填充的宽度。其中,正数表示在轴的两端填充相应的宽度,负数表示削减相应的宽度。

在这里,我们使用 numpy.pad() 函数将 3D 数据沿着三个轴进行填充,以将其填充到目标大小 (640, 640, 24)。因此,我们需要指定每个轴上填充的宽度,以及填充的方式。

具体来说,我们使用 pad_widths = ((left_pad, right_pad), (top_pad, bottom_pad), (front_pad, back_pad)) 指定每个轴上的填充宽度。
其中,left_pad 和 right_pad 分别表示在 x 轴左侧和右侧填充的宽度,top_pad 和 bottom_pad 分别表示在 y 轴上方和下方填充的宽度,front_pad 和 back_pad 分别表示在 z 轴前面和后面填充的宽度。
回答2: nib.Nifti1Image 是 nibabel 库中的一个函数,用于创建一个 Nifti 文件格式的图像对象,其中 padded_data 是填充后的 3D 数据,img.affine 是原始图像的仿射变换矩阵。

仿射变换矩阵是一个 4 x 4 的矩阵,它将 3D 数据中的坐标映射到物理空间中的坐标。Nifti 格式的图像数据不仅包含 3D 数据本身,还包括其仿射变换矩阵,用于描述数据在物理空间中的位置、方向和缩放等信息。

在创建 Nifti1Image 对象时,可以将仿射变换矩阵设置为原始图像的仿射变换矩阵 img.affine,以保留原始图像的空间信息。
那么简而言之: 我原始图像的信息存到img.affine当中了,我最后需要提取出原图像中的一些信息保存到填充后的图像中,但需要注意,三次高质量插值会导致生成的文件结果较大,若不可接受,删除插值部分代码即可。

crop裁剪

bing = 'xueguan'
source = 'niidata'
modal = 't1c'

def crop_nifti_file(file_path, output_path, target_size=(512, 512, 24)):

    img = nib.load(file_path)
    data = img.get_fdata()

    center = np.array(data.shape[:3]) // 2
    start = center - np.array(target_size) // 2
    end = start + np.array(target_size)

    cropped_data = data[start[0]:end[0], start[1]:end[1], start[2]:end[2]]
    cropped_img = nib.Nifti1Image(cropped_data, img.affine)


    # 构造输出文件名
    output_path = os.path.join(output_path, bing,source,file_path.split('\\')[-2])

    if not os.path.exists(output_path):  # 如果不存在路径,则创建这个路径,关键函数就在这两行,其他可以改变
        os.makedirs(output_path)

    output_path = os.path.join(output_path, file_path.split('\\')[-1])

    # Save the cropped image to the output path
    nib.save(cropped_img, output_path)

标题保存 标题为2D图像的pickle格式

import numpy as np
import os  # 用于遍历文件夹
import nibabel as nib  # 用nibabel包打开nii文件
import pickle
import glob

# t1c模态比t2模态更容易看到肿瘤
modalities = 't1c'
class_name = 'naomo'

#加载nii.gz文件
def nib_load(file_name):
    if not os.path.exists(file_name):
        print('Invalid file name, can not find the file!')

    # 加载该图像
    proxy = nib.load(file_name)
    # 获取图像
    data = proxy.get_fdata()
    proxy.uncache()
    # 返回图像
    return data

# 改变视角
def change_view(img):
    (x, y, z) = img.shape  # 获取图像的3个方向的维度

    for i in range(z):  # z方向
        silce = np.fliplr(np.rot90(img[:, :, :], -1))
    return silce



def nii_to_image(img_path,labelpath,twoD_imgfile):
    filenames = os.listdir(imgpath)  # 指定nii所在的文件夹

    for patient in filenames:

        patient_path = os.listdir(os.path.join(imgpath,patient))
        for f in patient_path:

            if f.split("_")[1].startswith("t1c"):

                x =  f.split("_")[0]

                label_path = os.path.join(labelpath,x,'*')
                # 获取文件夹中的文件列表
                label_file = glob.glob(label_path)
                # 如果列表只包含一个文件,则读取该文件
                if len(label_file) == 1:

                    label = np.array(nib_load(label_file[0]), dtype='uint8', order='C')

                    for depth in range(label.shape[-1]):
                        if np.any(label[..., depth]):
                            img = nib_load(os.path.join(img_path,patient,patient+'_'+modalities+'.nii.gz'))


                            # 对图像的z方向进行旋转翻转,得到与原图像相同的视角
                            img = change_view(img)
                            img = np.array(img, dtype='float32', order='c')[..., depth]
                            output = os.path.join(twoD_imgfile,class_name,modalities)
                            if not os.path.exists(output):  # 如果不存在路径,则创建这个路径,关键函数就在这两行,其他可以改变
                                os.makedirs(output)
                            output = os.path.join(output,f'{
      
      x}_{
      
      modalities}_{
      
      depth}.pkl')
                            print(output)
                            with open(output, 'wb') as f:
                                assert img.shape == (512, 512), "img.shape: {}, not match (512, 512)!"
                                pickle.dump(img, f)

若保存为2Dpng图像,即把后面保存部分代码修改

# 将输出路径设置为输出目录下的类别名和模态名
                            output = os.path.join(twoD_imgfile,class_name,modalities)
                            if not os.path.exists(output):  # 如果不存在路径,则创建这个路径,关键函数就在这两行,其他可以改变
                                os.makedirs(output)
                            output = os.path.join(output,f'{
      
      x}_{
      
      modalities}_{
      
      depth}.png')
                            print(output)
                            # 将图像保存为PNG格式
                            imageio.imwrite(output, img)

猜你喜欢

转载自blog.csdn.net/qq_45807235/article/details/129040104