首先,感谢paper桑大佬关于nnUNet项目的解释,我从中获益很多。本片是关于nnUNet代码中我看到的认为可能比较重要的某些细节的记录。
1.推理阶段。在nnUNet/nnunet/preprocessing/cropping.py中 crop_to_nonzero函数
def crop_to_nonzero(data, seg=None, nonzero_label=-1):
"""
:param data:
:param seg:
:param nonzero_label: this will be written into the segmentation map
:return:
"""
nonzero_mask = create_nonzero_mask(data)
bbox = get_bbox_from_mask(nonzero_mask, 0)
cropped_data = []
for c in range(data.shape[0]):
cropped = crop_to_bbox(data[c], bbox)
cropped_data.append(cropped[None])
data = np.vstack(cropped_data)
if seg is not None:
cropped_seg = []
for c in range(seg.shape[0]):
cropped = crop_to_bbox(seg[c], bbox)
cropped_seg.append(cropped[None])
seg = np.vstack(cropped_seg)
nonzero_mask = crop_to_bbox(nonzero_mask, bbox)[None]
if seg is not None:
seg[(seg == 0) & (nonzero_mask == 0)] = nonzero_label
else:
nonzero_mask = nonzero_mask.astype(int)
nonzero_mask[nonzero_mask == 0] = nonzero_label
nonzero_mask[nonzero_mask > 0] = 0
seg = nonzero_mask
return data, seg, bbox
data中值为0的对于nonzero_mask中都设置为了-1.(当然其中create_nonzero_mask函数时用到了binary_fill_holes,填充了一部分)
2.推理阶段。在nnUNet/nnunet/preprocessing/preprocessing.py中311行
data, seg, properties = self.resample_and_normalize(data, target_spacing, properties, seg, force_separate_z=force_separate_z)
实现对数据的重采样和归一化。
3.推理阶段: 在nnUNet/nnunet/preprocessing/preprocessing.py中150行
reshaped_data.append(resize_fn(data[c, slice_id], new_shape_2d, order, cval=cval, **kwargs))
里对每一张512*512进行了重采样。 这里的resize_fn代表的是skimage.transform.resize() 函数其中的order=3.
值得一提的是。如果这是对掩码的重采样的话,resize_fn代表的是batchgenerators.augmentations.utils.resize_segmentation() 其中order=3,原因是为了防止([0, 0, 2] -> [0, 1, 2])的情况。因为掩码可能是0代表背景,1代表前景,2代表前景中的病灶。这0到1就是使一个背景变前景。
4.推理阶段:在nnUNet/nnunet/preprocessing/preprocessing.py中174行
reshaped_final_data.append(map_coordinates(reshaped_data, coord_map, order=order_z, cval=cval,mode='nearest')[None])
z轴方向,用的是scipy.ndimage.interpolation.map_coordinates() 函数来出处理添加中间的层数(做一个3dmap坐标。z轴3d矩阵,x一个,y一个。填充坐标最近的原坐标值)。实例如下
#原数据
reshaped_data[0][300][300]=-94.4081754097679
reshaped_data[1][300][300]=-38.33892068143663
reshaped_data[0][301][300]=-100.75139288087729
#map_coordinates采样后
#z轴在变,但值还是那些值(分辨率改变)
reshaped_final_data[0][0][0][300][300]=-94.4081754097679
reshaped_final_data[0][0][1][300][300]=-94.4081754097679
reshaped_final_data[0][0][2][300][300]=-94.4081754097679
reshaped_final_data[0][0][3][300][300]=-38.33892068143663
reshaped_final_data[0][0][4][300][300]=-38.33892068143663
reshaped_final_data[0][0][5][300][300]=-38.33892068143663
reshaped_final_data[0][0][6][300][300]= 46.13715590124825
#x轴不变,x分辨率不变。
reshaped_final_data[0][0][0][301][300]=-100.75139288087729
5.2d数据转nii格式阶段:在/home/pacs/nnUNet/nnunet/dataset_conversion/Task120_Massachusetts_RoadSegm.py中66行
transform=lambda x: (x == 255).astype(int)
单标签:
import numpy as np
a=[[0,60,120,180,240],[0,0,0,0,0],[0,0,0,0,0],[240,180,120,60,0]]
a=np.array(a)
transform=lambda x: (x == 240).astype(int)
b=transform(a)
print(b)
[[0 0 0 0 1]
[0 0 0 0 0]
[0 0 0 0 0]
[1 0 0 0 0]]
多标签:
import numpy as np
a=[[0,60,120,180,240],[0,0,0,0,0],[0,0,0,0,0],[240,180,120,60,0]]
a=np.array(a)
transform=lambda x: (x == 240).astype(int)*1
transform1=lambda x: (x == 180).astype(int)*2
transform2=lambda x: (x == 120).astype(int)*3
transform3=lambda x: (x == 60).astype(int)*4
b=transform(a)+transform1(a)+transform2(a)+transform3(a)
print(b)
[[0 4 3 2 1]
[0 0 0 0 0]
[0 0 0 0 0]
[1 2 3 4 0]]