Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

minor_axis_length for 1 pixel objects #2792

Open
Phlya opened this issue Sep 5, 2017 · 4 comments
Open

minor_axis_length for 1 pixel objects #2792

Phlya opened this issue Sep 5, 2017 · 4 comments

Comments

@Phlya
Copy link
Contributor

Phlya commented Sep 5, 2017

Description

When an object has a width of 1 pixel, minor_axis_length (from regionprops) equals 0, while I expected it to be 1. Same goes for major_axis_length, if the object is just one pixel.
I would expect to never get zero width, since if width equals 0 then there is no object... This is very annoying when checks like p.major_axis_length/p.minor_axis_length>1.5 raise a ZeroDivisionError.

a = np.zeros((5, 5))
a[2:4, 2] = 1
pr = regionprops(label(a))
print(pr[0].major_axis_length)
print(pr[0].minor_axis_length)
#Output:
2.0
0.0

skimage 0.13.0, python3, Ubuntu 16.04

@stefanv
Copy link
Member

stefanv commented Sep 5, 2017

We should probably clip the result to 1, minimum, but also check carefully what happens for 2 pixels etc.

@soupault soupault added this to the 0.14.1 milestone Jan 15, 2018
@soupault soupault modified the milestones: 0.14.1, 0.14 Apr 27, 2018
@soupault soupault modified the milestones: 0.14, 0.14.1 May 29, 2018
@soupault soupault modified the milestones: 0.14.1, 0.15 Aug 20, 2018
@soupault soupault modified the milestones: 0.15, 0.16 Apr 20, 2019
@rfezzani
Copy link
Member

After some investigations, I found that this is due to the 'grid centered' (versus 'cell centered' paradigm) adopted in the skimage.measure._moments module.
In fact, minor_axis_length calls internally _moments.inertia_tensor_eigvals, with dependency to _moments.inertia_tensor, _moments.moments_central and finally _moments.centroid.

The output of this last function explains the behavior observed in this issue:

>>> from skimage.measure import _moments
>>> _moments.centroid(ones((1, )))
array([0.])
>>> _moments.centroid(ones((1, 1)))
array([0., 0.])
>>> _moments.centroid(ones((1, 2)))
array([0. , 0.5])
>>> _moments.centroid(ones((2, 1)))
array([0.5, 0. ])
>>> _moments.centroid(ones((2, 2)))
array([0.5, 0.5])

Clipping the the result to 1 as suggested by @stefanv in fact solves the problem, but what about enabling the cell centered paradigm?

@jni
Copy link
Member

jni commented Feb 14, 2020

@rfezzani do you have a source that defends the little square model as effectively as Alvy Ray attacks it? =)

http://alvyray.com/Memos/CG/Microsoft/6_pixel.pdf

Almost every time I've looked, I've found that the continuous-space model is more self-consistent, and easier to program with and reason about.

@rfezzani
Copy link
Member

rfezzani commented Feb 14, 2020

Concerning this subject @jni, I liked this blog post.

I think that we all agree that images manipulates data positioned on a grid. The cell centered paradigm doesn't stipulate that a pixel is a little square, it stipulates that the sampled values are positioned at the center of the grid cells, while the grid centered paradigm stipulates that it lies on the intersection points of the grid.

Both paradigms are valid, depending on the context in which they are involved ;-).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

7 participants