I’m writing some Python code to label different objects in my image using connected components. I’m using 4-neighbors to evaluate each pixel’s label in my logic and I’m not using unionfind to create an equevalency list of the labels because I had some trouble understanding it and I don’t have enough time to use it without blantly copying it from someone else.

I’ll explain what I got up until now:

```
# -*- coding: utf-8 -*-
import cv2
import numpy as np
# input images
fig1 = cv2.imread("fig1.jpg", cv2.IMREAD_UNCHANGED)
# fig2 = cv2.imread("fig2.jpg", cv2.IMREAD_UNCHANGED)
# fig3 = cv2.imread("fig3.jpg", cv2.IMREAD_UNCHANGED)
# fig4 = cv2.imread("fig4.jpg", cv2.IMREAD_UNCHANGED)
def connected_components(img):
# working with a copy of the image just for good practice
im = img.copy()
im = cv2.bitwise_not(im) # inverting image to have white as 0 = not objects
# normalizing image to have a proper binary image
im = cv2.normalize(im, None, alpha=0, beta=1, norm_type=cv2.NORM_MINMAX, dtype=cv2.CV_8U)
im = cv2.copyMakeBorder(im, 1, 1, 1, 1, cv2.BORDER_CONSTANT, 0) # add padding to work ouside borders
labels = np.zeros((im.shape(0), im.shape(1)), dtype=int) # create label matrix with the same size of the image
corr = (0) # create a correlation array that already includes 0 as being 0
# this array works like this: position corr(15) = 1 if the label 15 is equivalent to the label 1
NextLabel = 1 # counts the label that will be placed on the next pixel with no labeled neighbors
# first pass - rastering through the image
for row in range(1, im.shape(0)):
for column in range(1, im.shape(1)):
if im(row, column) > 0: # if the current pixel is not a backgroud pixel
if im(row, column - 1) == 0 and im(row - 1, column) == 0: # if both neighboring pixels are 0
labels(row, column) = NextLabel
corr.append(NextLabel)
NextLabel += 1
elif im(row, column - 1) != 0 and im(row - 1, column) == 0: # if up pixel is 0 and left pixel is 1
labels(row, column) = labels(row, column - 1)
elif im(row, column - 1) == 0 and im(row - 1, column) != 0: # if up pixel is 1 and left pixel is 0
labels(row, column) = labels(row - 1, column)
elif im(row, column - 1) != 0 and im(row - 1, column) != 0: # if both are 1
labels(row, column) = min(labels(row, column - 1), labels(row - 1, column))
if corr(min(labels(row, column - 1), labels(row - 1, column))) != min(labels(row, column - 1), labels(row - 1, column)): # will explain later
corr(max(labels(row, column - 1), labels(row - 1, column))) = corr(min(labels(row, column - 1), labels(row - 1, column)))
else:
corr(max(labels(row, column - 1), labels(row - 1, column))) = min(labels(row, column - 1), labels(row - 1, column))
#
for s in range(2): # cheat for the correspondances to work
for i in range(1, labels.shape(0)-1): # normal way to assign the correspondant value to the label
for j in range(1, labels.shape(1)-1):
if labels(i, j) != corr(labels(i, j)):
labels(i, j) = corr(labels(i, j))
elementos = () # list of elements to fix number of elements on the picture
for i in range(labels.shape(0)):
for j in range(labels.shape(1)):
if labels(i, j) not in elementos:
elementos.append(labels(i, j))
for i in range(1, labels.shape(0)-1): # fix elements numbers
for j in range(1, labels.shape(1)-1):
labels(i, j) = elementos.index(labels(i, j))
return labels(1:labels.shape(0)-1, 1:labels.shape(1)-1) # returns original image without padding
# , im(1:labels.shape(0)-1, 1:labels.shape(1)-1)
a = connected_components(fig1)
# print(a)
```

So, in the part I said I’d explain later, I filter out if the correspondant value is assigned to a value that corresponds to itself, if not, I fix it. But it’s not working as expected. It only works if I apply the correspondances multiple times. E.g. if I have 13 corresponding to 12, 12 corresponding 11 and 11 corresponding to 1, if I fix it only once I’ll get rid of 13 -> 12, so 13 -> 11, but I want 13 -> 1. How can I assure it’ll always correspond to a number that only corresponds to itself? This is the code snipped that does this:

```
if corr(min(labels(row, column - 1), labels(row - 1, column))) != min(labels(row, column - 1), labels(row - 1, column)):
corr(max(labels(row, column - 1), labels(row - 1, column))) = corr(min(labels(row, column - 1), labels(row - 1, column)))
else:
corr(max(labels(row, column - 1), labels(row - 1, column))) = min(labels(row, column - 1), labels(row - 1, column))
```

This is the image I’m using:

My results for this image are as follows:

corr = (0, 1, 2, 2, 1, 2, 1, 2, 1, 2, 1, 2, 11, 1, 1, 2, 1, 2, 1, 1, 2, 1, 2, 1, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 48, 1, 1, 52, 52, 52, 52, 52, 52, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57)

elementos = (0, 1, 2, 52)

labels (with cheat) =

labels (without cheat) =

As you can see, there are some objects that have two values inside. If I use the “cheat” I can get rid of those, but I don’t think this cheat has a fixed value and I don’t want to let it there, because it’s wrong.

To see these array values just use a breakpoint on the return line and they’ll all show up!