Search code examples
pythonimage-processingimage-segmentationscikit-image

How do I filter by area or eccentricity using skimage.measure.regionprops on a binary image in Python


I have a binary image of a road surface and I am trying to isolate the pothole only. Using skimage.measure.regionprops and skimage.measure.label I can produce a table of properties for different labels within the image.

How do I then filter using those values? - for instance using area or axis length or eccentricity to turn off certain labels. Input, labled Image and properties table

using python 3


Solution

  • I would use pandas together with skimage.measure.regionprops_table to get what you want:

    import pandas as pd
    import imageio as iio
    from skimage.measure import regionprops_table, label
    
    image = np.asarray(iio.imread('path/to/image.png'))
    labeled = label(image > 0)  # ensure input is binary
    data = regionprops_table(
            labeled,
            properties=('label', 'eccentricity'),
            )
    table = pd.DataFrame(data)
    table_sorted_by_ecc = table.sort_values(
            by='eccentricity', ascending=False
            )
    
    # print e.g. the 10 most eccentric labels
    print(table_sorted.iloc[:10])
    

    If you then want to e.g. produce the label image with only the most eccentric label, you can do:

    eccentric_label = table['labels'].iloc[np.argmax(table['eccentricity'])]
    labeled_ecc = np.where(labeled == eccentric_label, eccentric_label, 0)
    

    You can also do more sophisticated things, e.g. make a label image with only labels above a certain eccentricity. Below, we use NumPy elementwise multiplication to produce an array that is the original label if that label has high eccentricity, or 0 otherwise. We then use the skimage.util.map_array function to map the original labels to either themselves or 0, again, depending on the eccentricity.

    from skimage.util import map_array
    
    ecc_threshold = 0.3
    eccentric_labels = table['labels'] * (table['eccentricity'] > ecc_threshold)
    new_labels = map_array(
            labeled,
            np.asarray(table['labels']),
            np.asarray(eccentric_labels),
            )