update
This commit is contained in:
171
.CondaPkg/env/Lib/site-packages/skimage/measure/_moments_analytical.py
vendored
Normal file
171
.CondaPkg/env/Lib/site-packages/skimage/measure/_moments_analytical.py
vendored
Normal file
@@ -0,0 +1,171 @@
|
||||
"""Analytical transformations from raw image moments to central moments.
|
||||
|
||||
The expressions for the 2D central moments of order <=2 are often given in
|
||||
textbooks. Expressions for higher orders and dimensions were generated in SymPy
|
||||
using ``tools/precompute/moments_sympy.py`` in the GitHub repository.
|
||||
|
||||
"""
|
||||
|
||||
import itertools
|
||||
import math
|
||||
|
||||
import numpy as np
|
||||
|
||||
|
||||
def _moments_raw_to_central_fast(moments_raw):
|
||||
"""Analytical formulae for 2D and 3D central moments of order < 4.
|
||||
|
||||
`moments_raw_to_central` will automatically call this function when
|
||||
ndim < 4 and order < 4.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
moments_raw : ndarray
|
||||
The raw moments.
|
||||
|
||||
Returns
|
||||
-------
|
||||
moments_central : ndarray
|
||||
The central moments.
|
||||
"""
|
||||
ndim = moments_raw.ndim
|
||||
order = moments_raw.shape[0] - 1
|
||||
float_dtype = moments_raw.dtype
|
||||
# convert to float64 during the computation for better accuracy
|
||||
moments_raw = moments_raw.astype(np.float64, copy=False)
|
||||
moments_central = np.zeros_like(moments_raw)
|
||||
if order >= 4 or ndim not in [2, 3]:
|
||||
raise ValueError("This function only supports 2D or 3D moments of order < 4.")
|
||||
m = moments_raw
|
||||
if ndim == 2:
|
||||
cx = m[1, 0] / m[0, 0]
|
||||
cy = m[0, 1] / m[0, 0]
|
||||
moments_central[0, 0] = m[0, 0]
|
||||
# Note: 1st order moments are both 0
|
||||
if order > 1:
|
||||
# 2nd order moments
|
||||
moments_central[1, 1] = m[1, 1] - cx * m[0, 1]
|
||||
moments_central[2, 0] = m[2, 0] - cx * m[1, 0]
|
||||
moments_central[0, 2] = m[0, 2] - cy * m[0, 1]
|
||||
if order > 2:
|
||||
# 3rd order moments
|
||||
moments_central[2, 1] = (
|
||||
m[2, 1]
|
||||
- 2 * cx * m[1, 1]
|
||||
- cy * m[2, 0]
|
||||
+ cx**2 * m[0, 1]
|
||||
+ cy * cx * m[1, 0]
|
||||
)
|
||||
moments_central[1, 2] = (
|
||||
m[1, 2] - 2 * cy * m[1, 1] - cx * m[0, 2] + 2 * cy * cx * m[0, 1]
|
||||
)
|
||||
moments_central[3, 0] = m[3, 0] - 3 * cx * m[2, 0] + 2 * cx**2 * m[1, 0]
|
||||
moments_central[0, 3] = m[0, 3] - 3 * cy * m[0, 2] + 2 * cy**2 * m[0, 1]
|
||||
else:
|
||||
# 3D case
|
||||
cx = m[1, 0, 0] / m[0, 0, 0]
|
||||
cy = m[0, 1, 0] / m[0, 0, 0]
|
||||
cz = m[0, 0, 1] / m[0, 0, 0]
|
||||
moments_central[0, 0, 0] = m[0, 0, 0]
|
||||
# Note: all first order moments are 0
|
||||
if order > 1:
|
||||
# 2nd order moments
|
||||
moments_central[0, 0, 2] = -cz * m[0, 0, 1] + m[0, 0, 2]
|
||||
moments_central[0, 1, 1] = -cy * m[0, 0, 1] + m[0, 1, 1]
|
||||
moments_central[0, 2, 0] = -cy * m[0, 1, 0] + m[0, 2, 0]
|
||||
moments_central[1, 0, 1] = -cx * m[0, 0, 1] + m[1, 0, 1]
|
||||
moments_central[1, 1, 0] = -cx * m[0, 1, 0] + m[1, 1, 0]
|
||||
moments_central[2, 0, 0] = -cx * m[1, 0, 0] + m[2, 0, 0]
|
||||
if order > 2:
|
||||
# 3rd order moments
|
||||
moments_central[0, 0, 3] = (
|
||||
2 * cz**2 * m[0, 0, 1] - 3 * cz * m[0, 0, 2] + m[0, 0, 3]
|
||||
)
|
||||
moments_central[0, 1, 2] = (
|
||||
-cy * m[0, 0, 2] + 2 * cz * (cy * m[0, 0, 1] - m[0, 1, 1]) + m[0, 1, 2]
|
||||
)
|
||||
moments_central[0, 2, 1] = (
|
||||
cy**2 * m[0, 0, 1]
|
||||
- 2 * cy * m[0, 1, 1]
|
||||
+ cz * (cy * m[0, 1, 0] - m[0, 2, 0])
|
||||
+ m[0, 2, 1]
|
||||
)
|
||||
moments_central[0, 3, 0] = (
|
||||
2 * cy**2 * m[0, 1, 0] - 3 * cy * m[0, 2, 0] + m[0, 3, 0]
|
||||
)
|
||||
moments_central[1, 0, 2] = (
|
||||
-cx * m[0, 0, 2] + 2 * cz * (cx * m[0, 0, 1] - m[1, 0, 1]) + m[1, 0, 2]
|
||||
)
|
||||
moments_central[1, 1, 1] = (
|
||||
-cx * m[0, 1, 1]
|
||||
+ cy * (cx * m[0, 0, 1] - m[1, 0, 1])
|
||||
+ cz * (cx * m[0, 1, 0] - m[1, 1, 0])
|
||||
+ m[1, 1, 1]
|
||||
)
|
||||
moments_central[1, 2, 0] = (
|
||||
-cx * m[0, 2, 0] - 2 * cy * (-cx * m[0, 1, 0] + m[1, 1, 0]) + m[1, 2, 0]
|
||||
)
|
||||
moments_central[2, 0, 1] = (
|
||||
cx**2 * m[0, 0, 1]
|
||||
- 2 * cx * m[1, 0, 1]
|
||||
+ cz * (cx * m[1, 0, 0] - m[2, 0, 0])
|
||||
+ m[2, 0, 1]
|
||||
)
|
||||
moments_central[2, 1, 0] = (
|
||||
cx**2 * m[0, 1, 0]
|
||||
- 2 * cx * m[1, 1, 0]
|
||||
+ cy * (cx * m[1, 0, 0] - m[2, 0, 0])
|
||||
+ m[2, 1, 0]
|
||||
)
|
||||
moments_central[3, 0, 0] = (
|
||||
2 * cx**2 * m[1, 0, 0] - 3 * cx * m[2, 0, 0] + m[3, 0, 0]
|
||||
)
|
||||
|
||||
return moments_central.astype(float_dtype, copy=False)
|
||||
|
||||
|
||||
def moments_raw_to_central(moments_raw):
|
||||
ndim = moments_raw.ndim
|
||||
order = moments_raw.shape[0] - 1
|
||||
if ndim in [2, 3] and order < 4:
|
||||
return _moments_raw_to_central_fast(moments_raw)
|
||||
|
||||
moments_central = np.zeros_like(moments_raw)
|
||||
m = moments_raw
|
||||
# centers as computed in centroid above
|
||||
centers = tuple(m[tuple(np.eye(ndim, dtype=int))] / m[(0,) * ndim])
|
||||
|
||||
if ndim == 2:
|
||||
# This is the general 2D formula from
|
||||
# https://en.wikipedia.org/wiki/Image_moment#Central_moments
|
||||
for p in range(order + 1):
|
||||
for q in range(order + 1):
|
||||
if p + q > order:
|
||||
continue
|
||||
for i in range(p + 1):
|
||||
term1 = math.comb(p, i)
|
||||
term1 *= (-centers[0]) ** (p - i)
|
||||
for j in range(q + 1):
|
||||
term2 = math.comb(q, j)
|
||||
term2 *= (-centers[1]) ** (q - j)
|
||||
moments_central[p, q] += term1 * term2 * m[i, j]
|
||||
return moments_central
|
||||
|
||||
# The nested loops below are an n-dimensional extension of the 2D formula
|
||||
# given at https://en.wikipedia.org/wiki/Image_moment#Central_moments
|
||||
|
||||
# iterate over all [0, order] (inclusive) on each axis
|
||||
for orders in itertools.product(*((range(order + 1),) * ndim)):
|
||||
# `orders` here is the index into the `moments_central` output array
|
||||
if sum(orders) > order:
|
||||
# skip any moment that is higher than the requested order
|
||||
continue
|
||||
# loop over terms from `m` contributing to `moments_central[orders]`
|
||||
for idxs in itertools.product(*[range(o + 1) for o in orders]):
|
||||
val = m[idxs]
|
||||
for i_order, c, idx in zip(orders, centers, idxs):
|
||||
val *= math.comb(i_order, idx)
|
||||
val *= (-c) ** (i_order - idx)
|
||||
moments_central[orders] += val
|
||||
|
||||
return moments_central
|
||||
Reference in New Issue
Block a user