5

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

Tarcisiofl
  • 123
  • 1
  • 4
  • 16
  • Can you upload the binary image of which you are trying to find the largest connected component ? – ZdaR Nov 01 '17 at 13:18
  • @ZdaR Updated with the binary image! – Tarcisiofl Nov 01 '17 at 13:27
  • 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. – Sunreef Nov 01 '17 at 14:04
  • Yes, @Sunreef. I want to remove the min_size parameter to select only the bigger one; however, I'm stuck on it – Tarcisiofl Nov 01 '17 at 14:23

2 Answers2

7

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.

Sunreef
  • 4,452
  • 21
  • 33
  • Thank you, @Sunreef. It works well; however, my results are still poor, I will need to find another approach to solve my issue – Tarcisiofl Nov 01 '17 at 17:17
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://stackoverflow.com/a/35854198/650885

yang5
  • 1,125
  • 11
  • 16