https://brainder.org/2012/09/23/the-nifti-file-format/
https://blog.csdn.net/DoronLee/article/details/78597868
import matplotlib.pyplot as plt
import numpy as np
import os
NII_DIR='./nii_dir' #nii文件所在root目录
import nibabel as nib
def read_nii_file1(nii_path):
'''
根据nii文件路径读取nii图像
'''
nii_image=nib.load(nii_path)
return nii_image
def nii_one_slice1(image):
'''
显示nii image中的其中1张slice
'''
image_arr=image.get_data()
print(type(image_arr))
print(image_arr.shape)
#注意:nibabel读出的image的data的数组顺序为:Width,Height,Channel
#将2d数组转置,让plt正常显示
image_2d=image_arr[:,:,85].transpose((1,0))
plt.imshow(image_2d, cmap = 'gray')
plt.show()
nii_image1=read_nii_file1(os.path.join(NII_DIR,'Brats18_2013_2_1','Brats18_2013_2_1_flair.nii.gz'))
nii_one_slice1(nii_image1)
输出:
(240, 240, 155)
import SimpleITK as sitk
def read_nii_file2(img_path):
'''
根据nii文件路径读取nii图像
'''
nii_image = sitk.ReadImage(img_path)
return nii_image
def nii_one_slice2(image):
'''
显示nii image中的其中1张slice
'''
#C,H,W
#SimpleITK读出的image的data的数组顺序为:Channel,Height,Width
image_arr=sitk.GetArrayFromImage(image)
print(type(image_arr))
print(image_arr.shape)
image_2d=image_arr[85,:,:]
plt.imshow(image_2d, cmap = 'gray')
plt.show()
nii_image2=read_nii_file2(os.path.join(NII_DIR,'Brats18_2013_2_1','Brats18_2013_2_1_flair.nii.gz'))
nii_one_slice2(nii_image2)
from nilearn.image import new_img_like,resample_to_img
nii_img=nib.load(os.path.join(NII_DIR,'Brats18_2013_2_1','Brats18_2013_2_1_flair.nii.gz'))
print(nii_img.affine.shape)
print(nii_img.affine)
输出:
(4, 4)
[[ -1. 0. 0. -0.]
[ 0. -1. 0. 239.]
[ 0. 0. 1. 0.]
[ 0. 0. 0. 1.]]
仿射矩阵是对图像实现仿射变换的矩阵,仿射变换包括平移、放缩、旋转。
3D图像的仿射矩阵大小为4*4,最后一行固定为[0,0,0,1]不起作用.
第4列控制平移变换,主对角线控制放缩变换,affine[:3,:3]控制旋转变换。
def random_scale_factor(n_dim=3, mean=1, std=0.25):
return np.random.normal(mean, std, n_dim)
def scale_image(image, scale_factor):
scale_factor = np.asarray(scale_factor)
new_affine = np.copy(image.affine)
#修改原image的affine
#乘以放缩系数
new_affine[:3, :3] = image.affine[:3, :3] * scale_factor
#修改第4列的前3个值,保证放缩后的图像居中
#1-scale_factor:缩小时,右移;放大时,左移
new_affine[:, 3][:3] = image.affine[:, 3][:3] + (image.shape * np.diag(image.affine)[:3] * (1 - scale_factor)) / 2
#返回创建新的nii image,data与原image相同,affine更新
return new_img_like(image, data=image.get_data(), affine=new_affine)
new_image1=scale_image(nii_img,(0.5,0.5,0.5))
#print(nii_img.get_data()[120,120,:])
print(nii_img.affine)
#print(new_image1.get_data()[120,120,:])
print(new_image1.affine)
nii_one_slice1(new_image1)
#调用resample_to_img实现重采样
image_scaled=resample_to_img(new_image1,nii_img,interpolation="continuous")
nii_one_slice1(image_scaled)
输出:
[[ -1. 0. 0. -0.]
[ 0. -1. 0. 239.]
[ 0. 0. 1. 0.]
[ 0. 0. 0. 1.]]
[[ -0.5 0. 0. -60. ]
[ 0. -0.5 0. 179. ]
[ 0. 0. 0.5 38.75]
[ 0. 0. 0. 1. ]]
(240, 240, 155)
(240, 240, 155)
def random_boolean():
return np.random.choice([True, False])
#随机选择翻转的axis
def random_flip_dimensions(n_dimensions):
axis = list()
for dim in range(n_dimensions):
if random_boolean():
axis.append(dim)
return axis
def flip_image(image, axis):
try:
new_data = np.copy(image.get_data())
for axis_index in axis:
#根据axis对image数组进行翻转
new_data = np.flip(new_data, axis=axis_index)
except TypeError:
new_data = np.flip(image.get_data(), axis=axis)
return new_img_like(image, data=new_data)
#翻转axis=1,即上下翻转
new_image2=flip_image(nii_img,axis=[1])
print(nii_img.get_data()[120,120,:])
print(new_image2.get_data()[120,120,:])
nii_one_slice1(new_image2)
#使用resample_to_img实现重采样和不使用效果一样
image_flipped=resample_to_img(new_image2,nii_img,interpolation="continuous")
print(image_flipped.get_data()[120,120,:])
nii_one_slice1(image_flipped)
输出:
[ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 60 119 124 130
126 137 188 248 308 312 273 262 284 328 339 365 418 424 367 271 176 111
96 105 127 159 215 286 320 322 249 134 125 216 304 322 329 371 398 401
413 409 383 374 370 415 481 490 496 506 506 513 503 491 482 483 493 392
198 129 161 162 168 187 209 221 217 214 217 216 217 214 199 168 132 110
112 121 107 79 62 53 48 47 48 54 82 87 39 1 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0]
[ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 68 120
130 148 206 281 358 353 296 293 329 363 368 398 429 412 345 252 160 94
71 78 98 135 196 262 316 303 222 146 176 273 326 333 344 380 398 404
414 415 394 379 380 434 489 497 500 501 505 509 497 487 477 479 481 383
195 139 189 184 174 193 220 229 222 218 219 230 238 228 204 169 134 115
121 126 109 91 77 66 59 55 49 65 96 85 38 4 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0]
(240, 240, 155)
[ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 68 120
130 148 206 281 358 353 296 293 329 363 368 398 429 412 345 252 160 94
71 78 98 135 196 262 316 303 222 146 176 273 326 333 344 380 398 404
414 415 394 379 380 434 489 497 500 501 505 509 497 487 477 479 481 383
195 139 189 184 174 193 220 229 222 218 219 230 238 228 204 169 134 115
121 126 109 91 77 66 59 55 49 65 96 85 38 4 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0]
(240, 240, 155)
#放缩+翻转的封装函数
def distort_image(image, flip_axis=None, scale_factor=None):
if flip_axis:
image = flip_image(image, flip_axis)
if scale_factor is not None:
image = scale_image(image, scale_factor)
return image
def get_image(data, affine, nib_class=nib.Nifti1Image):
#将数组data转换成nifiti1图像
return nib_class(dataobj=data, affine=affine)
def augment_data(data, truth, affine, scale_deviation=None, flip=True):
'''
data shape;[num_motailities,W,H,C]
truth:[W,H,C]
'''
#随机的生成放缩尺度和翻转的axis
n_dim = len(truth.shape)
if scale_deviation:
scale_factor = random_scale_factor(n_dim, std=scale_deviation)
else:
scale_factor = None
if flip:
flip_axis = random_flip_dimensions(n_dim)
else:
flip_axis = None
data_list = list()
#数据的模态索引
for data_index in range(data.shape[0]):
#hdf5文件中保存的每个模态的image得数组转换为nii image
#调用resample_to_img实现仿射变换
image = get_image(data[data_index], affine)
data_list.append(resample_to_img(distort_image(image, flip_axis=flip_axis,scale_factor=scale_factor),
image,
interpolation="continuous").get_data())
data = np.asarray(data_list)
#hdf5文件中保存的truth image得数组转换为nii image
truth_image = get_image(truth, affine)
#调用resample_to_img实现仿射变换
truth_data = resample_to_img(distort_image(truth_image, flip_axis=flip_axis, scale_factor=scale_factor),
truth_image,
interpolation="nearest").get_data()
return data, truth_data
import itertools
import random
def generate_permutation_keys():
"""
This function returns a set of "keys" that represent the 48 unique rotations &
reflections of a 3D matrix.
Each item of the set is a tuple:
((rotate_y, rotate_x), flip_x, flip_y, flip_z, transpose)
As an example, ((0, 1), 0, 1, 0, 1) represents a permutation in which the data is
rotated 90 degrees around the z-axis, then reversed on the y-axis, and then
transposed.
48 unique rotations & reflections:
https://en.wikipedia.org/wiki/Octahedral_symmetry#The_isometries_of_the_cube
"""
##((0,0)/(0,1)/(1,1),0/1,0/1,0/1,0/1)=3*16=48种组合的笛卡尔积集合
return set(itertools.product(
itertools.combinations_with_replacement(range(2), 2), range(2), range(2), range(2), range(2)))
def random_permutation_key():
"""
Generates and randomly selects a permutation key. See the documentation for the
"generate_permutation_keys" function.
"""
#随机选择1种permutation
return random.choice(list(generate_permutation_keys()))
def permute_data(data, key):
"""
Permutes the given data according to the specification of the given key. Input data
must be of shape (n_modalities, x, y, z).
Input key is a tuple: (rotate_y, rotate_x), flip_x, flip_y, flip_z, transpose)
As an example, ((0, 1), 0, 1, 0, 1) represents a permutation in which the data is
rotated 90 degrees around the x-axis, then reversed on the y-axis, and then
transposed.
"""
data = np.copy(data)
(rotate_y, rotate_x), flip_x, flip_y, flip_z, transpose = key
if rotate_y != 0:
data = np.rot90(data, rotate_y, axes=(1, 3))
if rotate_x != 0:
data = np.rot90(data, rotate_x, axes=(2, 3))
#翻转x/y/z轴
if flip_x:
data = data[:, ::-1]
if flip_y:
data = data[:, :, ::-1]
if flip_z:
data = data[:, :, :, ::-1]
#转置
if transpose:
new_data=np.zeros((1,data.shape[-1],data.shape[-2],data.shape[-3]))
for i in range(data.shape[0]):
new_data[i] = data[i].T
return new_data
def random_permutation_x_y(x_data, y_data):
"""
Performs random permutation on the data.
:param x_data: numpy array containing the data. Data must be of shape (n_modalities, x, y, z).
:param y_data: numpy array containing the data. Data must be of shape (n_modalities, x, y, z).
:return: the permuted data
"""
key = random_permutation_key()
return permute_data(x_data, key), permute_data(y_data, key)
测试:
#绕y轴(H)旋转90度
key1=((1, 0), 0, 0, 0, 0)
data_permuted1=permute_data(data_ori,key1)
nii_one_slice1(nii_img)
nii_one_slice1(new_img_like(nii_img,data=data_permuted1[0,:]))
输出:
(240, 240, 155)
(155, 240, 240)
测试:
#绕x轴(W)旋转90度
key2=((0, 1), 0, 0, 0, 0)
data_permuted2=permute_data(data_ori,key2)
nii_one_slice1(nii_img)
nii_one_slice1(new_img_like(nii_img,data=data_permuted2[0,:]))
输出:
(240, 240, 155)
(240, 155, 240)
测试:
#转置
key3=((0, 0), 0, 0, 0, 1)
data_permuted3=permute_data(data_ori,key3)
nii_one_slice1(nii_img)
nii_one_slice1(new_img_like(nii_img,data=data_permuted3[0,:]))
输出:
(240, 240, 155)
(155, 240, 240)