1111import numpy as np
1212import colorsys
1313import fastremap
14+ import fill_voids
1415from multiprocessing import Pool , cpu_count
1516
1617from . import metrics
@@ -619,7 +620,7 @@ def size_distribution(masks):
619620def fill_holes_and_remove_small_masks (masks , min_size = 15 ):
620621 """ Fills holes in masks (2D/3D) and discards masks smaller than min_size.
621622
622- This function fills holes in each mask using scipy.ndimage.morphology.binary_fill_holes .
623+ This function fills holes in each mask using fill_voids.fill .
623624 It also removes masks that are smaller than the specified min_size.
624625
625626 Parameters:
@@ -640,20 +641,25 @@ def fill_holes_and_remove_small_masks(masks, min_size=15):
640641 raise ValueError ("masks_to_outlines takes 2D or 3D array, not %dD array" %
641642 masks .ndim )
642643
644+ # Filter small masks
645+ counts = fastremap .unique (masks , return_counts = True )[1 ][1 :]
646+ if min_size > 0 :
647+ masks = fastremap .mask (masks , np .nonzero (counts < min_size )[0 ] + 1 )
648+ fastremap .renumber (masks , in_place = True )
649+
643650 slices = find_objects (masks )
644651 j = 0
645- for i , slc in enumerate (slices ):
652+ for i in np .arange (0 , len (slices )):
653+ slc = slices [i ]
646654 if slc is not None :
647655 msk = masks [slc ] == (i + 1 )
648- npix = msk .sum ()
649- if min_size > 0 and npix < min_size :
650- masks [slc ][msk ] = 0
651- elif npix > 0 :
652- if msk .ndim == 3 :
653- for k in range (msk .shape [0 ]):
654- msk [k ] = binary_fill_holes (msk [k ])
655- else :
656- msk = binary_fill_holes (msk )
657- masks [slc ][msk ] = (j + 1 )
658- j += 1
656+ msk = fill_voids .fill (msk )
657+ masks [slc ][msk ] = (j + 1 )
658+ j += 1
659+
660+ if min_size > 0 :
661+ counts = fastremap .unique (masks , return_counts = True )[1 ][1 :]
662+ masks = fastremap .mask (masks , np .nonzero (counts < min_size )[0 ] + 1 )
663+ fastremap .renumber (masks , in_place = True )
664+
659665 return masks
0 commit comments