LIVIAETS / boundary-loss

Official code for "Boundary loss for highly unbalanced segmentation", runner-up for best paper award at MIDL 2019. Extended version in MedIA, volume 67, January 2021.
https://doi.org/10.1016/j.media.2020.101851
MIT License
647 stars 97 forks source link

Heterogeneous resolution yields non-zero boundary. #45

Open ramonemiliani93 opened 3 years ago

ramonemiliani93 commented 3 years ago

Hi, when the resolution for the distance maps is heterogeneous the formula in one_hot2dist will yield non-zero values in the boundaries. For example:

import numpy as np
from scipy.ndimage import distance_transform_edt as eedt

array = np.zeros((5, 5))
array[1:4, 1:4] = 1
resolution = (1, 0.5)

mask = array.astype(np.bool)
eedt(~mask, resolution) * ~mask - (eedt(mask, resolution) - 1) * mask

Here the boundaries will be 0.5 instead of 0. Maybe eroding one of the masks could help generalize:

import numpy as np
from scipy.ndimage import distance_transform_edt as eedt
from scipy.ndimage import binary_erosion

def signed_eedt(array: np.ndarray, resolution: Sequence[float]) -> np.ndarray:
    if not array.any():
        return np.zeros_like(array)

    mask = array.astype(np.bool)
    positive = eedt(~mask, resolution) * ~mask
    negative = eedt(binary_erosion(mask), resolution) * mask

    return positive - negative
HKervadec commented 3 years ago

Hi Ramone,

Thanks for the interest, this is really a corner case. Are you allowed to share any of such examples, with real-world data?

Did you try to train in-spite with the boundary at 0.5? Though the distance would be slightly off, I would not necessarily affect the minimization process much.

I will try to keep thinking about this in the coming days. Your suggested erosion might be enough.

Best,

Hoel

ramonemiliani93 commented 3 years ago

Hi Hoel,

Unfortunately I have no data to share, any other synthetic example will have the same problem. Using skimage.morphology.ball and slicing it through the middle may yield a better toy problem.

I agree the optimization shouldn't be affected by this; with the current implementation I did not train for long so I am unable to tell you about the results, on the other hand, the binary erosion is working. I have to train for longer and compare with only regional loss.

If you come up with something keep me posted.

Best,

Ramón

HKervadec commented 2 years ago

Hi Ramón,

Thank you for your useful feedback. I suppose I could (should) add some unit test for that. (I have some partial unit-testing file somewhere locally, that I haven't included in the repo.) That might help to decide how to deal with this corner case.

I have some deadlines coming up and I will not have time to handle that right now, so I will snooze this until late October.

Best,

Hoel

ramonemiliani93 commented 2 years ago

Hi Hoel,

Wish you the best with your deadlines! Yes, if at some point you add the unit test files, I could help you resolve the corner case.

Best,

Ramón

HKervadec commented 2 years ago

I just added a basic test.py in 8f4457416a583e33cae71443779591173e27ec62

Feel free to play around and add new test-cases, this would help to define the issue.

It seems that now the codebase triggers some deprecation warnings (I have updated my machine, so brand-new python, numpy and pytorch), I will investigate those.