每个case都对应若干Day的若干个scan得到的slices,在train.csv中,每个case-Day-slice占3行,分别对应3个类别(大肠、小肠、胃)的标注信息

因此,在制作每一个case-Day-slice的mask时(制作1D数据),这三行分别作为mask的一个通道,因此mask是3个通道的:

1
2
3
4
5
6
7
8
9
10
11
def id2mask(id_):
idf = df[df['id']==id_]
wh = idf[['height','width']].iloc[0]
shape = (wh.height, wh.width, 3)
mask = np.zeros(shape, dtype=np.uint8)
for i, class_ in enumerate(['large_bowel', 'small_bowel', 'stomach']):
cdf = idf[idf['class']==class_]
rle = cdf.segmentation.squeeze()
if len(cdf) and not pd.isna(rle):
mask[..., i] = rle_decode(rle, shape[:2])
return mask

本题是多标签分割(不同类别有重合,即同一个像素可能有多个类别对应),所以最后的激活函数用Sigmoid,分别对每个通道(共3个通道)进行映射。

对应地,在最终提交的预测文件中,每一个case-Day-slice占三行,分别是三个类别的mask预测结果(转回RLE格式)

1D数据

训练时,将每张slice图复制3份,形成RGB3通道的图,拿去训练:

1
2
3
4
5
6
7
8
def load_img(path):
img = cv2.imread(path, cv2.IMREAD_UNCHANGED)
img = np.tile(img[...,None], [1, 1, 3]) # gray to rgb
img = img.astype('float32') # original is uint16
mx = np.max(img)
if mx:
img/=mx # scale image to [0, 1]
return img

预测时做和训练时同样的操作

2.5D数据

训练时,将每一张待预测的slice图,与其周围的slice图做成2.5D图(3个通道),拿去做训练,此时的mask仍然是之前制作好的mask

预测时,将每一张待预测的slice图,与其周围的slice图做成2.5D图(3个通道),拿去预测mask(3通道)

y_pred: torch.Size([64, 3, 320, 384])

gt masks: torch.Size([64, 3, 320, 384])

-[制作 1D data] https://www.kaggle.com/code/awsaf49/uwmgi-mask-data