MIC-DKFZ / nnUNet

Apache License 2.0
5.79k stars 1.74k forks source link

How nonzero_label is used in crop_to_nonzero? #2054

Closed icekang closed 4 months ago

icekang commented 7 months ago

I would like to used the data processed and splitted by the nnUNet for other networks I have, so I have been digging into the DataLoader code of nnUNet project. I stumbled upon the function crop_to_nonzero. I am wondering how, when, and why is the value -1 used? Would it be ignored during the training process, or will it be used using the oversampling of the foreground?

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)

    slicer = bounding_box_to_slice(bbox)
    data = data[tuple([slice(None), *slicer])]

    if seg is not None:
        seg = seg[tuple([slice(None), *slicer])]

    nonzero_mask = nonzero_mask[slicer][None]
    if seg is not None:
        seg[(seg == 0) & (~nonzero_mask)] = nonzero_label
    else:
        nonzero_mask = nonzero_mask.astype(np.int8)
        nonzero_mask[nonzero_mask == 0] = nonzero_label
        nonzero_mask[nonzero_mask > 0] = 0
        seg = nonzero_mask
    return data, seg, bbox

If you could point out to where it is later used, I would be so much grateful!

Thank you in advance, and thank you so much for this project :)

GregorKoehler commented 6 months ago

Hi @icekang ,

I'm not entirely sure if I remember this correctly, but I think this was connected to segmentations from previous stages: https://github.com/MIC-DKFZ/nnUNet/blob/3808231601265aed98d70de4218fc845e185959d/nnunetv2/training/dataloading/data_loader_3d.py#L35 . Maybe @FabianIsensee can hook in here to confirm?

FabianIsensee commented 4 months ago

Images are cropped to their central nonzero region during preprocessing. If the cropping resulted in a large reduction in image size, nnU-Net will use the nonzero region (defined as seg>=0) to perform renormalization (masked z-score) of the intensity values at the end of the data augmentation. If cropping didn't do much then we don't do anything with the -1 and just replace them with 0.

So TLDR from my side would be to just set them to 0. When you are exporting the predictions, make sure to follow the way nnU-Net does it, see convert_predicted_logits_to_segmentation_with_correct_shape

icekang commented 4 months ago

Thanks!