mirror of
https://github.com/wassname/scikit-image.git
synced 2026-07-02 07:55:57 +08:00
Merge pull request #1815 from stefanv/regionprops_cached_decorator
Regionprops cached decorator
This commit is contained in:
@@ -7,6 +7,9 @@ from ._label import label
|
||||
from . import _moments
|
||||
|
||||
|
||||
from functools import wraps
|
||||
from collections import defaultdict
|
||||
|
||||
__all__ = ['regionprops', 'perimeter']
|
||||
|
||||
|
||||
@@ -20,14 +23,14 @@ PROPS = {
|
||||
'CentralMoments': 'moments_central',
|
||||
'Centroid': 'centroid',
|
||||
'ConvexArea': 'convex_area',
|
||||
# 'ConvexHull',
|
||||
# 'ConvexHull',
|
||||
'ConvexImage': 'convex_image',
|
||||
'Coordinates': 'coords',
|
||||
'Eccentricity': 'eccentricity',
|
||||
'EquivDiameter': 'equivalent_diameter',
|
||||
'EulerNumber': 'euler_number',
|
||||
'Extent': 'extent',
|
||||
# 'Extrema',
|
||||
# 'Extrema',
|
||||
'FilledArea': 'filled_area',
|
||||
'FilledImage': 'filled_image',
|
||||
'HuMoments': 'moments_hu',
|
||||
@@ -42,10 +45,10 @@ PROPS = {
|
||||
'NormalizedMoments': 'moments_normalized',
|
||||
'Orientation': 'orientation',
|
||||
'Perimeter': 'perimeter',
|
||||
# 'PixelIdxList',
|
||||
# 'PixelList',
|
||||
# 'PixelIdxList',
|
||||
# 'PixelList',
|
||||
'Solidity': 'solidity',
|
||||
# 'SubarrayIdx'
|
||||
# 'SubarrayIdx'
|
||||
'WeightedCentralMoments': 'weighted_moments_central',
|
||||
'WeightedCentroid': 'weighted_centroid',
|
||||
'WeightedHuMoments': 'weighted_moments_hu',
|
||||
@@ -56,52 +59,18 @@ PROPS = {
|
||||
PROP_VALS = set(PROPS.values())
|
||||
|
||||
|
||||
class _cached_property(object):
|
||||
"""Decorator to use a function as a cached property.
|
||||
def _cached(f):
|
||||
@wraps(f)
|
||||
def wrapper(obj):
|
||||
cache = obj._cache
|
||||
prop = f.__name__
|
||||
|
||||
The function is only called the first time and each successive call returns
|
||||
the cached result of the first call.
|
||||
if not ((prop in cache) and obj._cache_active):
|
||||
cache[prop] = f(obj)
|
||||
|
||||
class Foo(object):
|
||||
return cache[prop]
|
||||
|
||||
@_cached_property
|
||||
def foo(self):
|
||||
return "Cached"
|
||||
|
||||
class Foo(object):
|
||||
|
||||
def __init__(self):
|
||||
self._cache_active = False
|
||||
|
||||
@_cached_property
|
||||
def foo(self):
|
||||
return "Not cached"
|
||||
|
||||
Adapted from <http://wiki.python.org/moin/PythonDecoratorLibrary>.
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, func, name=None, doc=None):
|
||||
self.__name__ = name or func.__name__
|
||||
self.__module__ = func.__module__
|
||||
self.__doc__ = doc or func.__doc__
|
||||
self.func = func
|
||||
|
||||
def __get__(self, obj, type=None):
|
||||
if obj is None:
|
||||
return self
|
||||
|
||||
# call every time, if cache is not active
|
||||
if not obj.__dict__.get('_cache_active', True):
|
||||
return self.func(obj)
|
||||
|
||||
# try to retrieve from cache or call and store result in cache
|
||||
try:
|
||||
value = obj.__dict__[self.__name__]
|
||||
except KeyError:
|
||||
value = self.func(obj)
|
||||
obj.__dict__[self.__name__] = value
|
||||
return value
|
||||
return wrapper
|
||||
|
||||
|
||||
class _RegionProperties(object):
|
||||
@@ -112,75 +81,69 @@ class _RegionProperties(object):
|
||||
def __init__(self, slice, label, label_image, intensity_image,
|
||||
cache_active):
|
||||
self.label = label
|
||||
|
||||
self._slice = slice
|
||||
self._label_image = label_image
|
||||
self._intensity_image = intensity_image
|
||||
self._cache_active = cache_active
|
||||
|
||||
@property
|
||||
self._cache_active = cache_active
|
||||
self._cache = {}
|
||||
|
||||
def area(self):
|
||||
return self.moments[0, 0]
|
||||
|
||||
@property
|
||||
def bbox(self):
|
||||
return (self._slice[0].start, self._slice[1].start,
|
||||
self._slice[0].stop, self._slice[1].stop)
|
||||
|
||||
@property
|
||||
def centroid(self):
|
||||
row, col = self.local_centroid
|
||||
return row + self._slice[0].start, col + self._slice[1].start
|
||||
|
||||
@property
|
||||
def convex_area(self):
|
||||
return np.sum(self.convex_image)
|
||||
|
||||
@_cached_property
|
||||
@_cached
|
||||
def convex_image(self):
|
||||
from ..morphology.convex_hull import convex_hull_image
|
||||
return convex_hull_image(self.image)
|
||||
|
||||
@property
|
||||
def coords(self):
|
||||
rr, cc = np.nonzero(self.image)
|
||||
return np.vstack((rr + self._slice[0].start,
|
||||
cc + self._slice[1].start)).T
|
||||
|
||||
@property
|
||||
def eccentricity(self):
|
||||
l1, l2 = self.inertia_tensor_eigvals
|
||||
if l1 == 0:
|
||||
return 0
|
||||
return sqrt(1 - l2 / l1)
|
||||
|
||||
@property
|
||||
def equivalent_diameter(self):
|
||||
return sqrt(4 * self.moments[0, 0] / PI)
|
||||
|
||||
@property
|
||||
def euler_number(self):
|
||||
euler_array = self.filled_image != self.image
|
||||
_, num = label(euler_array, neighbors=8, return_num=True, background=-1)
|
||||
_, num = label(euler_array, neighbors=8, return_num=True,
|
||||
background=-1)
|
||||
return -num + 1
|
||||
|
||||
@property
|
||||
def extent(self):
|
||||
rows, cols = self.image.shape
|
||||
return self.moments[0, 0] / (rows * cols)
|
||||
|
||||
@property
|
||||
def filled_area(self):
|
||||
return np.sum(self.filled_image)
|
||||
|
||||
@_cached_property
|
||||
@_cached
|
||||
def filled_image(self):
|
||||
return ndi.binary_fill_holes(self.image, STREL_8)
|
||||
|
||||
@_cached_property
|
||||
@_cached
|
||||
def image(self):
|
||||
return self._label_image[self._slice] == self.label
|
||||
|
||||
@_cached_property
|
||||
@_cached
|
||||
def inertia_tensor(self):
|
||||
mu = self.moments_central
|
||||
a = mu[2, 0] / mu[0, 0]
|
||||
@@ -188,7 +151,7 @@ class _RegionProperties(object):
|
||||
c = mu[0, 2] / mu[0, 0]
|
||||
return np.array([[a, b], [b, c]])
|
||||
|
||||
@_cached_property
|
||||
@_cached
|
||||
def inertia_tensor_eigvals(self):
|
||||
a, b, b, c = self.inertia_tensor.flat
|
||||
# eigen values of inertia tensor
|
||||
@@ -196,64 +159,55 @@ class _RegionProperties(object):
|
||||
l2 = (a + c) / 2 - sqrt(4 * b ** 2 + (a - c) ** 2) / 2
|
||||
return l1, l2
|
||||
|
||||
@_cached_property
|
||||
@_cached
|
||||
def intensity_image(self):
|
||||
if self._intensity_image is None:
|
||||
raise AttributeError('No intensity image specified.')
|
||||
return self._intensity_image[self._slice] * self.image
|
||||
|
||||
@property
|
||||
def _intensity_image_double(self):
|
||||
return self.intensity_image.astype(np.double)
|
||||
|
||||
@property
|
||||
def local_centroid(self):
|
||||
m = self.moments
|
||||
row = m[0, 1] / m[0, 0]
|
||||
col = m[1, 0] / m[0, 0]
|
||||
return row, col
|
||||
|
||||
@property
|
||||
def max_intensity(self):
|
||||
return np.max(self.intensity_image[self.image])
|
||||
|
||||
@property
|
||||
def mean_intensity(self):
|
||||
return np.mean(self.intensity_image[self.image])
|
||||
|
||||
@property
|
||||
def min_intensity(self):
|
||||
return np.min(self.intensity_image[self.image])
|
||||
|
||||
@property
|
||||
def major_axis_length(self):
|
||||
l1, _ = self.inertia_tensor_eigvals
|
||||
return 4 * sqrt(l1)
|
||||
|
||||
@property
|
||||
def minor_axis_length(self):
|
||||
_, l2 = self.inertia_tensor_eigvals
|
||||
return 4 * sqrt(l2)
|
||||
|
||||
@_cached_property
|
||||
@_cached
|
||||
def moments(self):
|
||||
return _moments.moments(self.image.astype(np.uint8), 3)
|
||||
|
||||
@_cached_property
|
||||
@_cached
|
||||
def moments_central(self):
|
||||
row, col = self.local_centroid
|
||||
return _moments.moments_central(self.image.astype(np.uint8),
|
||||
row, col, 3)
|
||||
|
||||
@property
|
||||
def moments_hu(self):
|
||||
return _moments.moments_hu(self.moments_normalized)
|
||||
|
||||
@_cached_property
|
||||
@_cached
|
||||
def moments_normalized(self):
|
||||
return _moments.moments_normalized(self.moments_central, 3)
|
||||
|
||||
@property
|
||||
def orientation(self):
|
||||
a, b, b, c = self.inertia_tensor.flat
|
||||
b = -b
|
||||
@@ -265,41 +219,37 @@ class _RegionProperties(object):
|
||||
else:
|
||||
return - 0.5 * atan2(2 * b, (a - c))
|
||||
|
||||
@property
|
||||
def perimeter(self):
|
||||
return perimeter(self.image, 4)
|
||||
|
||||
@property
|
||||
def solidity(self):
|
||||
return self.moments[0, 0] / np.sum(self.convex_image)
|
||||
|
||||
@property
|
||||
def weighted_centroid(self):
|
||||
row, col = self.weighted_local_centroid
|
||||
return row + self._slice[0].start, col + self._slice[1].start
|
||||
|
||||
@property
|
||||
def weighted_local_centroid(self):
|
||||
m = self.weighted_moments
|
||||
row = m[0, 1] / m[0, 0]
|
||||
col = m[1, 0] / m[0, 0]
|
||||
return row, col
|
||||
|
||||
@_cached_property
|
||||
@_cached
|
||||
def weighted_moments(self):
|
||||
return _moments.moments_central(self._intensity_image_double, 0, 0, 3)
|
||||
return _moments.moments_central(self._intensity_image_double(),
|
||||
0, 0, 3)
|
||||
|
||||
@_cached_property
|
||||
@_cached
|
||||
def weighted_moments_central(self):
|
||||
row, col = self.weighted_local_centroid
|
||||
return _moments.moments_central(self._intensity_image_double,
|
||||
return _moments.moments_central(self._intensity_image_double(),
|
||||
row, col, 3)
|
||||
|
||||
@property
|
||||
def weighted_moments_hu(self):
|
||||
return _moments.moments_hu(self.weighted_moments_normalized)
|
||||
|
||||
@_cached_property
|
||||
@_cached
|
||||
def weighted_moments_normalized(self):
|
||||
return _moments.moments_normalized(self.weighted_moments_central, 3)
|
||||
|
||||
@@ -335,7 +285,7 @@ class _RegionProperties(object):
|
||||
|
||||
for key in PROP_VALS:
|
||||
try:
|
||||
#so that NaNs are equal
|
||||
# so that NaNs are equal
|
||||
np.testing.assert_equal(getattr(self, key, None),
|
||||
getattr(other, key, None))
|
||||
except AssertionError:
|
||||
@@ -352,7 +302,8 @@ def regionprops(label_image, intensity_image=None, cache=True):
|
||||
label_image : (N, M) ndarray
|
||||
Labeled input image. Labels with value 0 are ignored.
|
||||
intensity_image : (N, M) ndarray, optional
|
||||
Intensity image with same size as labeled image. Default is None.
|
||||
Intensity (i.e., input) image with same size as labeled image.
|
||||
Default is None.
|
||||
cache : bool, optional
|
||||
Determine whether to cache calculated properties. The computation is
|
||||
much faster for cached properties, whereas the memory consumption
|
||||
@@ -371,7 +322,7 @@ def regionprops(label_image, intensity_image=None, cache=True):
|
||||
**area** : int
|
||||
Number of pixels of region.
|
||||
**bbox** : tuple
|
||||
Bounding box ``(min_row, min_col, max_row, max_col)``
|
||||
Bounding box ``(min_row, min_col, max_row, max_col)``
|
||||
**centroid** : array
|
||||
Centroid coordinate tuple ``(row, col)``.
|
||||
**convex_area** : int
|
||||
@@ -405,8 +356,13 @@ def regionprops(label_image, intensity_image=None, cache=True):
|
||||
Inertia tensor of the region for the rotation around its mass.
|
||||
**inertia_tensor_eigvals** : tuple
|
||||
The two eigen values of the inertia tensor in decreasing order.
|
||||
**intensity_image** : ndarray
|
||||
Image inside region bounding box.
|
||||
**label** : int
|
||||
The label in the labeled input image.
|
||||
**local_centroid** : array
|
||||
Centroid coordinate tuple ``(row, col)``, relative to region bounding
|
||||
box.
|
||||
**major_axis_length** : float
|
||||
The length of the major axis of the ellipse that has the same
|
||||
normalized second central moments as the region.
|
||||
@@ -452,6 +408,9 @@ def regionprops(label_image, intensity_image=None, cache=True):
|
||||
**weighted_centroid** : array
|
||||
Centroid coordinate tuple ``(row, col)`` weighted with intensity
|
||||
image.
|
||||
**weighted_local_centroid** : array
|
||||
Centroid coordinate tuple ``(row, col)``, relative to region bounding
|
||||
box, weighted with intensity image.
|
||||
**weighted_moments** : (3, 3) ndarray
|
||||
Spatial moments of intensity image up to 3rd order::
|
||||
|
||||
@@ -568,7 +527,6 @@ def perimeter(image, neighbourhood=4):
|
||||
perimeter_weights[[21, 33]] = sqrt(2)
|
||||
perimeter_weights[[13, 23]] = (1 + sqrt(2)) / 2
|
||||
|
||||
|
||||
perimeter_image = ndi.convolve(border_image, np.array([[10, 2, 10],
|
||||
[ 2, 1, 2],
|
||||
[10, 2, 10]]),
|
||||
@@ -581,3 +539,32 @@ def perimeter(image, neighbourhood=4):
|
||||
perimeter_histogram = np.bincount(perimeter_image.ravel(), minlength=50)
|
||||
total_perimeter = np.dot(perimeter_histogram, perimeter_weights)
|
||||
return total_perimeter
|
||||
|
||||
|
||||
def _parse_docs():
|
||||
import re
|
||||
import textwrap
|
||||
|
||||
doc = regionprops.__doc__
|
||||
matches = re.finditer('\*\*(\w+)\*\* \:.*?\n(.*?)(?=\n [\*\S]+)',
|
||||
doc, flags=re.DOTALL)
|
||||
prop_doc = dict((m.group(1), textwrap.dedent(m.group(2))) for m in matches)
|
||||
|
||||
return prop_doc
|
||||
|
||||
|
||||
def _install_properties_docs():
|
||||
prop_doc = _parse_docs()
|
||||
|
||||
for p in [member for member in dir(_RegionProperties)
|
||||
if not member.startswith('_')]:
|
||||
try:
|
||||
getattr(_RegionProperties, p).__doc__ = prop_doc[p]
|
||||
except AttributeError:
|
||||
# For Python 2.x
|
||||
getattr(_RegionProperties, p).im_func.__doc__ = prop_doc[p]
|
||||
|
||||
setattr(_RegionProperties, p, property(getattr(_RegionProperties, p)))
|
||||
|
||||
|
||||
_install_properties_docs()
|
||||
|
||||
@@ -3,8 +3,8 @@ from numpy.testing import assert_array_equal, assert_almost_equal, \
|
||||
import numpy as np
|
||||
import math
|
||||
|
||||
from skimage.measure._regionprops import regionprops, PROPS, perimeter
|
||||
from skimage._shared._warnings import expected_warnings
|
||||
from skimage.measure._regionprops import (regionprops, PROPS, perimeter,
|
||||
_parse_docs)
|
||||
|
||||
|
||||
SAMPLE = np.array(
|
||||
@@ -63,14 +63,14 @@ def test_bbox():
|
||||
def test_moments_central():
|
||||
mu = regionprops(SAMPLE)[0].moments_central
|
||||
# determined with OpenCV
|
||||
assert_almost_equal(mu[0,2], 436.00000000000045)
|
||||
assert_almost_equal(mu[0, 2], 436.00000000000045)
|
||||
# different from OpenCV results, bug in OpenCV
|
||||
assert_almost_equal(mu[0,3], -737.333333333333)
|
||||
assert_almost_equal(mu[1,1], -87.33333333333303)
|
||||
assert_almost_equal(mu[1,2], -127.5555555555593)
|
||||
assert_almost_equal(mu[2,0], 1259.7777777777774)
|
||||
assert_almost_equal(mu[2,1], 2000.296296296291)
|
||||
assert_almost_equal(mu[3,0], -760.0246913580195)
|
||||
assert_almost_equal(mu[0, 3], -737.333333333333)
|
||||
assert_almost_equal(mu[1, 1], -87.33333333333303)
|
||||
assert_almost_equal(mu[1, 2], -127.5555555555593)
|
||||
assert_almost_equal(mu[2, 0], 1259.7777777777774)
|
||||
assert_almost_equal(mu[2, 1], 2000.296296296291)
|
||||
assert_almost_equal(mu[3, 0], -760.0246913580195)
|
||||
|
||||
|
||||
def test_centroid():
|
||||
@@ -145,13 +145,13 @@ def test_extent():
|
||||
def test_moments_hu():
|
||||
hu = regionprops(SAMPLE)[0].moments_hu
|
||||
ref = np.array([
|
||||
3.27117627e-01,
|
||||
2.63869194e-02,
|
||||
2.35390060e-02,
|
||||
1.23151193e-03,
|
||||
1.38882330e-06,
|
||||
3.27117627e-01,
|
||||
2.63869194e-02,
|
||||
2.35390060e-02,
|
||||
1.23151193e-03,
|
||||
1.38882330e-06,
|
||||
-2.72586158e-05,
|
||||
6.48350653e-06
|
||||
6.48350653e-06
|
||||
])
|
||||
# bug in OpenCV caused in Central Moments calculation?
|
||||
assert_array_almost_equal(hu, ref)
|
||||
@@ -217,27 +217,27 @@ def test_minor_axis_length():
|
||||
def test_moments():
|
||||
m = regionprops(SAMPLE)[0].moments
|
||||
# determined with OpenCV
|
||||
assert_almost_equal(m[0,0], 72.0)
|
||||
assert_almost_equal(m[0,1], 408.0)
|
||||
assert_almost_equal(m[0,2], 2748.0)
|
||||
assert_almost_equal(m[0,3], 19776.0)
|
||||
assert_almost_equal(m[1,0], 680.0)
|
||||
assert_almost_equal(m[1,1], 3766.0)
|
||||
assert_almost_equal(m[1,2], 24836.0)
|
||||
assert_almost_equal(m[2,0], 7682.0)
|
||||
assert_almost_equal(m[2,1], 43882.0)
|
||||
assert_almost_equal(m[3,0], 95588.0)
|
||||
assert_almost_equal(m[0, 0], 72.0)
|
||||
assert_almost_equal(m[0, 1], 408.0)
|
||||
assert_almost_equal(m[0, 2], 2748.0)
|
||||
assert_almost_equal(m[0, 3], 19776.0)
|
||||
assert_almost_equal(m[1, 0], 680.0)
|
||||
assert_almost_equal(m[1, 1], 3766.0)
|
||||
assert_almost_equal(m[1, 2], 24836.0)
|
||||
assert_almost_equal(m[2, 0], 7682.0)
|
||||
assert_almost_equal(m[2, 1], 43882.0)
|
||||
assert_almost_equal(m[3, 0], 95588.0)
|
||||
|
||||
|
||||
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)
|
||||
assert_almost_equal(nu[1,2], -0.002899800614433943)
|
||||
assert_almost_equal(nu[2,0], 0.24301268861454037)
|
||||
assert_almost_equal(nu[2,1], 0.045473992910668816)
|
||||
assert_almost_equal(nu[3,0], -0.017278118992041805)
|
||||
assert_almost_equal(nu[0, 2], 0.08410493827160502)
|
||||
assert_almost_equal(nu[1, 1], -0.016846707818929982)
|
||||
assert_almost_equal(nu[1, 2], -0.002899800614433943)
|
||||
assert_almost_equal(nu[2, 0], 0.24301268861454037)
|
||||
assert_almost_equal(nu[2, 1], 0.045473992910668816)
|
||||
assert_almost_equal(nu[3, 0], -0.017278118992041805)
|
||||
|
||||
|
||||
def test_orientation():
|
||||
@@ -277,14 +277,14 @@ def test_weighted_moments_central():
|
||||
wmu = regionprops(SAMPLE, intensity_image=INTENSITY_SAMPLE
|
||||
)[0].weighted_moments_central
|
||||
ref = np.array(
|
||||
[[ 7.4000000000e+01, -2.1316282073e-13, 4.7837837838e+02,
|
||||
-7.5943608473e+02],
|
||||
[ 3.7303493627e-14, -8.7837837838e+01, -1.4801314828e+02,
|
||||
-1.2714707125e+03],
|
||||
[ 1.2602837838e+03, 2.1571526662e+03, 6.6989799420e+03,
|
||||
1.5304076361e+04],
|
||||
[ -7.6561796932e+02, -4.2385971907e+03, -9.9501164076e+03,
|
||||
-3.3156729271e+04]]
|
||||
[[ 7.4000000000e+01, -2.1316282073e-13,
|
||||
4.7837837838e+02, -7.5943608473e+02],
|
||||
[ 3.7303493627e-14, -8.7837837838e+01,
|
||||
-1.4801314828e+02, -1.2714707125e+03],
|
||||
[ 1.2602837838e+03, 2.1571526662e+03,
|
||||
6.6989799420e+03, 1.5304076361e+04],
|
||||
[-7.6561796932e+02, -4.2385971907e+03,
|
||||
-9.9501164076e+03, -3.3156729271e+04]]
|
||||
)
|
||||
np.set_printoptions(precision=10)
|
||||
assert_array_almost_equal(wmu, ref)
|
||||
@@ -315,14 +315,10 @@ def test_weighted_moments():
|
||||
wm = regionprops(SAMPLE, intensity_image=INTENSITY_SAMPLE
|
||||
)[0].weighted_moments
|
||||
ref = np.array(
|
||||
[[ 7.4000000000e+01, 4.1000000000e+02, 2.7500000000e+03,
|
||||
1.9778000000e+04],
|
||||
[ 6.9900000000e+02, 3.7850000000e+03, 2.4855000000e+04,
|
||||
1.7500100000e+05],
|
||||
[ 7.8630000000e+03, 4.4063000000e+04, 2.9347700000e+05,
|
||||
2.0810510000e+06],
|
||||
[ 9.7317000000e+04, 5.7256700000e+05, 3.9007170000e+06,
|
||||
2.8078871000e+07]]
|
||||
[[7.4000000e+01, 4.1000000e+02, 2.7500000e+03, 1.9778000e+04],
|
||||
[6.9900000e+02, 3.7850000e+03, 2.4855000e+04, 1.7500100e+05],
|
||||
[7.8630000e+03, 4.4063000e+04, 2.9347700e+05, 2.0810510e+06],
|
||||
[9.7317000e+04, 5.7256700e+05, 3.9007170e+06, 2.8078871e+07]]
|
||||
)
|
||||
assert_array_almost_equal(wm, ref)
|
||||
|
||||
@@ -355,8 +351,10 @@ def test_pure_background():
|
||||
|
||||
def test_invalid():
|
||||
ps = regionprops(SAMPLE)
|
||||
|
||||
def get_intensity_image():
|
||||
ps[0].intensity_image
|
||||
|
||||
assert_raises(AttributeError, get_intensity_image)
|
||||
|
||||
|
||||
@@ -386,6 +384,37 @@ def test_iterate_all_props():
|
||||
assert len(p0) < len(p1)
|
||||
|
||||
|
||||
def test_cache():
|
||||
region = regionprops(SAMPLE)[0]
|
||||
f0 = region.filled_image
|
||||
region._label_image[:10] = 1
|
||||
f1 = region.filled_image
|
||||
|
||||
# Changed underlying image, but cache keeps result the same
|
||||
assert_array_equal(f0, f1)
|
||||
|
||||
# Now invalidate cache
|
||||
region._cache_active = False
|
||||
f1 = region.filled_image
|
||||
|
||||
assert np.any(f0 != f1)
|
||||
|
||||
|
||||
def test_docstrings_and_props():
|
||||
region = regionprops(SAMPLE)[0]
|
||||
|
||||
docs = _parse_docs()
|
||||
props = [m for m in dir(region) if not m.startswith('_')]
|
||||
|
||||
nr_docs_parsed = len(docs)
|
||||
nr_props = len(props)
|
||||
assert_equal(nr_docs_parsed, nr_props)
|
||||
|
||||
ds = docs['weighted_moments_normalized']
|
||||
assert 'iteration' not in ds
|
||||
assert len(ds.split('\n')) > 3
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
from numpy.testing import run_module_suite
|
||||
run_module_suite()
|
||||
|
||||
Reference in New Issue
Block a user