connected component labeling in python
Asked Answered
P

2

28

How to implement connected component labeling in python with open cv? This is an image example:

I need connected component labeling to separate objects on a black and white image.

Pox answered 27/9, 2017 at 7:28 Comment(0)
L
77

The OpenCV 3.0 docs for connectedComponents() don't mention Python but it actually is implemented. See for e.g. this SO question. On OpenCV 3.4.0 and above, the docs do include the Python signatures, as can be seen on the current master docs.

The function call is simple: num_labels, labels_im = cv2.connectedComponents(img) and you can specify a parameter connectivity to check for 4- or 8-way (default) connectivity. The difference is that 4-way connectivity just checks the top, bottom, left, and right pixels and sees if they connect; 8-way checks if any of the eight neighboring pixels connect. If you have diagonal connections (like you do here) you should specify connectivity=8. Note that it just numbers each component and gives them increasing integer labels starting at 0. So all the zeros are connected, all the ones are connected, etc. If you want to visualize them, you can map those numbers to specific colors. I like to map them to different hues, combine them into an HSV image, and then convert to BGR to display. Here's an example with your image:

import cv2
import numpy as np

img = cv2.imread('eGaIy.jpg', 0)
img = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY)[1]  # ensure binary
num_labels, labels_im = cv2.connectedComponents(img)

def imshow_components(labels):
    # Map component labels to hue val
    label_hue = np.uint8(179*labels/np.max(labels))
    blank_ch = 255*np.ones_like(label_hue)
    labeled_img = cv2.merge([label_hue, blank_ch, blank_ch])

    # cvt to BGR for display
    labeled_img = cv2.cvtColor(labeled_img, cv2.COLOR_HSV2BGR)

    # set bg label to black
    labeled_img[label_hue==0] = 0

    cv2.imshow('labeled.png', labeled_img)
    cv2.waitKey()

imshow_components(labels_im)

Labeled image

Lysine answered 27/9, 2017 at 7:43 Comment(5)
thanks alexander, i already use cv2.connectedComponents, but i found eror like this, AttributeError: 'module' object has no attribute 'connectedComponents'Pox
Ah, then you're likely on an older version of OpenCV where the bindings weren't ported over yet. What version of OpenCV are you using? If you can't upgrade, then consider another library like scikit-image; here's an example with that library. Alternatively you could detect contours and use that to label the image.Lysine
my opencv version '2.4.13'. thanks a lot, very helpful, I think my opencv needs an upgradePox
@AlexanderReynolds Thank you so much for this answer. This ret, labels = cv2.connectedComponents(img) is applicable on 2D arrays. Could I ask would it be possible to do it for 3D data?Woodhead
@Woodhead I don't think OpenCV's connected components works on 3D data, but I'm pretty sure scikit-image's connected components algorithm (skimage.morphology.label()) will. See the docs here. If that doesn't work, open up a new question for it and link me here and I'll take a look!Lysine
I
0

My adaptation of the CCL in 2D is:

1) Convert the image into a 1/0 image, with 1 being the object pixels and 0 being the background pixels.

2) Make a 2 pass CCL algorithm by implementing the Union-Find algorithm with pass compression. You can see more here.

In the First pass in this CCL implementation, you check the neighbor pixels, in the case your target pixel is an object pixel, and compare their label between them so that you can generate equivalences between them. You assign the least label, of those neighbor pixels which are objects pixels (label>0) to your target pixel. In this way, you are not only assigning an object label to your target pixesl (label>0) but also creating a list of equivalences.

2) In the second pass, you go through all the pixels, and change their previous label by the label of its parent label by just looking into the equivalent table stored in your Union-Find class.

3)I implemented an additional pass to make the labels follow a sequential order (1,2,3,4....) instead of a random order (23,45,1,...). That involves changing the labels "name" just for aesthetic purposes.

Impropriety answered 9/8, 2019 at 12:54 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.