mirror of
https://github.com/wassname/scikit-image.git
synced 2026-08-12 12:30:16 +08:00
Make moments functions public, rename, add tests
This commit is contained in:
@@ -2,6 +2,7 @@ from .find_contours import find_contours
|
||||
from ._regionprops import regionprops, perimeter
|
||||
from ._structural_similarity import structural_similarity
|
||||
from ._polygon import approximate_polygon, subdivide_polygon
|
||||
from ._moments import moments, moments_central, moments_normalized, moments_hu
|
||||
from .fit import LineModel, CircleModel, EllipseModel, ransac
|
||||
from .block import block_reduce
|
||||
|
||||
@@ -16,4 +17,8 @@ __all__ = ['find_contours',
|
||||
'CircleModel',
|
||||
'EllipseModel',
|
||||
'ransac',
|
||||
'block_reduce']
|
||||
'block_reduce',
|
||||
'moments',
|
||||
'moments_central',
|
||||
'moments_normalized',
|
||||
'moments_hu']
|
||||
|
||||
@@ -4,15 +4,79 @@
|
||||
#cython: wraparound=False
|
||||
import numpy as np
|
||||
|
||||
cimport numpy as cnp
|
||||
|
||||
|
||||
def moments(double[:, :] image, Py_ssize_t order=3):
|
||||
return central_moments(image, 0, 0, order)
|
||||
"""Calculate all raw image moments up to a certain order.
|
||||
|
||||
The following properties can be calculated from raw image moments:
|
||||
* Area as ``m[0, 0]``.
|
||||
* Centroid as {``m[0, 1] / m[0, 0]``, ``m[1, 0] / m[0, 0]``}.
|
||||
|
||||
Note that raw moments are whether translation, scale nor rotation
|
||||
invariant.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
image : 2D double array
|
||||
Rasterized shape as image.
|
||||
order : int, optional
|
||||
Maximum order of moments. Default is 3.
|
||||
|
||||
Returns
|
||||
-------
|
||||
m : (``order + 1``, ``order + 1``) array
|
||||
Raw image moments.
|
||||
|
||||
References
|
||||
----------
|
||||
.. [1] Wilhelm Burger, Mark Burge. Principles of Digital Image Processing:
|
||||
Core Algorithms. Springer-Verlag, London, 2009.
|
||||
.. [2] B. Jähne. Digital Image Processing. Springer-Verlag,
|
||||
Berlin-Heidelberg, 6. edition, 2005.
|
||||
.. [3] T. H. Reiss. Recognizing Planar Objects Using Invariant Image
|
||||
Features, from Lecture notes in computer science, p. 676. Springer,
|
||||
Berlin, 1993.
|
||||
.. [4] http://en.wikipedia.org/wiki/Image_moment
|
||||
|
||||
"""
|
||||
return moments_central(image, 0, 0, order)
|
||||
|
||||
|
||||
def central_moments(double[:, :] image, double cr, double cc,
|
||||
def moments_central(double[:, :] image, double cr, double cc,
|
||||
Py_ssize_t order=3):
|
||||
"""Calculate all central image moments up to a certain order.
|
||||
|
||||
Note that central moments are translation invariant but not scale and
|
||||
rotation invariant.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
image : 2D double array
|
||||
Rasterized shape as image.
|
||||
cr : double
|
||||
Center row coordinate.
|
||||
cc : double
|
||||
Center column coordinate.
|
||||
order : int, optional
|
||||
Maximum order of moments. Default is 3.
|
||||
|
||||
Returns
|
||||
-------
|
||||
mu : (``order + 1``, ``order + 1``) array
|
||||
Central image moments.
|
||||
|
||||
References
|
||||
----------
|
||||
.. [1] Wilhelm Burger, Mark Burge. Principles of Digital Image Processing:
|
||||
Core Algorithms. Springer-Verlag, London, 2009.
|
||||
.. [2] B. Jähne. Digital Image Processing. Springer-Verlag,
|
||||
Berlin-Heidelberg, 6. edition, 2005.
|
||||
.. [3] T. H. Reiss. Recognizing Planar Objects Using Invariant Image
|
||||
Features, from Lecture notes in computer science, p. 676. Springer,
|
||||
Berlin, 1993.
|
||||
.. [4] http://en.wikipedia.org/wiki/Image_moment
|
||||
|
||||
"""
|
||||
cdef Py_ssize_t p, q, r, c
|
||||
cdef double[:, ::1] mu = np.zeros((order + 1, order + 1), dtype=np.double)
|
||||
for p in range(order + 1):
|
||||
@@ -23,7 +87,36 @@ def central_moments(double[:, :] image, double cr, double cc,
|
||||
return np.asarray(mu)
|
||||
|
||||
|
||||
def normalized_moments(double[:, :] mu, Py_ssize_t order=3):
|
||||
def moments_normalized(double[:, :] mu, Py_ssize_t order=3):
|
||||
"""Calculate all normalized central image moments up to a certain order.
|
||||
|
||||
Note that normalized central moments are translation and scale invariant
|
||||
but not rotation invariant.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
mu : (M, M) array
|
||||
Central image moments, where M must be > ``order``.
|
||||
order : int, optional
|
||||
Maximum order of moments. Default is 3.
|
||||
|
||||
Returns
|
||||
-------
|
||||
nu : (``order + 1``, ``order + 1``) array
|
||||
Normalized central image moments.
|
||||
|
||||
References
|
||||
----------
|
||||
.. [1] Wilhelm Burger, Mark Burge. Principles of Digital Image Processing:
|
||||
Core Algorithms. Springer-Verlag, London, 2009.
|
||||
.. [2] B. Jähne. Digital Image Processing. Springer-Verlag,
|
||||
Berlin-Heidelberg, 6. edition, 2005.
|
||||
.. [3] T. H. Reiss. Recognizing Planar Objects Using Invariant Image
|
||||
Features, from Lecture notes in computer science, p. 676. Springer,
|
||||
Berlin, 1993.
|
||||
.. [4] http://en.wikipedia.org/wiki/Image_moment
|
||||
|
||||
"""
|
||||
cdef Py_ssize_t p, q
|
||||
cdef double[:, ::1] nu = np.zeros((order + 1, order + 1), dtype=np.double)
|
||||
for p in range(order + 1):
|
||||
@@ -35,7 +128,37 @@ def normalized_moments(double[:, :] mu, Py_ssize_t order=3):
|
||||
return np.asarray(nu)
|
||||
|
||||
|
||||
def hu_moments(double[:, :] nu):
|
||||
def moments_hu(double[:, :] nu):
|
||||
"""Calculate Hu's set of image moments.
|
||||
|
||||
Note that this set of moments is proofed to be translation, scale and
|
||||
rotation invariant.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
nu : (M, M) array
|
||||
Normalized central image moments, where M must be > 4.
|
||||
|
||||
Returns
|
||||
-------
|
||||
nu : (7, 1) array
|
||||
Hu's set of image moments.
|
||||
|
||||
References
|
||||
----------
|
||||
.. [1] M. K. Hu, "Visual Pattern Recognition by Moment Invariants",
|
||||
IRE Trans. Info. Theory, vol. IT-8, pp. 179-187, 1962
|
||||
.. [2] Wilhelm Burger, Mark Burge. Principles of Digital Image Processing:
|
||||
Core Algorithms. Springer-Verlag, London, 2009.
|
||||
.. [3] B. Jähne. Digital Image Processing. Springer-Verlag,
|
||||
Berlin-Heidelberg, 6. edition, 2005.
|
||||
.. [4] T. H. Reiss. Recognizing Planar Objects Using Invariant Image
|
||||
Features, from Lecture notes in computer science, p. 676. Springer,
|
||||
Berlin, 1993.
|
||||
.. [5] http://en.wikipedia.org/wiki/Image_moment
|
||||
|
||||
|
||||
"""
|
||||
cdef double[::1] hu = np.zeros((7, ), dtype=np.double)
|
||||
cdef double t0 = nu[3, 0] + nu[1, 2]
|
||||
cdef double t1 = nu[2, 1] + nu[0, 3]
|
||||
|
||||
@@ -18,7 +18,7 @@ STREL_8 = np.ones((3, 3), 'int8')
|
||||
PROPS = {
|
||||
'Area': 'area',
|
||||
'BoundingBox': 'bbox',
|
||||
'CentralMoments': 'central_moments',
|
||||
'CentralMoments': 'moments_central',
|
||||
'Centroid': 'centroid',
|
||||
'ConvexArea': 'convex_area',
|
||||
# 'ConvexHull',
|
||||
@@ -31,7 +31,7 @@ PROPS = {
|
||||
# 'Extrema',
|
||||
'FilledArea': 'filled_area',
|
||||
'FilledImage': 'filled_image',
|
||||
'HuMoments': 'hu_moments',
|
||||
'HuMoments': 'moments_hu',
|
||||
'Image': 'image',
|
||||
'Label': 'label',
|
||||
'MajorAxisLength': 'major_axis_length',
|
||||
@@ -40,7 +40,7 @@ PROPS = {
|
||||
'MinIntensity': 'min_intensity',
|
||||
'MinorAxisLength': 'minor_axis_length',
|
||||
'Moments': 'moments',
|
||||
'NormalizedMoments': 'normalized_moments',
|
||||
'NormalizedMoments': 'moments_normalized',
|
||||
'Orientation': 'orientation',
|
||||
'Perimeter': 'perimeter',
|
||||
# 'PixelIdxList',
|
||||
@@ -49,9 +49,9 @@ PROPS = {
|
||||
# 'SubarrayIdx'
|
||||
'WeightedCentralMoments': 'weighted_central_moments',
|
||||
'WeightedCentroid': 'weighted_centroid',
|
||||
'WeightedHuMoments': 'weighted_hu_moments',
|
||||
'WeightedHuMoments': 'weighted_moments_hu',
|
||||
'WeightedMoments': 'weighted_moments',
|
||||
'WeightedNormalizedMoments': 'weighted_normalized_moments'
|
||||
'WeightedNormalizedMoments': 'weighted_moments_normalized'
|
||||
}
|
||||
|
||||
|
||||
@@ -128,9 +128,9 @@ class _RegionProperties(object):
|
||||
return row + self._slice[0].start, col + self._slice[1].start
|
||||
|
||||
@_cached_property
|
||||
def central_moments(self):
|
||||
def moments_central(self):
|
||||
row, col = self.local_centroid
|
||||
return _moments.central_moments(self._image_double, row, col, 3)
|
||||
return _moments.moments_central(self._image_double, row, col, 3)
|
||||
|
||||
@_cached_property
|
||||
def convex_area(self):
|
||||
@@ -177,8 +177,8 @@ class _RegionProperties(object):
|
||||
return ndimage.binary_fill_holes(self.image, STREL_8)
|
||||
|
||||
@_cached_property
|
||||
def hu_moments(self):
|
||||
return _moments.hu_moments(self.normalized_moments)
|
||||
def moments_hu(self):
|
||||
return _moments.moments_hu(self.moments_normalized)
|
||||
|
||||
@_cached_property
|
||||
def image(self):
|
||||
@@ -190,7 +190,7 @@ class _RegionProperties(object):
|
||||
|
||||
@_cached_property
|
||||
def inertia_tensor(self):
|
||||
mu = self.central_moments
|
||||
mu = self.moments_central
|
||||
a = mu[2, 0] / mu[0, 0]
|
||||
b = -mu[1, 1] / mu[0, 0]
|
||||
c = mu[0, 2] / mu[0, 0]
|
||||
@@ -248,8 +248,8 @@ class _RegionProperties(object):
|
||||
return 4 * sqrt(l2)
|
||||
|
||||
@_cached_property
|
||||
def normalized_moments(self):
|
||||
return _moments.normalized_moments(self.central_moments, 3)
|
||||
def moments_normalized(self):
|
||||
return _moments.moments_normalized(self.moments_central, 3)
|
||||
|
||||
@_cached_property
|
||||
def orientation(self):
|
||||
@@ -274,7 +274,7 @@ class _RegionProperties(object):
|
||||
@_cached_property
|
||||
def weighted_central_moments(self):
|
||||
row, col = self.weighted_local_centroid
|
||||
return _moments.central_moments(self._intensity_image_double,
|
||||
return _moments.moments_central(self._intensity_image_double,
|
||||
row, col, 3)
|
||||
|
||||
@_cached_property
|
||||
@@ -290,16 +290,16 @@ class _RegionProperties(object):
|
||||
return row, col
|
||||
|
||||
@_cached_property
|
||||
def weighted_hu_moments(self):
|
||||
return _moments.hu_moments(self.weighted_normalized_moments)
|
||||
def weighted_moments_hu(self):
|
||||
return _moments.moments_hu(self.weighted_moments_normalized)
|
||||
|
||||
@_cached_property
|
||||
def weighted_moments(self):
|
||||
return _moments.central_moments(self._intensity_image_double, 0, 0, 3)
|
||||
return _moments.moments_central(self._intensity_image_double, 0, 0, 3)
|
||||
|
||||
@_cached_property
|
||||
def weighted_normalized_moments(self):
|
||||
return _moments.normalized_moments(self.weighted_central_moments, 3)
|
||||
def weighted_moments_normalized(self):
|
||||
return _moments.moments_normalized(self.weighted_central_moments, 3)
|
||||
|
||||
def __getitem__(self, key):
|
||||
value = getattr(self, key, None)
|
||||
@@ -347,7 +347,7 @@ def regionprops(label_image, properties=None,
|
||||
Number of pixels of region.
|
||||
**bbox** : tuple
|
||||
Bounding box `(min_row, min_col, max_row, max_col)`
|
||||
**central_moments** : (3, 3) ndarray
|
||||
**moments_central** : (3, 3) ndarray
|
||||
Central moments (translation invariant) up to 3rd order::
|
||||
|
||||
mu_ji = sum{ array(x, y) * (x - x_c)^j * (y - y_c)^i }
|
||||
@@ -379,7 +379,7 @@ def regionprops(label_image, properties=None,
|
||||
**filled_image** : (H, J) ndarray
|
||||
Binary region image with filled holes which has the same size as
|
||||
bounding box.
|
||||
**hu_moments** : tuple
|
||||
**moments_hu** : tuple
|
||||
Hu moments (translation, scale and rotation invariant).
|
||||
**image** : (H, J) ndarray
|
||||
Sliced binary region image which has the same size as bounding box.
|
||||
@@ -407,7 +407,7 @@ def regionprops(label_image, properties=None,
|
||||
m_ji = sum{ array(x, y) * x^j * y^i }
|
||||
|
||||
where the sum is over the `x`, `y` coordinates of the region.
|
||||
**normalized_moments** : (3, 3) ndarray
|
||||
**moments_normalized** : (3, 3) ndarray
|
||||
Normalized moments (translation and scale invariant) up to 3rd order::
|
||||
|
||||
nu_ji = mu_ji / m_00^[(i+j)/2 + 1]
|
||||
@@ -433,7 +433,7 @@ def regionprops(label_image, properties=None,
|
||||
**weighted_centroid** : array
|
||||
Centroid coordinate tuple `(row, col)` weighted with intensity
|
||||
image.
|
||||
**weighted_hu_moments** : tuple
|
||||
**weighted_moments_hu** : tuple
|
||||
Hu moments (translation, scale and rotation invariant) of intensity
|
||||
image.
|
||||
**weighted_moments** : (3, 3) ndarray
|
||||
@@ -442,7 +442,7 @@ def regionprops(label_image, properties=None,
|
||||
wm_ji = sum{ array(x, y) * x^j * y^i }
|
||||
|
||||
where the sum is over the `x`, `y` coordinates of the region.
|
||||
**weighted_normalized_moments** : (3, 3) ndarray
|
||||
**weighted_moments_normalized** : (3, 3) ndarray
|
||||
Normalized moments (translation and scale invariant) of intensity
|
||||
image up to 3rd order::
|
||||
|
||||
|
||||
@@ -47,8 +47,8 @@ def test_bbox():
|
||||
assert_array_almost_equal(bbox, (0, 0, SAMPLE.shape[0], SAMPLE.shape[1]-1))
|
||||
|
||||
|
||||
def test_central_moments():
|
||||
mu = regionprops(SAMPLE)[0].central_moments
|
||||
def test_moments_central():
|
||||
mu = regionprops(SAMPLE)[0].moments_central
|
||||
# determined with OpenCV
|
||||
assert_almost_equal(mu[0,2], 436.00000000000045)
|
||||
# different from OpenCV results, bug in OpenCV
|
||||
@@ -129,8 +129,8 @@ def test_extent():
|
||||
assert_almost_equal(extent, 0.4)
|
||||
|
||||
|
||||
def test_hu_moments():
|
||||
hu = regionprops(SAMPLE)[0].hu_moments
|
||||
def test_moments_hu():
|
||||
hu = regionprops(SAMPLE)[0].moments_hu
|
||||
ref = np.array([
|
||||
3.27117627e-01,
|
||||
2.63869194e-02,
|
||||
@@ -216,8 +216,8 @@ def test_moments():
|
||||
assert_almost_equal(m[3,0], 95588.0)
|
||||
|
||||
|
||||
def test_normalized_moments():
|
||||
nu = regionprops(SAMPLE)[0].normalized_moments
|
||||
def test_moments_normalized():
|
||||
nu = regionprops(SAMPLE)[0].moments_normalized
|
||||
# determined with OpenCV
|
||||
assert_almost_equal(nu[0,2], 0.08410493827160502)
|
||||
assert_almost_equal(nu[1,1], -0.016846707818929982)
|
||||
@@ -260,9 +260,9 @@ def test_solidity():
|
||||
assert_almost_equal(solidity, 0.580645161290323)
|
||||
|
||||
|
||||
def test_weighted_central_moments():
|
||||
def test_weighted_moments():
|
||||
wmu = regionprops(SAMPLE, intensity_image=INTENSITY_SAMPLE
|
||||
)[0].weighted_central_moments
|
||||
)[0].weighted_moments_central
|
||||
ref = np.array(
|
||||
[[ 7.4000000000e+01, -2.1316282073e-13, 4.7837837838e+02,
|
||||
-7.5943608473e+02],
|
||||
@@ -283,9 +283,9 @@ def test_weighted_centroid():
|
||||
assert_array_almost_equal(centroid, (5.540540540540, 9.445945945945))
|
||||
|
||||
|
||||
def test_weighted_hu_moments():
|
||||
def test_weighted_moments_hu():
|
||||
whu = regionprops(SAMPLE, intensity_image=INTENSITY_SAMPLE
|
||||
)[0].weighted_hu_moments
|
||||
)[0].weighted_moments_hu
|
||||
ref = np.array([
|
||||
3.1750587329e-01,
|
||||
2.1417517159e-02,
|
||||
@@ -314,9 +314,9 @@ def test_weighted_moments():
|
||||
assert_array_almost_equal(wm, ref)
|
||||
|
||||
|
||||
def test_weighted_normalized_moments():
|
||||
def test_weighted_moments_normalized():
|
||||
wnu = regionprops(SAMPLE, intensity_image=INTENSITY_SAMPLE
|
||||
)[0].weighted_normalized_moments
|
||||
)[0].weighted_moments_normalized
|
||||
ref = np.array(
|
||||
[[ np.nan, np.nan, 0.0873590903, -0.0161217406],
|
||||
[ np.nan, -0.0160405109, -0.0031421072, -0.0031376984],
|
||||
|
||||
Reference in New Issue
Block a user