import numpy as np
import os
import nibabel as nib
import matplotlib.pyplot as plt
from nilearn.image.image import _crop_img_to as crop_img_to
from nilearn.image.image import check_niimg
from nilearn.image import new_img_like
NII_DIR='./nii_dir' 
#显示其中的一个slice
def read_nii_file(nii_path):
    nii_image=nib.load(nii_path)
    return nii_image
#需要将data数组的前两个维度转置以便正常显示
def nii_one_slice(image):
    #W,H,C
    image_arr=image.get_data()
    print(type(image_arr))
    #print(image_arr[125,160])
    print(image_arr.shape)
    image_2d=image_arr[:,:,85].transpose((1,0))
    plt.imshow(image_2d, cmap = 'gray')
    plt.show() 
nii_image=read_nii_file(os.path.join(NII_DIR,'Brats18_2013_2_1','Brats18_2013_2_1_flair.nii.gz'))
#最大像素值和最小像素值
#0:background像素值
nii_arr=nii_image.get_data()
print(np.max(nii_arr),np.min(nii_arr))
nii_one_slice(nii_image) 
输出:
 
1252 0
<class 'numpy.ndarray'>
(240, 240, 155)
 
 
根据设定的background像素值,综合所有模态和truth,得到前景区域
 
def get_foreground_from_set_of_files(set_of_files, background_value=0, tolerance=0.00001, return_image=False):
    #set_of_files:('sub1-T1.nii.gz', 'sub1-T2.nii.gz', 'sub1-flair.nii.gz','sub1-t1ce.nii.gz','sub1-truth.nii.gz')
    #image_file:sub1-T1.nii.gz
    for i, image_file in enumerate(set_of_files):
        #读取image无裁剪,无resize
        print(image_file)
        image = read_nii_file(image_file)
        #根据设置的background值,综合所有模态和truth将image data数组中foreground位置设为True
        is_foreground = np.logical_or(image.get_data() < (background_value - tolerance),
                                      image.get_data() > (background_value + tolerance))
        if i == 0:
            foreground = np.zeros(is_foreground.shape, dtype=np.uint8)
        #将is_foreground位置像素值设置为1
        foreground[is_foreground] = 1
    #返回image
    if return_image:
        return new_img_like(image, foreground)
    #返回数组
    else:
        return foreground 
set_of_files=(os.path.join(NII_DIR,'Brats18_2013_2_1',item) for item in ('Brats18_2013_2_1_flair.nii.gz','Brats18_2013_2_1_t1.nii.gz','Brats18_2013_2_1_t2.nii.gz','Brats18_2013_2_1_t1ce.nii.gz','Brats18_2013_2_1_seg.nii.gz'))
nii_foreground=get_foreground_from_set_of_files(set_of_files,return_image=True)
nii_one_slice(nii_foreground) 
输出:
 
./nii_dir\Brats18_2013_2_1\Brats18_2013_2_1_flair.nii.gz
./nii_dir\Brats18_2013_2_1\Brats18_2013_2_1_t1.nii.gz
./nii_dir\Brats18_2013_2_1\Brats18_2013_2_1_t2.nii.gz
./nii_dir\Brats18_2013_2_1\Brats18_2013_2_1_t1ce.nii.gz
./nii_dir\Brats18_2013_2_1\Brats18_2013_2_1_seg.nii.gz
<class 'numpy.ndarray'>
(240, 240, 155) 
 
 得到裁剪的空间位置坐标范围
 
def get_slice_index(img,rtol=1e-8):
    
    img = check_niimg(img)
    data = img.get_data()
    
    infinity_norm = max(-data.min(), data.max())
    passes_threshold = np.logical_or(data < -rtol * infinity_norm,
                                     data > rtol * infinity_norm)  ##
    if data.ndim == 4:
        #any:对数组axis=-1上做或运算
        passes_threshold = np.any(passes_threshold, axis=-1)
        
    #np.where(condition):返回condition为Ture的索引,即坐标
    coords = np.array(np.where(passes_threshold))
    print(coords)
    #每个维度起始位置,终止位置
    start = coords.min(axis=1)
    end = coords.max(axis=1) + 1
    print(start,end)
    # start和end不超过image
    start = np.maximum(start - 1, 0)
    end = np.minimum(end + 1, data.shape[:3])
    
    #每个维度裁剪的slice切片对象:class slice(start, stop[, step])裁剪范围
    slices = [slice(s, e) for s, e in zip(start, end)]
    return slices 
#W,H,C
crop = get_slice_index(nii_foreground)
print(crop) 
输出:
 
[[ 49  49  49 ... 190 190 190]
 [131 131 131 ... 153 153 153]
 [ 47  48  49 ...  42  43  44]]
[49 41 14] [191 220 143]
[slice(48, 192, None), slice(40, 221, None), slice(13, 144, None)] 
 根据crop([slice(48, 192, None), slice(41, 221, None), slice(13, 143, None)])裁剪
 
图像
 
#根据每个维度裁剪的slice切片对象裁剪
nii_image_croped=crop_img_to(nii_image,crop,copy=True)
#放射矩阵4*4
print(nii_image_croped.affine)
nii_one_slice(nii_image_croped) 
 输出:
 
[[ -1.   0.   0. -48.]
 [  0.  -1.   0. 199.]
 [  0.   0.   1.  13.]
 [  0.   0.   0.   1.]]
<class 'numpy.ndarray'>
(144, 181, 131)