How to extract the largest connected component using OpenCV and Python?
Asked Answered
B

2

6

I am using OpenCV in Python to be able to identify only the Leaf presented on the image. I already be able to segment my image, and now I am currently stuck at "how to crop the largest component after I have detected all of them. Below is the codes, please have a look.

  1. Using scipy.ndimage, I was unable to advance after find the components:

    def undesired_objects ( image ):
        components, n = ndimage.label( image )
        components = skimage.morphology.remove_small_objects( components, min_size = 50 )
        components, n = ndimage.label( components )
        plot.imshow( components )
        plot.show()
    
  2. Using OpenCV connectedComponentsWithStats:

    def undesired_objects ( image ):
        image = image.astype( 'uint8' )
        nb_components, output, stats, centroids = cv2.connectedComponentsWithStats(image, connectivity=4)
        sizes = stats[1:, -1]; nb_components = nb_components - 1
        min_size = 150
        img2 = np.zeros(( output.shape ))
        for i in range(0, nb_components):
            if sizes[i] >= min_size:
                img2[output == i + 1] = 255
                plot.imshow( img2 )
                plot.show()
    

However, in both approaches, I'm still getting more than one component as result. Below, you will find the binary image:

Binary Image

Briggs answered 1/11, 2017 at 13:17 Comment(4)
Can you upload the binary image of which you are trying to find the largest connected component ?Shizukoshizuoka
@Shizukoshizuoka Updated with the binary image!Briggs
What's the problem with your result ? Your code is not guaranteed to output only one component. It will select all components bigger than your min_size parameter. And since you're not clearing your img2 between different components, they will all end up being drawn on the same image.Kantos
Yes, @Sunreef. I want to remove the min_size parameter to select only the bigger one; however, I'm stuck on itBriggs
K
8

I would replace your code with something like this:

def undesired_objects (image):
    image = image.astype('uint8')
    nb_components, output, stats, centroids = cv2.connectedComponentsWithStats(image, connectivity=4)
    sizes = stats[:, -1]

    max_label = 1
    max_size = sizes[1]
    for i in range(2, nb_components):
        if sizes[i] > max_size:
            max_label = i
            max_size = sizes[i]

    img2 = np.zeros(output.shape)
    img2[output == max_label] = 255
    cv2.imshow("Biggest component", img2)
    cv2.waitKey()

The loop on components now finds the component with the biggest area and displays it at the end of the loop.

Tell me if this works for you as I haven't tested it myself.

Kantos answered 1/11, 2017 at 14:35 Comment(1)
Thank you, @Sunreef. It works well; however, my results are still poor, I will need to find another approach to solve my issueBriggs
P
2

Using cv2.CC_STAT_AREA for readability:

# Connected components with stats.
nb_components, output, stats, centroids = cv2.connectedComponentsWithStats(image, connectivity=4)

# Find the largest non background component.
# Note: range() starts from 1 since 0 is the background label.
max_label, max_size = max([(i, stats[i, cv2.CC_STAT_AREA]) for i in range(1, nb_components)], key=lambda x: x[1])

More here: https://mcmap.net/q/258365/-how-to-use-opencv-39-s-connectedcomponentswithstats-in-python

Perez answered 7/5, 2020 at 16:17 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.