-
-
Notifications
You must be signed in to change notification settings - Fork 2.2k
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
Crofton perimeter and Euler number #4121
base: main
Are you sure you want to change the base?
Conversation
Added crofton perimeter approximation for 2D binary images.
Modified Euler number function to get correct values. Added example to show different perimeters on a rotated square.
Added Euler number evaluation in 3D. Algorithm is on O(m), with m the number of pixels in image. Euler number uses 8 connectivity by default, 26 in 3D. Modified test in consequence. Typos in example
This comment has been minimized.
This comment has been minimized.
mainly removed trailing whitespace and ; at ends of lines
thank you @yg42 ! I'll review your PR in the next couple of days, I'm very excited about having these features for 3D images. Maybe @alexdesiqueira is also an appropriate reviewer. |
So I started playing a bit adapting your example and it's possible that there is a bug somewhere because the result below looks fishy to me:
I would not expect the Crofton perimeter to be so different from perimeter... Did I miss something? I'll keep on investigating. |
@emmanuelle Perimeter function only counts the outer contour, is this an expected behavior? I would say no. If I test on a disk I get the same result. My proposition of Crofton perimeter gives approximately the same perimeter for a disk.
|
Oh yes my example was actually very convoluted :-), sorry about that. I was trying to find an example for which crofton perimeter would get more accurate results than the perimeter function with 4 neighbors, because in the original gallery example you provided, they look really close. |
Would it be possible to explain more the pros and cons of the two algorithms? |
skimage/measure/_regionprops.py
Outdated
Parameters | ||
---------- | ||
image: (N, M) ndarray | ||
2D image. If image is not binary, all strictly greater than zero values |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
all values strictly greater than zero
skimage/measure/_regionprops.py
Outdated
0, 1, 0, 0, 0, 0, 0, -1, 0] | ||
bins = 16 | ||
else: # 3D images | ||
F = np.array([[[0, 0, 0], [0, 0, 0], [0, 0, 0]], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is it possible to find a more self-explaining name than F
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I changed it to config, as this describes a configuration neighbourhood.
Co-Authored-By: Mark Harfouche <mark.harfouche@gmail.com>
There is no big difference, which is good! As you know, the perimeter evaluation is really tricky and there is no absolute method to measure it. You can only have approximations. Crofton perimeter, as well as previously present perimeter function in skimage are one of them. OpenCV has a different approach: it approximates the contour with polygons and evaluates the arc length. In fact, the question of evaluating the perimeter is linked to finding the original boundary of the discretized object. Maybe I will work on this last approach and try to include it in skimage. In 3D, this is the same problem as surface area evaluation, I know you mentioned it in feature requests. This is not easy to evaluate the efficiency of a perimeter function, and I wouldnt dare saying that one method is better than the other. |
Co-Authored-By: Mark Harfouche <mark.harfouche@gmail.com>
Added explanations Modified variable name to be explicit Corrected english in comments
skimage/measure/_regionprops.py
Outdated
@@ -835,6 +846,133 @@ def regionprops(label_image, intensity_image=None, cache=True): | |||
return regions | |||
|
|||
|
|||
def euler_number(image, neighbourhood=8): | |||
"""Calculate the Euler characteristic in 2D binary image, that characterize |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
2D or 3D
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok
skimage/measure/_regionprops.py
Outdated
"""Calculate the Euler characteristic in 2D binary image, that characterize | ||
the topology of the objects. | ||
|
||
A neighbourhood configuration is constructed (see variable config), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would remove "see variable config" since we don't expect users reading the docstring to read the code as well. However you can move this to a comment within the function.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok
@yg42 regarding perimeter evaluation based on polygons, we already have the building blocks for this with marching cubes in 3d and |
Out of curiosity, why did you want to have Crofton perimeter in scikit-image? The Euler number in 3D was clearly missing (all the more if the 2D version is buggy), but I have more mixed feelings about adding another perimeter function. |
Thank you very much @yg42. I left a couple of minor comments, besides we also need
I know it's a lot of work, please bear with us! |
@emmanuelle About the Crofton perimeter interest, I wanted to make a presentation to my colleagues who work in the field of chemical engineering. As most of the users of skimage (I suppose), they are not aware that a perimeter in discrete objects is only an approximation, and I wanted to illustrate this by simple examples (I added the perimeter evaluation of a rotated square in the examples). For this purpose, I coded the Crofton perimeter. As this code is really similar to the Euler characteristic evaluation, I detected some problems on it and decided to submit these two methods. In my opinion, Crofton perimeter has to be in the measure submodule. Does it have to be in regionprops? It can create confusion for general users, but it is an interesting property, mathematically elegant, and practically quite precise for high sampling and general objects. I will soon add explanations and discussion in the gallery example, even if the Crofton perimeter is not included, it can be interesting to warn people about this approximation. I will propose an example illustrating the Euler number, but I have to think of it. |
Thank you @yg42 ! One thing I forgot: since you're adding new features and the behavior of |
ok, I mentioned it as a bug and as a new feature (the function is now a method and has neighbourhood parameters). I will wait for a decision about the crofton perimeter. |
Change name of function to perimeter_crofton in order to use autocompletion
Connectivity is used instead of neighborhood. the example was not using this parameter.
Added sentence to explain objects and holes Reduced the number of generated images
change in description of euler number function
I did my best to rebase on trunk. Just tell me if I still have things to do. :) |
@emmanuelle |
@alexdesiqueira @jni @emmanuelle |
@yg42 apologies, I have had an extremely busy past few weeks. I will try to review this properly next week, if someone doesn't beat me to it! |
I think this is a very exciting PR, but I need a bit more time to read through the theoretical aspects. |
Hi all, |
Description
This PR consists in 2 changes in regionprops functions
A new Euler number function is proposed, that uses convolution to get configurations codes, followed by a scalar product. This algorithm is in O(m), with m the total number of pixels in the image. It works for 2D and 3D images. Notice that I propose this method because it seemed that there was an error in the previous version (I compared with the matlab version). I got the coefficients from [1] for 2D images and [2] for 3D images.
[1] S. Rivollier. Analyse d’image geometrique et morphometrique par diagrammes de forme et voisinages adaptatifs generaux. PhD thesis, 2010. Ecole Nationale Superieure des Mines de Saint-Etienne. https://tel.archives-ouvertes.fr/tel-00560838
[2] Ohser J., Nagel W., Schladitz K. (2002) The Euler Number of Discretized Sets - On the Choice of Adjacency in Homogeneous Lattices. In: Mecke K., Stoyan D. (eds) Morphology of Condensed Matter. Lecture Notes in Physics, vol 600. Springer, Berlin, Heidelberg
A new perimeter method, based on the Crofton formula [3], is proposed. The same algorithm as for Euler number is used. It works only for 2D images.
I added an example to illustrate the approximation of the 2 different perimeter methods with 4 and 8 connectivity. The perimeter of a rotated square is represented as a function of the rotation angle.
[3] https://en.wikipedia.org/wiki/Crofton_formula
Note: There is an interesting link with #3812 and #3797, because minkowski functionals (volume, surface are, integral of mean curvature and Euler number in 3D) can be evaluated by the same method proposed in the previous references (see [4]). You can also refer to
Geometric measure in 2D and 3D for matlab, by D. Legland where a similar method is implemented using a marching cube approach.
[4] Ohser, J., & Schladitz, K. (2009). 3D images of materials structures: processing and analysis. John Wiley & Sons.
Checklist
./doc/examples
(new features only)./benchmarks
, if your changes aren't covered by anexisting benchmark
For reviewers
later.
__init__.py
.doc/release/release_dev.rst
.@meeseeksdev backport to v0.14.x