1

My goal is to count objects in a binary array, using Python. I am applying the scikit-image measure.label, to to count objects(should be 1's) in the the array, despite reading the documentation-link, I am getting results that cannot be explained.

a=np.array(np.matrix('0 1 0 0 1;0 1 0 0 0; 0 0 0 0 0;0 0 0 0 1'))
print(a)
img=measure.label(a)
propsa = measure.regionprops(img)
length = len(propsa)
print ('length='+str(length))
for label in propsa:
    print (label.centroid)

>>> 
[[0 1 0 0 1]
 [0 1 0 0 0]
 [0 0 0 0 0]
 [0 0 0 0 1]]
length=3
(0.5, 1.0)
(0.0, 4.0)
(3.0, 4.0)

When background is selected to be zero,

a=np.array(np.matrix('0 1 0 0 1;0 1 0 0 0; 0 0 0 0 0;0 0 0 0 1'))
print(a)
img=measure.label(a, background=0)
propsa = measure.regionprops(img)
length = len(propsa)
print ('length='+str(length))
for label in propsa:
    print (label.centroid)

>>>
[[0 1 0 0 1]
 [0 1 0 0 0]
 [0 0 0 0 0]
 [0 0 0 0 1]]
length=2
(0.0, 4.0)
(3.0, 4.0)

Why is there inconsistent? From my understanding the label function labels "0" as -1 background?!

Following question It appears that measure.label of the CSV file example counts two objects a large one and its cavity. Sure enough when I inquiry the coordinates of the cavity of img I get a value of 2. Which means the cavity is the second object. Why is an aggregate of zeros counted as an object, and is there away around it?

length=2
(214.23444957510378, 505.25546156532539)
(238.77173913043478, 740.28260869565213)
>>> img[238,740]
2
>>> 
3
  • If you dislike skimage.measure.label's convention of labelling 'background' pixels as -1, another option would be to use scipy.ndimage.label. It does essentially the same thing, but always treats zeros in the input array as background, and assigns them a label of zero in the output. Commented Nov 20, 2015 at 21:18
  • Thanks that is very helpful, I was nearly hopeless! Your comment should be an answer so I can credit it. Thanks! Commented Nov 20, 2015 at 22:07
  • I'm glad my comment helped, but it's not really an answer to the question you originally posed (whereas fjarri's answer is) Commented Nov 20, 2015 at 22:31

2 Answers 2

4

For debug purposes it is useful to print the full labeled image. With background=0:

>>> print(img)
[[-1  0 -1 -1  1]
 [-1  0 -1 -1 -1]
 [-1 -1 -1 -1 -1]
 [-1 -1 -1 -1  2]]

The background is correctly labeled as -1. But when you call regionprops on it, it only returns RegionProperties objects for labels 1 and 2 because, as stated in the docs for regionprops(),

label_image : (N, M) ndarray

Labeled input image. Labels with value 0 are ignored.

Therefore the first area that has label 0 is ignored.

When background is not specified, the 0-filled area is has the label 0 and therefore ignored by regionprops(), giving the output of the remaining three 1-filled regions:

>>> print(img)
[[0 1 0 0 2]
 [0 1 0 0 0]
 [0 0 0 0 0]
 [0 0 0 0 3]]
Sign up to request clarification or add additional context in comments.

4 Comments

I understand the explanation, but not the logic, or the reasoning for labelling one of the three 1's group as 0. I use the background argument to explicitly inform the algorithm to focus on the foreground, whereas it appears it converts the first group of 1's from foreground to background, and then dose not count them?!
It does seem like an inconsistent labeling convention. If you start numbering supposedly meaningful things from 0 in one function (which is fine by itself, seeing how -1 is reserved for the background), you shouldn't treat 0 as the background in the other function. But I'm not very familiar with this area, so perhaps there's a rationale for it.
Fjarri, what was posted earlier was an attempt to understand the label function and background argument. What channelled me me to this is a a matrix(link above) that has a large object and a cavity. For some reason the cavity is counted though it is zeros. I am trying to find away around it.
If background is not set, every pixel in the image is "counted", that is, assigned a non-negative label. If background is set, it is assigned the label -1. That's just how the function's interface was designed. Note that this will change in v0.12, where the background will be more logically assigned 0. In your example the cavity is a separate region, and therefore assigned a label 2.
2

Ok here is simple solution that struck me. I can simply define background=0, and img=img+1. The problem was, when label is applied on the matrix with a background=0 the 0 values are changed to -1 and if I have a group of ones they are reduced to 0.Therefore by adding a 1, I adjust the img object to background=0 and any group of numbers that is not 0 will be counted.

Here is an example of what I mean:

    import matplotlib
    matplotlib.use('Gtk3Agg')
    import numpy as np
    from skimage import filters, morphology, measure
    np.set_printoptions(threshold=np.nan)

a=np.array(np.matrix('0 1 0 0 1;0 1 0 0 0; 0 0 0 0 0;0 0 0 1 1'))

print(a)

img=measure.label(a, background=0)
print('img=')
print (img)
#adjusting +1
img=img+1
print('img+1=')
print (img)
propsa = measure.regionprops(img)
length = len(propsa)
print ('length='+str(length))
for label in propsa:
    print (label.centroid)

The code returns the following.

>>> 
(4, 5)
[[0 1 0 0 1]
 [0 1 0 0 0]
 [0 0 0 0 0]
 [0 0 0 1 1]]
img=
[[-1  0 -1 -1  1]
 [-1  0 -1 -1 -1]
 [-1 -1 -1 -1 -1]
 [-1 -1 -1  2  2]]
img+1=
[[0 1 0 0 2]
 [0 1 0 0 0]
 [0 0 0 0 0]
 [0 0 0 3 3]]
length=3
(0.5, 1.0)
(0.0, 4.0)
(3.0, 3.5)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.