Fixed database typo and removed unnecessary class identifier.
This commit is contained in:
parent
00ad49a143
commit
45fb349a7d
5098 changed files with 952558 additions and 85 deletions
9
venv/Lib/site-packages/skimage/measure/tests/__init__.py
Normal file
9
venv/Lib/site-packages/skimage/measure/tests/__init__.py
Normal file
|
@ -0,0 +1,9 @@
|
|||
from ..._shared.testing import setup_test, teardown_test
|
||||
|
||||
|
||||
def setup():
|
||||
setup_test()
|
||||
|
||||
|
||||
def teardown():
|
||||
teardown_test()
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
117
venv/Lib/site-packages/skimage/measure/tests/test_block.py
Normal file
117
venv/Lib/site-packages/skimage/measure/tests/test_block.py
Normal file
|
@ -0,0 +1,117 @@
|
|||
import numpy as np
|
||||
from skimage.measure import block_reduce
|
||||
|
||||
from skimage._shared import testing
|
||||
from skimage._shared.testing import assert_equal
|
||||
|
||||
|
||||
def test_block_reduce_sum():
|
||||
image1 = np.arange(4 * 6).reshape(4, 6)
|
||||
out1 = block_reduce(image1, (2, 3))
|
||||
expected1 = np.array([[ 24, 42],
|
||||
[ 96, 114]])
|
||||
assert_equal(expected1, out1)
|
||||
|
||||
image2 = np.arange(5 * 8).reshape(5, 8)
|
||||
out2 = block_reduce(image2, (3, 3))
|
||||
expected2 = np.array([[ 81, 108, 87],
|
||||
[174, 192, 138]])
|
||||
assert_equal(expected2, out2)
|
||||
|
||||
|
||||
def test_block_reduce_mean():
|
||||
image1 = np.arange(4 * 6).reshape(4, 6)
|
||||
out1 = block_reduce(image1, (2, 3), func=np.mean)
|
||||
expected1 = np.array([[ 4., 7.],
|
||||
[ 16., 19.]])
|
||||
assert_equal(expected1, out1)
|
||||
|
||||
image2 = np.arange(5 * 8).reshape(5, 8)
|
||||
out2 = block_reduce(image2, (4, 5), func=np.mean)
|
||||
expected2 = np.array([[14. , 10.8],
|
||||
[ 8.5, 5.7]])
|
||||
assert_equal(expected2, out2)
|
||||
|
||||
|
||||
def test_block_reduce_median():
|
||||
image1 = np.arange(4 * 6).reshape(4, 6)
|
||||
out1 = block_reduce(image1, (2, 3), func=np.median)
|
||||
expected1 = np.array([[ 4., 7.],
|
||||
[ 16., 19.]])
|
||||
assert_equal(expected1, out1)
|
||||
|
||||
image2 = np.arange(5 * 8).reshape(5, 8)
|
||||
out2 = block_reduce(image2, (4, 5), func=np.median)
|
||||
expected2 = np.array([[ 14., 6.5],
|
||||
[ 0., 0. ]])
|
||||
assert_equal(expected2, out2)
|
||||
|
||||
image3 = np.array([[1, 5, 5, 5], [5, 5, 5, 1000]])
|
||||
out3 = block_reduce(image3, (2, 4), func=np.median)
|
||||
assert_equal(5, out3)
|
||||
|
||||
|
||||
def test_block_reduce_min():
|
||||
image1 = np.arange(4 * 6).reshape(4, 6)
|
||||
out1 = block_reduce(image1, (2, 3), func=np.min)
|
||||
expected1 = np.array([[ 0, 3],
|
||||
[12, 15]])
|
||||
assert_equal(expected1, out1)
|
||||
|
||||
image2 = np.arange(5 * 8).reshape(5, 8)
|
||||
out2 = block_reduce(image2, (4, 5), func=np.min)
|
||||
expected2 = np.array([[0, 0],
|
||||
[0, 0]])
|
||||
assert_equal(expected2, out2)
|
||||
|
||||
|
||||
def test_block_reduce_max():
|
||||
image1 = np.arange(4 * 6).reshape(4, 6)
|
||||
out1 = block_reduce(image1, (2, 3), func=np.max)
|
||||
expected1 = np.array([[ 8, 11],
|
||||
[20, 23]])
|
||||
assert_equal(expected1, out1)
|
||||
|
||||
image2 = np.arange(5 * 8).reshape(5, 8)
|
||||
out2 = block_reduce(image2, (4, 5), func=np.max)
|
||||
expected2 = np.array([[28, 31],
|
||||
[36, 39]])
|
||||
assert_equal(expected2, out2)
|
||||
|
||||
|
||||
def test_invalid_block_size():
|
||||
image = np.arange(4 * 6).reshape(4, 6)
|
||||
|
||||
with testing.raises(ValueError):
|
||||
block_reduce(image, [1, 2, 3])
|
||||
with testing.raises(ValueError):
|
||||
block_reduce(image, [1, 0.5])
|
||||
|
||||
|
||||
def test_func_kwargs_same_dtype():
|
||||
image = np.array([[97, 123, 173, 227],
|
||||
[217, 241, 221, 214],
|
||||
[211, 11, 170, 53],
|
||||
[214, 205, 101, 57]], dtype=np.uint8)
|
||||
|
||||
out = block_reduce(image, (2, 2), func=np.mean,
|
||||
func_kwargs={'dtype': np.uint8})
|
||||
expected = np.array([[41, 16], [32, 31]], dtype=np.uint8)
|
||||
|
||||
assert_equal(out, expected)
|
||||
assert out.dtype == expected.dtype
|
||||
|
||||
|
||||
def test_func_kwargs_different_dtype():
|
||||
image = np.array([[0.45745366, 0.67479345, 0.20949775, 0.3147348],
|
||||
[0.7209286, 0.88915504, 0.66153409, 0.07919526],
|
||||
[0.04640037, 0.54008495, 0.34664343, 0.56152301],
|
||||
[0.58085003, 0.80144708, 0.87844473, 0.29811511]],
|
||||
dtype=np.float64)
|
||||
|
||||
out = block_reduce(image, (2, 2), func=np.mean,
|
||||
func_kwargs={'dtype': np.float16})
|
||||
expected = np.array([[0.6855, 0.3164], [0.4922, 0.521]], dtype=np.float16)
|
||||
|
||||
assert_equal(out, expected)
|
||||
assert out.dtype == expected.dtype
|
16
venv/Lib/site-packages/skimage/measure/tests/test_entropy.py
Normal file
16
venv/Lib/site-packages/skimage/measure/tests/test_entropy.py
Normal file
|
@ -0,0 +1,16 @@
|
|||
import numpy as np
|
||||
from skimage.measure import shannon_entropy
|
||||
|
||||
from skimage._shared.testing import assert_almost_equal
|
||||
|
||||
|
||||
def test_shannon_ones():
|
||||
img = np.ones((10, 10))
|
||||
res = shannon_entropy(img, base=np.e)
|
||||
assert_almost_equal(res, 0.0)
|
||||
|
||||
|
||||
def test_shannon_all_unique():
|
||||
img = np.arange(64)
|
||||
res = shannon_entropy(img, base=2)
|
||||
assert_almost_equal(res, np.log(64) / np.log(2))
|
|
@ -0,0 +1,132 @@
|
|||
import numpy as np
|
||||
from skimage.measure import find_contours
|
||||
|
||||
from skimage._shared import testing
|
||||
from skimage._shared.testing import assert_array_equal
|
||||
from pytest import raises
|
||||
|
||||
|
||||
a = np.ones((8, 8), dtype=np.float32)
|
||||
a[1:-1, 1] = 0
|
||||
a[1, 1:-1] = 0
|
||||
|
||||
x, y = np.mgrid[-1:1:5j, -1:1:5j]
|
||||
r = np.sqrt(x**2 + y**2)
|
||||
|
||||
|
||||
def test_binary():
|
||||
ref = [[6. , 1.5],
|
||||
[5. , 1.5],
|
||||
[4. , 1.5],
|
||||
[3. , 1.5],
|
||||
[2. , 1.5],
|
||||
[1.5, 2. ],
|
||||
[1.5, 3. ],
|
||||
[1.5, 4. ],
|
||||
[1.5, 5. ],
|
||||
[1.5, 6. ],
|
||||
[1. , 6.5],
|
||||
[0.5, 6. ],
|
||||
[0.5, 5. ],
|
||||
[0.5, 4. ],
|
||||
[0.5, 3. ],
|
||||
[0.5, 2. ],
|
||||
[0.5, 1. ],
|
||||
[1. , 0.5],
|
||||
[2. , 0.5],
|
||||
[3. , 0.5],
|
||||
[4. , 0.5],
|
||||
[5. , 0.5],
|
||||
[6. , 0.5],
|
||||
[6.5, 1. ],
|
||||
[6. , 1.5]]
|
||||
|
||||
contours = find_contours(a, 0.5, positive_orientation='high')
|
||||
assert len(contours) == 1
|
||||
assert_array_equal(contours[0][::-1], ref)
|
||||
|
||||
|
||||
# target contour for mask tests
|
||||
mask_contour = [
|
||||
[6. , 0.5],
|
||||
[5. , 0.5],
|
||||
[4. , 0.5],
|
||||
[3. , 0.5],
|
||||
[2. , 0.5],
|
||||
[1. , 0.5],
|
||||
[0.5, 1. ],
|
||||
[0.5, 2. ],
|
||||
[0.5, 3. ],
|
||||
[0.5, 4. ],
|
||||
[0.5, 5. ],
|
||||
[0.5, 6. ],
|
||||
[1. , 6.5],
|
||||
[1.5, 6. ],
|
||||
[1.5, 5. ],
|
||||
[1.5, 4. ],
|
||||
[1.5, 3. ],
|
||||
[1.5, 2. ],
|
||||
[2. , 1.5],
|
||||
[3. , 1.5],
|
||||
[4. , 1.5],
|
||||
[5. , 1.5],
|
||||
[6. , 1.5],
|
||||
]
|
||||
|
||||
mask = np.ones((8, 8), dtype=bool)
|
||||
# Some missing data that should result in a hole in the contour:
|
||||
mask[7, 0:3] = False
|
||||
|
||||
|
||||
def test_nodata():
|
||||
# Test missing data via NaNs in input array
|
||||
b = np.copy(a)
|
||||
b[~mask] = np.nan
|
||||
contours = find_contours(b, 0.5, positive_orientation='high')
|
||||
assert len(contours) == 1
|
||||
assert_array_equal(contours[0], mask_contour)
|
||||
|
||||
|
||||
def test_mask():
|
||||
# Test missing data via explicit masking
|
||||
contours = find_contours(a, 0.5, positive_orientation='high', mask=mask)
|
||||
assert len(contours) == 1
|
||||
assert_array_equal(contours[0], mask_contour)
|
||||
|
||||
|
||||
def test_mask_shape():
|
||||
bad_mask = np.ones((8, 7), dtype=bool)
|
||||
with raises(ValueError, match='shape'):
|
||||
find_contours(a, 0, mask=bad_mask)
|
||||
|
||||
|
||||
def test_mask_dtype():
|
||||
bad_mask = np.ones((8,8), dtype=np.uint8)
|
||||
with raises(TypeError, match='binary'):
|
||||
find_contours(a, 0, mask=bad_mask)
|
||||
|
||||
|
||||
def test_float():
|
||||
contours = find_contours(r, 0.5)
|
||||
assert len(contours) == 1
|
||||
assert_array_equal(contours[0],
|
||||
[[ 2., 3.],
|
||||
[ 1., 2.],
|
||||
[ 2., 1.],
|
||||
[ 3., 2.],
|
||||
[ 2., 3.]])
|
||||
|
||||
|
||||
def test_memory_order():
|
||||
contours = find_contours(np.ascontiguousarray(r), 0.5)
|
||||
assert len(contours) == 1
|
||||
|
||||
contours = find_contours(np.asfortranarray(r), 0.5)
|
||||
assert len(contours) == 1
|
||||
|
||||
|
||||
def test_invalid_input():
|
||||
with testing.raises(ValueError):
|
||||
find_contours(r, 0.5, 'foo', 'bar')
|
||||
with testing.raises(ValueError):
|
||||
find_contours(r[..., None], 0.5)
|
388
venv/Lib/site-packages/skimage/measure/tests/test_fit.py
Normal file
388
venv/Lib/site-packages/skimage/measure/tests/test_fit.py
Normal file
|
@ -0,0 +1,388 @@
|
|||
import numpy as np
|
||||
from skimage.measure import LineModelND, CircleModel, EllipseModel, ransac
|
||||
from skimage.transform import AffineTransform
|
||||
from skimage.measure.fit import _dynamic_max_trials
|
||||
|
||||
from skimage._shared import testing
|
||||
from skimage._shared.testing import (assert_equal, assert_almost_equal,
|
||||
assert_array_less, xfail, arch32)
|
||||
|
||||
|
||||
def test_line_model_invalid_input():
|
||||
with testing.raises(ValueError):
|
||||
LineModelND().estimate(np.empty((1, 3)))
|
||||
|
||||
|
||||
def test_line_model_predict():
|
||||
model = LineModelND()
|
||||
model.params = ((0, 0), (1, 1))
|
||||
x = np.arange(-10, 10)
|
||||
y = model.predict_y(x)
|
||||
assert_almost_equal(x, model.predict_x(y))
|
||||
|
||||
|
||||
def test_line_model_nd_invalid_input():
|
||||
with testing.raises(ValueError):
|
||||
LineModelND().predict_x(np.zeros(1))
|
||||
|
||||
with testing.raises(ValueError):
|
||||
LineModelND().predict_y(np.zeros(1))
|
||||
|
||||
with testing.raises(ValueError):
|
||||
LineModelND().predict_x(np.zeros(1), np.zeros(1))
|
||||
|
||||
with testing.raises(ValueError):
|
||||
LineModelND().predict_y(np.zeros(1))
|
||||
|
||||
with testing.raises(ValueError):
|
||||
LineModelND().predict_y(np.zeros(1), np.zeros(1))
|
||||
|
||||
with testing.raises(ValueError):
|
||||
LineModelND().estimate(np.empty((1, 3)))
|
||||
|
||||
with testing.raises(ValueError):
|
||||
LineModelND().residuals(np.empty((1, 3)))
|
||||
|
||||
data = np.empty((1, 2))
|
||||
with testing.raises(ValueError):
|
||||
LineModelND().estimate(data)
|
||||
|
||||
|
||||
def test_line_model_nd_predict():
|
||||
model = LineModelND()
|
||||
model.params = (np.array([0, 0]), np.array([0.2, 0.8]))
|
||||
x = np.arange(-10, 10)
|
||||
y = model.predict_y(x)
|
||||
assert_almost_equal(x, model.predict_x(y))
|
||||
|
||||
|
||||
def test_line_model_nd_estimate():
|
||||
# generate original data without noise
|
||||
model0 = LineModelND()
|
||||
model0.params = (np.array([0, 0, 0], dtype='float'),
|
||||
np.array([1, 1, 1], dtype='float')/np.sqrt(3))
|
||||
# we scale the unit vector with a factor 10 when generating points on the
|
||||
# line in order to compensate for the scale of the random noise
|
||||
data0 = (model0.params[0] +
|
||||
10 * np.arange(-100, 100)[..., np.newaxis] * model0.params[1])
|
||||
|
||||
# add gaussian noise to data
|
||||
random_state = np.random.RandomState(1234)
|
||||
data = data0 + random_state.normal(size=data0.shape)
|
||||
|
||||
# estimate parameters of noisy data
|
||||
model_est = LineModelND()
|
||||
model_est.estimate(data)
|
||||
# assert_almost_equal(model_est.residuals(data0), np.zeros(len(data)), 1)
|
||||
|
||||
# test whether estimated parameters are correct
|
||||
# we use the following geometric property: two aligned vectors have
|
||||
# a cross-product equal to zero
|
||||
# test if direction vectors are aligned
|
||||
assert_almost_equal(np.linalg.norm(np.cross(model0.params[1],
|
||||
model_est.params[1])), 0, 1)
|
||||
# test if origins are aligned with the direction
|
||||
a = model_est.params[0] - model0.params[0]
|
||||
if np.linalg.norm(a) > 0:
|
||||
a /= np.linalg.norm(a)
|
||||
assert_almost_equal(np.linalg.norm(np.cross(model0.params[1], a)), 0, 1)
|
||||
|
||||
|
||||
def test_line_model_nd_residuals():
|
||||
model = LineModelND()
|
||||
model.params = (np.array([0, 0, 0]), np.array([0, 0, 1]))
|
||||
assert_equal(abs(model.residuals(np.array([[0, 0, 0]]))), 0)
|
||||
assert_equal(abs(model.residuals(np.array([[0, 0, 1]]))), 0)
|
||||
assert_equal(abs(model.residuals(np.array([[10, 0, 0]]))), 10)
|
||||
# test params argument in model.rediduals
|
||||
data = np.array([[10, 0, 0]])
|
||||
params = (np.array([0, 0, 0]), np.array([2, 0, 0]))
|
||||
assert_equal(abs(model.residuals(data, params=params)), 30)
|
||||
|
||||
|
||||
def test_line_modelND_under_determined():
|
||||
data = np.empty((1, 3))
|
||||
with testing.raises(ValueError):
|
||||
LineModelND().estimate(data)
|
||||
|
||||
|
||||
def test_circle_model_invalid_input():
|
||||
with testing.raises(ValueError):
|
||||
CircleModel().estimate(np.empty((5, 3)))
|
||||
|
||||
|
||||
def test_circle_model_predict():
|
||||
model = CircleModel()
|
||||
r = 5
|
||||
model.params = (0, 0, r)
|
||||
t = np.arange(0, 2 * np.pi, np.pi / 2)
|
||||
|
||||
xy = np.array(((5, 0), (0, 5), (-5, 0), (0, -5)))
|
||||
assert_almost_equal(xy, model.predict_xy(t))
|
||||
|
||||
|
||||
def test_circle_model_estimate():
|
||||
# generate original data without noise
|
||||
model0 = CircleModel()
|
||||
model0.params = (10, 12, 3)
|
||||
t = np.linspace(0, 2 * np.pi, 1000)
|
||||
data0 = model0.predict_xy(t)
|
||||
|
||||
# add gaussian noise to data
|
||||
random_state = np.random.RandomState(1234)
|
||||
data = data0 + random_state.normal(size=data0.shape)
|
||||
|
||||
# estimate parameters of noisy data
|
||||
model_est = CircleModel()
|
||||
model_est.estimate(data)
|
||||
|
||||
# test whether estimated parameters almost equal original parameters
|
||||
assert_almost_equal(model0.params, model_est.params, 0)
|
||||
|
||||
|
||||
def test_circle_model_residuals():
|
||||
model = CircleModel()
|
||||
model.params = (0, 0, 5)
|
||||
assert_almost_equal(abs(model.residuals(np.array([[5, 0]]))), 0)
|
||||
assert_almost_equal(abs(model.residuals(np.array([[6, 6]]))),
|
||||
np.sqrt(2 * 6**2) - 5)
|
||||
assert_almost_equal(abs(model.residuals(np.array([[10, 0]]))), 5)
|
||||
|
||||
|
||||
def test_ellipse_model_invalid_input():
|
||||
with testing.raises(ValueError):
|
||||
EllipseModel().estimate(np.empty((5, 3)))
|
||||
|
||||
|
||||
def test_ellipse_model_predict():
|
||||
model = EllipseModel()
|
||||
model.params = (0, 0, 5, 10, 0)
|
||||
t = np.arange(0, 2 * np.pi, np.pi / 2)
|
||||
|
||||
xy = np.array(((5, 0), (0, 10), (-5, 0), (0, -10)))
|
||||
assert_almost_equal(xy, model.predict_xy(t))
|
||||
|
||||
|
||||
def test_ellipse_model_estimate():
|
||||
for angle in range(0, 180, 15):
|
||||
rad = np.deg2rad(angle)
|
||||
# generate original data without noise
|
||||
model0 = EllipseModel()
|
||||
model0.params = (10, 20, 15, 25, rad)
|
||||
t = np.linspace(0, 2 * np.pi, 100)
|
||||
data0 = model0.predict_xy(t)
|
||||
|
||||
# add gaussian noise to data
|
||||
random_state = np.random.RandomState(1234)
|
||||
data = data0 + random_state.normal(size=data0.shape)
|
||||
|
||||
# estimate parameters of noisy data
|
||||
model_est = EllipseModel()
|
||||
model_est.estimate(data)
|
||||
|
||||
# test whether estimated parameters almost equal original parameters
|
||||
assert_almost_equal(model0.params[:2], model_est.params[:2], 0)
|
||||
res = model_est.residuals(data0)
|
||||
assert_array_less(res, np.ones(res.shape))
|
||||
|
||||
|
||||
def test_ellipse_model_estimate_from_data():
|
||||
data = np.array([
|
||||
[264, 854], [265, 875], [268, 863], [270, 857], [275, 905], [285, 915],
|
||||
[305, 925], [324, 934], [335, 764], [336, 915], [345, 925], [345, 945],
|
||||
[354, 933], [355, 745], [364, 936], [365, 754], [375, 745], [375, 735],
|
||||
[385, 736], [395, 735], [394, 935], [405, 727], [415, 736], [415, 727],
|
||||
[425, 727], [426, 929], [435, 735], [444, 933], [445, 735], [455, 724],
|
||||
[465, 934], [465, 735], [475, 908], [475, 726], [485, 753], [485, 728],
|
||||
[492, 762], [495, 745], [491, 910], [493, 909], [499, 904], [505, 905],
|
||||
[504, 747], [515, 743], [516, 752], [524, 855], [525, 844], [525, 885],
|
||||
[533, 845], [533, 873], [535, 883], [545, 874], [543, 864], [553, 865],
|
||||
[553, 845], [554, 825], [554, 835], [563, 845], [565, 826], [563, 855],
|
||||
[563, 795], [565, 735], [573, 778], [572, 815], [574, 804], [575, 665],
|
||||
[575, 685], [574, 705], [574, 745], [575, 875], [572, 732], [582, 795],
|
||||
[579, 709], [583, 805], [583, 854], [586, 755], [584, 824], [585, 655],
|
||||
[581, 718], [586, 844], [585, 915], [587, 905], [594, 824], [593, 855],
|
||||
[590, 891], [594, 776], [596, 767], [593, 763], [603, 785], [604, 775],
|
||||
[603, 885], [605, 753], [605, 655], [606, 935], [603, 761], [613, 802],
|
||||
[613, 945], [613, 965], [615, 693], [617, 665], [623, 962], [624, 972],
|
||||
[625, 995], [633, 673], [633, 965], [633, 683], [633, 692], [633, 954],
|
||||
[634, 1016], [635, 664], [641, 804], [637, 999], [641, 956], [643, 946],
|
||||
[643, 926], [644, 975], [643, 655], [646, 705], [651, 664], [651, 984],
|
||||
[647, 665], [651, 715], [651, 725], [651, 734], [647, 809], [651, 825],
|
||||
[651, 873], [647, 900], [652, 917], [651, 944], [652, 742], [648, 811],
|
||||
[651, 994], [652, 783], [650, 911], [654, 879]])
|
||||
|
||||
# estimate parameters of real data
|
||||
model = EllipseModel()
|
||||
model.estimate(data)
|
||||
|
||||
# test whether estimated parameters are smaller then 1000, so means stable
|
||||
assert_array_less(np.abs(model.params[:4]), np.array([2e3] * 4))
|
||||
|
||||
|
||||
@xfail(condition=arch32,
|
||||
reason=('Known test failure on 32-bit platforms. See links for '
|
||||
'details: '
|
||||
'https://github.com/scikit-image/scikit-image/issues/3091 '
|
||||
'https://github.com/scikit-image/scikit-image/issues/2670'))
|
||||
def test_ellipse_model_estimate_failers():
|
||||
# estimate parameters of real data
|
||||
model = EllipseModel()
|
||||
assert not model.estimate(np.ones((5, 2)))
|
||||
assert not model.estimate(np.array([[50, 80], [51, 81], [52, 80]]))
|
||||
|
||||
|
||||
def test_ellipse_model_residuals():
|
||||
model = EllipseModel()
|
||||
# vertical line through origin
|
||||
model.params = (0, 0, 10, 5, 0)
|
||||
assert_almost_equal(abs(model.residuals(np.array([[10, 0]]))), 0)
|
||||
assert_almost_equal(abs(model.residuals(np.array([[0, 5]]))), 0)
|
||||
assert_almost_equal(abs(model.residuals(np.array([[0, 10]]))), 5)
|
||||
|
||||
|
||||
def test_ransac_shape():
|
||||
# generate original data without noise
|
||||
model0 = CircleModel()
|
||||
model0.params = (10, 12, 3)
|
||||
t = np.linspace(0, 2 * np.pi, 1000)
|
||||
data0 = model0.predict_xy(t)
|
||||
|
||||
# add some faulty data
|
||||
outliers = (10, 30, 200)
|
||||
data0[outliers[0], :] = (1000, 1000)
|
||||
data0[outliers[1], :] = (-50, 50)
|
||||
data0[outliers[2], :] = (-100, -10)
|
||||
|
||||
# estimate parameters of corrupted data
|
||||
model_est, inliers = ransac(data0, CircleModel, 3, 5, random_state=1)
|
||||
|
||||
# test whether estimated parameters equal original parameters
|
||||
assert_almost_equal(model0.params, model_est.params)
|
||||
for outlier in outliers:
|
||||
assert outlier not in inliers
|
||||
|
||||
|
||||
def test_ransac_geometric():
|
||||
random_state = np.random.RandomState(1)
|
||||
|
||||
# generate original data without noise
|
||||
src = 100 * random_state.random_sample((50, 2))
|
||||
model0 = AffineTransform(scale=(0.5, 0.3), rotation=1,
|
||||
translation=(10, 20))
|
||||
dst = model0(src)
|
||||
|
||||
# add some faulty data
|
||||
outliers = (0, 5, 20)
|
||||
dst[outliers[0]] = (10000, 10000)
|
||||
dst[outliers[1]] = (-100, 100)
|
||||
dst[outliers[2]] = (50, 50)
|
||||
|
||||
# estimate parameters of corrupted data
|
||||
model_est, inliers = ransac((src, dst), AffineTransform, 2, 20,
|
||||
random_state=random_state)
|
||||
|
||||
# test whether estimated parameters equal original parameters
|
||||
assert_almost_equal(model0.params, model_est.params)
|
||||
assert np.all(np.nonzero(inliers == False)[0] == outliers)
|
||||
|
||||
|
||||
def test_ransac_is_data_valid():
|
||||
def is_data_valid(data):
|
||||
return data.shape[0] > 2
|
||||
model, inliers = ransac(np.empty((10, 2)), LineModelND, 2, np.inf,
|
||||
is_data_valid=is_data_valid, random_state=1)
|
||||
assert_equal(model, None)
|
||||
assert_equal(inliers, None)
|
||||
|
||||
|
||||
def test_ransac_is_model_valid():
|
||||
def is_model_valid(model, data):
|
||||
return False
|
||||
model, inliers = ransac(np.empty((10, 2)), LineModelND, 2, np.inf,
|
||||
is_model_valid=is_model_valid, random_state=1)
|
||||
assert_equal(model, None)
|
||||
assert_equal(inliers, None)
|
||||
|
||||
|
||||
def test_ransac_dynamic_max_trials():
|
||||
# Numbers hand-calculated and confirmed on page 119 (Table 4.3) in
|
||||
# Hartley, R.~I. and Zisserman, A., 2004,
|
||||
# Multiple View Geometry in Computer Vision, Second Edition,
|
||||
# Cambridge University Press, ISBN: 0521540518
|
||||
|
||||
# e = 0%, min_samples = X
|
||||
assert_equal(_dynamic_max_trials(100, 100, 2, 0.99), 1)
|
||||
|
||||
# e = 5%, min_samples = 2
|
||||
assert_equal(_dynamic_max_trials(95, 100, 2, 0.99), 2)
|
||||
# e = 10%, min_samples = 2
|
||||
assert_equal(_dynamic_max_trials(90, 100, 2, 0.99), 3)
|
||||
# e = 30%, min_samples = 2
|
||||
assert_equal(_dynamic_max_trials(70, 100, 2, 0.99), 7)
|
||||
# e = 50%, min_samples = 2
|
||||
assert_equal(_dynamic_max_trials(50, 100, 2, 0.99), 17)
|
||||
|
||||
# e = 5%, min_samples = 8
|
||||
assert_equal(_dynamic_max_trials(95, 100, 8, 0.99), 5)
|
||||
# e = 10%, min_samples = 8
|
||||
assert_equal(_dynamic_max_trials(90, 100, 8, 0.99), 9)
|
||||
# e = 30%, min_samples = 8
|
||||
assert_equal(_dynamic_max_trials(70, 100, 8, 0.99), 78)
|
||||
# e = 50%, min_samples = 8
|
||||
assert_equal(_dynamic_max_trials(50, 100, 8, 0.99), 1177)
|
||||
|
||||
# e = 0%, min_samples = 5
|
||||
assert_equal(_dynamic_max_trials(1, 100, 5, 0), 0)
|
||||
assert_equal(_dynamic_max_trials(1, 100, 5, 1), np.inf)
|
||||
|
||||
|
||||
def test_ransac_invalid_input():
|
||||
# `residual_threshold` must be greater than zero
|
||||
with testing.raises(ValueError):
|
||||
ransac(np.zeros((10, 2)), None, min_samples=2,
|
||||
residual_threshold=-0.5)
|
||||
# "`max_trials` must be greater than zero"
|
||||
with testing.raises(ValueError):
|
||||
ransac(np.zeros((10, 2)), None, min_samples=2,
|
||||
residual_threshold=0, max_trials=-1)
|
||||
# `stop_probability` must be in range (0, 1)
|
||||
with testing.raises(ValueError):
|
||||
ransac(np.zeros((10, 2)), None, min_samples=2,
|
||||
residual_threshold=0, stop_probability=-1)
|
||||
# `stop_probability` must be in range (0, 1)
|
||||
with testing.raises(ValueError):
|
||||
ransac(np.zeros((10, 2)), None, min_samples=2,
|
||||
residual_threshold=0, stop_probability=1.01)
|
||||
# `min_samples` as ratio must be in range (0, nb)
|
||||
with testing.raises(ValueError):
|
||||
ransac(np.zeros((10, 2)), None, min_samples=0,
|
||||
residual_threshold=0)
|
||||
# `min_samples` as ratio must be in range (0, nb)
|
||||
with testing.raises(ValueError):
|
||||
ransac(np.zeros((10, 2)), None, min_samples=10,
|
||||
residual_threshold=0)
|
||||
# `min_samples` must be greater than zero
|
||||
with testing.raises(ValueError):
|
||||
ransac(np.zeros((10, 2)), None, min_samples=-1,
|
||||
residual_threshold=0)
|
||||
|
||||
|
||||
def test_ransac_sample_duplicates():
|
||||
class DummyModel(object):
|
||||
|
||||
"""Dummy model to check for duplicates."""
|
||||
|
||||
def estimate(self, data):
|
||||
# Assert that all data points are unique.
|
||||
assert_equal(np.unique(data).size, data.size)
|
||||
return True
|
||||
|
||||
def residuals(self, data):
|
||||
return np.ones(len(data), dtype=np.double)
|
||||
|
||||
# Create dataset with four unique points. Force 10 iterations
|
||||
# and check that there are no duplicated data points.
|
||||
data = np.arange(4)
|
||||
ransac(data, DummyModel, min_samples=3, residual_threshold=0.0,
|
||||
max_trials=10)
|
|
@ -0,0 +1,180 @@
|
|||
import numpy as np
|
||||
from skimage.draw import ellipsoid, ellipsoid_stats
|
||||
from skimage.measure import marching_cubes, mesh_surface_area
|
||||
from skimage._shared import testing
|
||||
from skimage._shared.testing import assert_array_equal
|
||||
import pytest
|
||||
|
||||
def test_marching_cubes_isotropic():
|
||||
ellipsoid_isotropic = ellipsoid(6, 10, 16, levelset=True)
|
||||
_, surf = ellipsoid_stats(6, 10, 16)
|
||||
|
||||
# Classic
|
||||
verts, faces = marching_cubes(ellipsoid_isotropic, 0., method='_lorensen')
|
||||
surf_calc = mesh_surface_area(verts, faces)
|
||||
# Test within 1% tolerance for isotropic. Will always underestimate.
|
||||
assert surf > surf_calc and surf_calc > surf * 0.99
|
||||
|
||||
# Lewiner
|
||||
verts, faces = marching_cubes(ellipsoid_isotropic, 0.)[:2]
|
||||
surf_calc = mesh_surface_area(verts, faces)
|
||||
# Test within 1% tolerance for isotropic. Will always underestimate.
|
||||
assert surf > surf_calc and surf_calc > surf * 0.99
|
||||
|
||||
|
||||
def test_marching_cubes_anisotropic():
|
||||
# test spacing as numpy array (and not just tuple)
|
||||
spacing = np.array([1., 10 / 6., 16 / 6.])
|
||||
ellipsoid_anisotropic = ellipsoid(6, 10, 16, spacing=spacing,
|
||||
levelset=True)
|
||||
_, surf = ellipsoid_stats(6, 10, 16)
|
||||
|
||||
# Classic
|
||||
verts, faces = marching_cubes(ellipsoid_anisotropic, 0.,
|
||||
spacing=spacing, method='_lorensen')
|
||||
surf_calc = mesh_surface_area(verts, faces)
|
||||
# Test within 1.5% tolerance for anisotropic. Will always underestimate.
|
||||
assert surf > surf_calc and surf_calc > surf * 0.985
|
||||
|
||||
# Lewiner
|
||||
verts, faces = marching_cubes(ellipsoid_anisotropic, 0.,
|
||||
spacing=spacing)[:2]
|
||||
surf_calc = mesh_surface_area(verts, faces)
|
||||
# Test within 1.5% tolerance for anisotropic. Will always underestimate.
|
||||
assert surf > surf_calc and surf_calc > surf * 0.985
|
||||
|
||||
# Test marching cube with mask
|
||||
with pytest.raises(ValueError):
|
||||
verts, faces = marching_cubes(
|
||||
ellipsoid_anisotropic, 0., spacing=spacing,
|
||||
mask=np.array([]))[:2]
|
||||
|
||||
# Test spacing together with allow_degenerate=False
|
||||
marching_cubes(ellipsoid_anisotropic, 0, spacing=spacing,
|
||||
allow_degenerate=False)
|
||||
|
||||
|
||||
def test_invalid_input():
|
||||
# Classic
|
||||
with testing.raises(ValueError):
|
||||
marching_cubes(np.zeros((2, 2, 1)), 0, method='_lorensen')
|
||||
with testing.raises(ValueError):
|
||||
marching_cubes(np.zeros((2, 2, 1)), 1, method='_lorensen')
|
||||
with testing.raises(ValueError):
|
||||
marching_cubes(np.ones((3, 3, 3)), 1, spacing=(1, 2), method='_lorensen')
|
||||
with testing.raises(ValueError):
|
||||
marching_cubes(np.zeros((20, 20)), 0, method='_lorensen')
|
||||
|
||||
# Lewiner
|
||||
with testing.raises(ValueError):
|
||||
marching_cubes(np.zeros((2, 2, 1)), 0)
|
||||
with testing.raises(ValueError):
|
||||
marching_cubes(np.zeros((2, 2, 1)), 1)
|
||||
with testing.raises(ValueError):
|
||||
marching_cubes(np.ones((3, 3, 3)), 1, spacing=(1, 2))
|
||||
with testing.raises(ValueError):
|
||||
marching_cubes(np.zeros((20, 20)), 0)
|
||||
|
||||
|
||||
def test_both_algs_same_result_ellipse():
|
||||
# Performing this test on data that does not have ambiguities
|
||||
|
||||
sphere_small = ellipsoid(1, 1, 1, levelset=True)
|
||||
|
||||
vertices1, faces1 = marching_cubes(sphere_small, 0, method='_lorensen')[:2]
|
||||
vertices2, faces2 = marching_cubes(sphere_small, 0,
|
||||
allow_degenerate=False)[:2]
|
||||
vertices3, faces3 = marching_cubes(sphere_small, 0,
|
||||
allow_degenerate=False,
|
||||
method='lorensen')[:2]
|
||||
|
||||
# Order is different, best we can do is test equal shape and same
|
||||
# vertices present
|
||||
assert _same_mesh(vertices1, faces1, vertices2, faces2)
|
||||
assert _same_mesh(vertices1, faces1, vertices3, faces3)
|
||||
|
||||
|
||||
def _same_mesh(vertices1, faces1, vertices2, faces2, tol=1e-10):
|
||||
""" Compare two meshes, using a certain tolerance and invariant to
|
||||
the order of the faces.
|
||||
"""
|
||||
# Unwind vertices
|
||||
triangles1 = vertices1[np.array(faces1)]
|
||||
triangles2 = vertices2[np.array(faces2)]
|
||||
# Sort vertices within each triangle
|
||||
triang1 = [np.concatenate(sorted(t, key=lambda x:tuple(x)))
|
||||
for t in triangles1]
|
||||
triang2 = [np.concatenate(sorted(t, key=lambda x:tuple(x)))
|
||||
for t in triangles2]
|
||||
# Sort the resulting 9-element "tuples"
|
||||
triang1 = np.array(sorted([tuple(x) for x in triang1]))
|
||||
triang2 = np.array(sorted([tuple(x) for x in triang2]))
|
||||
return (triang1.shape == triang2.shape and
|
||||
np.allclose(triang1, triang2, 0, tol))
|
||||
|
||||
|
||||
def test_both_algs_same_result_donut():
|
||||
# Performing this test on data that does not have ambiguities
|
||||
n = 48
|
||||
a, b = 2.5/n, -1.25
|
||||
|
||||
vol = np.empty((n, n, n), 'float32')
|
||||
for iz in range(vol.shape[0]):
|
||||
for iy in range(vol.shape[1]):
|
||||
for ix in range(vol.shape[2]):
|
||||
# Double-torii formula by Thomas Lewiner
|
||||
z, y, x = float(iz)*a+b, float(iy)*a+b, float(ix)*a+b
|
||||
vol[iz,iy,ix] = ( (
|
||||
(8*x)**2 + (8*y-2)**2 + (8*z)**2 + 16 - 1.85*1.85 ) * ( (8*x)**2 +
|
||||
(8*y-2)**2 + (8*z)**2 + 16 - 1.85*1.85 ) - 64 * ( (8*x)**2 + (8*y-2)**2 )
|
||||
) * ( ( (8*x)**2 + ((8*y-2)+4)*((8*y-2)+4) + (8*z)**2 + 16 - 1.85*1.85 )
|
||||
* ( (8*x)**2 + ((8*y-2)+4)*((8*y-2)+4) + (8*z)**2 + 16 - 1.85*1.85 ) -
|
||||
64 * ( ((8*y-2)+4)*((8*y-2)+4) + (8*z)**2
|
||||
) ) + 1025
|
||||
|
||||
vertices1, faces1 = marching_cubes(vol, 0, method='_lorensen')[:2]
|
||||
vertices2, faces2 = marching_cubes(vol, 0)[:2]
|
||||
vertices3, faces3 = marching_cubes(vol, 0, method='lorensen')[:2]
|
||||
|
||||
# Old and new alg are different
|
||||
assert not _same_mesh(vertices1, faces1, vertices2, faces2)
|
||||
# New classic and new Lewiner are different
|
||||
assert not _same_mesh(vertices2, faces2, vertices3, faces3)
|
||||
# Would have been nice if old and new classic would have been the same
|
||||
# assert _same_mesh(vertices1, faces1, vertices3, faces3, 5)
|
||||
|
||||
|
||||
def test_masked_marching_cubes():
|
||||
|
||||
ellipsoid_scalar = ellipsoid(6, 10, 16, levelset=True)
|
||||
mask = np.ones_like(ellipsoid_scalar, dtype=bool)
|
||||
mask[:10, :, :] = False
|
||||
mask[:, :, 20:] = False
|
||||
ver, faces, _, _ = marching_cubes(ellipsoid_scalar, 0, mask=mask)
|
||||
area = mesh_surface_area(ver, faces)
|
||||
|
||||
np.testing.assert_allclose(area, 299.56878662109375, rtol=.01)
|
||||
|
||||
|
||||
def test_masked_marching_cubes_empty():
|
||||
ellipsoid_scalar = ellipsoid(6, 10, 16, levelset=True)
|
||||
mask = np.array([])
|
||||
with pytest.raises(ValueError):
|
||||
_ = marching_cubes(ellipsoid_scalar, 0, mask=mask)
|
||||
|
||||
|
||||
def test_masked_marching_cubes_old_lewiner():
|
||||
ellipsoid_scalar = ellipsoid(6, 10, 16, levelset=True)
|
||||
mask = np.array([])
|
||||
with pytest.raises(NotImplementedError):
|
||||
_ = marching_cubes(ellipsoid_scalar, 0, mask=mask, method='_lorensen')
|
||||
|
||||
|
||||
def test_masked_marching_cubes_all_true():
|
||||
ellipsoid_scalar = ellipsoid(6, 10, 16, levelset=True)
|
||||
mask = np.ones_like(ellipsoid_scalar, dtype=bool)
|
||||
ver_m, faces_m, _, _ = marching_cubes(ellipsoid_scalar, 0, mask=mask)
|
||||
ver, faces, _, _ = marching_cubes(ellipsoid_scalar, 0, mask=mask)
|
||||
np.testing.assert_allclose(ver_m, ver, rtol=.00001)
|
||||
np.testing.assert_allclose(faces_m, faces, rtol=.00001)
|
||||
|
187
venv/Lib/site-packages/skimage/measure/tests/test_moments.py
Normal file
187
venv/Lib/site-packages/skimage/measure/tests/test_moments.py
Normal file
|
@ -0,0 +1,187 @@
|
|||
import numpy as np
|
||||
from scipy import ndimage as ndi
|
||||
from skimage import draw
|
||||
from skimage.measure import (moments, moments_central, moments_coords,
|
||||
moments_coords_central, moments_normalized,
|
||||
moments_hu, centroid, inertia_tensor,
|
||||
inertia_tensor_eigvals)
|
||||
|
||||
from skimage._shared import testing
|
||||
from skimage._shared.testing import (assert_equal, assert_almost_equal,
|
||||
assert_allclose)
|
||||
from skimage._shared._warnings import expected_warnings
|
||||
|
||||
|
||||
def test_moments():
|
||||
image = np.zeros((20, 20), dtype=np.double)
|
||||
image[14, 14] = 1
|
||||
image[15, 15] = 1
|
||||
image[14, 15] = 0.5
|
||||
image[15, 14] = 0.5
|
||||
m = moments(image)
|
||||
assert_equal(m[0, 0], 3)
|
||||
assert_almost_equal(m[1, 0] / m[0, 0], 14.5)
|
||||
assert_almost_equal(m[0, 1] / m[0, 0], 14.5)
|
||||
|
||||
|
||||
def test_moments_central():
|
||||
image = np.zeros((20, 20), dtype=np.double)
|
||||
image[14, 14] = 1
|
||||
image[15, 15] = 1
|
||||
image[14, 15] = 0.5
|
||||
image[15, 14] = 0.5
|
||||
mu = moments_central(image, (14.5, 14.5))
|
||||
|
||||
# check for proper centroid computation
|
||||
mu_calc_centroid = moments_central(image)
|
||||
assert_equal(mu, mu_calc_centroid)
|
||||
|
||||
# shift image by dx=2, dy=2
|
||||
image2 = np.zeros((20, 20), dtype=np.double)
|
||||
image2[16, 16] = 1
|
||||
image2[17, 17] = 1
|
||||
image2[16, 17] = 0.5
|
||||
image2[17, 16] = 0.5
|
||||
mu2 = moments_central(image2, (14.5 + 2, 14.5 + 2))
|
||||
# central moments must be translation invariant
|
||||
assert_equal(mu, mu2)
|
||||
|
||||
|
||||
def test_moments_coords():
|
||||
image = np.zeros((20, 20), dtype=np.double)
|
||||
image[13:17, 13:17] = 1
|
||||
mu_image = moments(image)
|
||||
|
||||
coords = np.array([[r, c] for r in range(13, 17)
|
||||
for c in range(13, 17)], dtype=np.double)
|
||||
mu_coords = moments_coords(coords)
|
||||
assert_almost_equal(mu_coords, mu_image)
|
||||
|
||||
|
||||
def test_moments_central_coords():
|
||||
image = np.zeros((20, 20), dtype=np.double)
|
||||
image[13:17, 13:17] = 1
|
||||
mu_image = moments_central(image, (14.5, 14.5))
|
||||
|
||||
coords = np.array([[r, c] for r in range(13, 17)
|
||||
for c in range(13, 17)], dtype=np.double)
|
||||
mu_coords = moments_coords_central(coords, (14.5, 14.5))
|
||||
assert_almost_equal(mu_coords, mu_image)
|
||||
|
||||
# ensure that center is being calculated normally
|
||||
mu_coords_calc_centroid = moments_coords_central(coords)
|
||||
assert_almost_equal(mu_coords_calc_centroid, mu_coords)
|
||||
|
||||
# shift image by dx=3 dy=3
|
||||
image = np.zeros((20, 20), dtype=np.double)
|
||||
image[16:20, 16:20] = 1
|
||||
mu_image = moments_central(image, (14.5, 14.5))
|
||||
|
||||
coords = np.array([[r, c] for r in range(16, 20)
|
||||
for c in range(16, 20)], dtype=np.double)
|
||||
mu_coords = moments_coords_central(coords, (14.5, 14.5))
|
||||
assert_almost_equal(mu_coords, mu_image)
|
||||
|
||||
|
||||
def test_moments_normalized():
|
||||
image = np.zeros((20, 20), dtype=np.double)
|
||||
image[13:17, 13:17] = 1
|
||||
mu = moments_central(image, (14.5, 14.5))
|
||||
nu = moments_normalized(mu)
|
||||
# shift image by dx=-3, dy=-3 and scale by 0.5
|
||||
image2 = np.zeros((20, 20), dtype=np.double)
|
||||
image2[11:13, 11:13] = 1
|
||||
mu2 = moments_central(image2, (11.5, 11.5))
|
||||
nu2 = moments_normalized(mu2)
|
||||
# central moments must be translation and scale invariant
|
||||
assert_almost_equal(nu, nu2, decimal=1)
|
||||
|
||||
|
||||
def test_moments_normalized_3d():
|
||||
image = draw.ellipsoid(1, 1, 10)
|
||||
mu_image = moments_central(image)
|
||||
nu = moments_normalized(mu_image)
|
||||
assert nu[0, 0, 2] > nu[0, 2, 0]
|
||||
assert_almost_equal(nu[0, 2, 0], nu[2, 0, 0])
|
||||
|
||||
coords = np.where(image)
|
||||
mu_coords = moments_coords_central(coords)
|
||||
assert_almost_equal(mu_coords, mu_image)
|
||||
|
||||
|
||||
def test_moments_normalized_invalid():
|
||||
with testing.raises(ValueError):
|
||||
moments_normalized(np.zeros((3, 3)), 3)
|
||||
with testing.raises(ValueError):
|
||||
moments_normalized(np.zeros((3, 3)), 4)
|
||||
|
||||
|
||||
def test_moments_hu():
|
||||
image = np.zeros((20, 20), dtype=np.double)
|
||||
image[13:15, 13:17] = 1
|
||||
mu = moments_central(image, (13.5, 14.5))
|
||||
nu = moments_normalized(mu)
|
||||
hu = moments_hu(nu)
|
||||
# shift image by dx=2, dy=3, scale by 0.5 and rotate by 90deg
|
||||
image2 = np.zeros((20, 20), dtype=np.double)
|
||||
image2[11, 11:13] = 1
|
||||
image2 = image2.T
|
||||
mu2 = moments_central(image2, (11.5, 11))
|
||||
nu2 = moments_normalized(mu2)
|
||||
hu2 = moments_hu(nu2)
|
||||
# central moments must be translation and scale invariant
|
||||
assert_almost_equal(hu, hu2, decimal=1)
|
||||
|
||||
|
||||
def test_centroid():
|
||||
image = np.zeros((20, 20), dtype=np.double)
|
||||
image[14, 14:16] = 1
|
||||
image[15, 14:16] = 1/3
|
||||
image_centroid = centroid(image)
|
||||
assert_allclose(image_centroid, (14.25, 14.5))
|
||||
|
||||
|
||||
def test_inertia_tensor_2d():
|
||||
image = np.zeros((40, 40))
|
||||
image[15:25, 5:35] = 1 # big horizontal rectangle (aligned with axis 1)
|
||||
T = inertia_tensor(image)
|
||||
assert T[0, 0] > T[1, 1]
|
||||
np.testing.assert_allclose(T[0, 1], 0)
|
||||
v0, v1 = inertia_tensor_eigvals(image, T=T)
|
||||
np.testing.assert_allclose(np.sqrt(v0/v1), 3, rtol=0.01, atol=0.05)
|
||||
|
||||
|
||||
def test_inertia_tensor_3d():
|
||||
image = draw.ellipsoid(10, 5, 3)
|
||||
T0 = inertia_tensor(image)
|
||||
eig0, V0 = np.linalg.eig(T0)
|
||||
# principal axis of ellipse = eigenvector of smallest eigenvalue
|
||||
v0 = V0[:, np.argmin(eig0)]
|
||||
|
||||
assert np.allclose(v0, [1, 0, 0]) or np.allclose(-v0, [1, 0, 0])
|
||||
|
||||
imrot = ndi.rotate(image.astype(float), 30, axes=(0, 1), order=1)
|
||||
Tr = inertia_tensor(imrot)
|
||||
eigr, Vr = np.linalg.eig(Tr)
|
||||
vr = Vr[:, np.argmin(eigr)]
|
||||
|
||||
# Check that axis has rotated by expected amount
|
||||
pi, cos, sin = np.pi, np.cos, np.sin
|
||||
R = np.array([[ cos(pi/6), -sin(pi/6), 0],
|
||||
[ sin(pi/6), cos(pi/6), 0],
|
||||
[ 0, 0, 1]])
|
||||
expected_vr = R @ v0
|
||||
assert (np.allclose(vr, expected_vr, atol=1e-3, rtol=0.01) or
|
||||
np.allclose(-vr, expected_vr, atol=1e-3, rtol=0.01))
|
||||
|
||||
|
||||
def test_inertia_tensor_eigvals():
|
||||
# Floating point precision problems could make a positive
|
||||
# semidefinite matrix have an eigenvalue that is very slightly
|
||||
# negative. Check that we have caught and fixed this problem.
|
||||
image = np.array([[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]])
|
||||
# mu = np.array([[3, 0, 98], [0, 14, 0], [2, 0, 98]])
|
||||
eigvals = inertia_tensor_eigvals(image=image)
|
||||
assert (min(eigvals) >= 0)
|
35
venv/Lib/site-packages/skimage/measure/tests/test_pnpoly.py
Normal file
35
venv/Lib/site-packages/skimage/measure/tests/test_pnpoly.py
Normal file
|
@ -0,0 +1,35 @@
|
|||
import numpy as np
|
||||
from skimage.measure import points_in_poly, grid_points_in_poly
|
||||
|
||||
from skimage._shared.testing import assert_array_equal
|
||||
|
||||
|
||||
class TestNpnpoly():
|
||||
def test_square(self):
|
||||
v = np.array([[0, 0],
|
||||
[0, 1],
|
||||
[1, 1],
|
||||
[1, 0]])
|
||||
assert(points_in_poly([[0.5, 0.5]], v)[0])
|
||||
assert(not points_in_poly([[-0.1, 0.1]], v)[0])
|
||||
|
||||
def test_triangle(self):
|
||||
v = np.array([[0, 0],
|
||||
[1, 0],
|
||||
[0.5, 0.75]])
|
||||
assert(points_in_poly([[0.5, 0.7]], v)[0])
|
||||
assert(not points_in_poly([[0.5, 0.76]], v)[0])
|
||||
assert(not points_in_poly([[0.7, 0.5]], v)[0])
|
||||
|
||||
def test_type(self):
|
||||
assert(points_in_poly([[0, 0]], [[0, 0]]).dtype == np.bool)
|
||||
|
||||
|
||||
def test_grid_points_in_poly():
|
||||
v = np.array([[0, 0],
|
||||
[5, 0],
|
||||
[5, 5]])
|
||||
|
||||
expected = np.tril(np.ones((5, 5), dtype=bool))
|
||||
|
||||
assert_array_equal(grid_points_in_poly((5, 5), v), expected)
|
64
venv/Lib/site-packages/skimage/measure/tests/test_polygon.py
Normal file
64
venv/Lib/site-packages/skimage/measure/tests/test_polygon.py
Normal file
|
@ -0,0 +1,64 @@
|
|||
import numpy as np
|
||||
from skimage.measure import approximate_polygon, subdivide_polygon
|
||||
from skimage.measure._polygon import _SUBDIVISION_MASKS
|
||||
|
||||
from skimage._shared import testing
|
||||
from skimage._shared.testing import assert_array_equal, assert_equal
|
||||
|
||||
|
||||
square = np.array([
|
||||
[0, 0], [0, 1], [0, 2], [0, 3],
|
||||
[1, 3], [2, 3], [3, 3],
|
||||
[3, 2], [3, 1], [3, 0],
|
||||
[2, 0], [1, 0], [0, 0]
|
||||
])
|
||||
|
||||
|
||||
def test_approximate_polygon():
|
||||
out = approximate_polygon(square, 0.1)
|
||||
assert_array_equal(out, square[(0, 3, 6, 9, 12), :])
|
||||
|
||||
out = approximate_polygon(square, 2.2)
|
||||
assert_array_equal(out, square[(0, 6, 12), :])
|
||||
|
||||
out = approximate_polygon(square[(0, 1, 3, 4, 5, 6, 7, 9, 11, 12), :], 0.1)
|
||||
assert_array_equal(out, square[(0, 3, 6, 9, 12), :])
|
||||
|
||||
out = approximate_polygon(square, -1)
|
||||
assert_array_equal(out, square)
|
||||
out = approximate_polygon(square, 0)
|
||||
assert_array_equal(out, square)
|
||||
|
||||
|
||||
def test_subdivide_polygon():
|
||||
new_square1 = square
|
||||
new_square2 = square[:-1]
|
||||
new_square3 = square[:-1]
|
||||
# test iterative subdvision
|
||||
for _ in range(10):
|
||||
square1, square2, square3 = new_square1, new_square2, new_square3
|
||||
# test different B-Spline degrees
|
||||
for degree in range(1, 7):
|
||||
mask_len = len(_SUBDIVISION_MASKS[degree][0])
|
||||
# test circular
|
||||
new_square1 = subdivide_polygon(square1, degree)
|
||||
assert_array_equal(new_square1[-1], new_square1[0])
|
||||
assert_equal(new_square1.shape[0],
|
||||
2 * square1.shape[0] - 1)
|
||||
# test non-circular
|
||||
new_square2 = subdivide_polygon(square2, degree)
|
||||
assert_equal(new_square2.shape[0],
|
||||
2 * (square2.shape[0] - mask_len + 1))
|
||||
# test non-circular, preserve_ends
|
||||
new_square3 = subdivide_polygon(square3, degree, True)
|
||||
assert_equal(new_square3[0], square3[0])
|
||||
assert_equal(new_square3[-1], square3[-1])
|
||||
|
||||
assert_equal(new_square3.shape[0],
|
||||
2 * (square3.shape[0] - mask_len + 2))
|
||||
|
||||
# not supported B-Spline degree
|
||||
with testing.raises(ValueError):
|
||||
subdivide_polygon(square, 0)
|
||||
with testing.raises(ValueError):
|
||||
subdivide_polygon(square, 8)
|
214
venv/Lib/site-packages/skimage/measure/tests/test_profile.py
Normal file
214
venv/Lib/site-packages/skimage/measure/tests/test_profile.py
Normal file
|
@ -0,0 +1,214 @@
|
|||
import numpy as np
|
||||
|
||||
from ..._shared.testing import assert_equal, assert_almost_equal
|
||||
from ..._shared._warnings import expected_warnings
|
||||
from ..profile import profile_line
|
||||
|
||||
image = np.arange(100).reshape((10, 10)).astype(np.float)
|
||||
|
||||
|
||||
def test_horizontal_rightward():
|
||||
prof = profile_line(image, (0, 2), (0, 8), order=0, mode='constant')
|
||||
expected_prof = np.arange(2, 9)
|
||||
assert_equal(prof, expected_prof)
|
||||
|
||||
|
||||
def test_horizontal_leftward():
|
||||
prof = profile_line(image, (0, 8), (0, 2), order=0, mode='constant')
|
||||
expected_prof = np.arange(8, 1, -1)
|
||||
assert_equal(prof, expected_prof)
|
||||
|
||||
|
||||
def test_vertical_downward():
|
||||
prof = profile_line(image, (2, 5), (8, 5), order=0, mode='constant')
|
||||
expected_prof = np.arange(25, 95, 10)
|
||||
assert_equal(prof, expected_prof)
|
||||
|
||||
|
||||
def test_vertical_upward():
|
||||
prof = profile_line(image, (8, 5), (2, 5), order=0, mode='constant')
|
||||
expected_prof = np.arange(85, 15, -10)
|
||||
assert_equal(prof, expected_prof)
|
||||
|
||||
|
||||
def test_45deg_right_downward():
|
||||
prof = profile_line(image, (2, 2), (8, 8), order=0, mode='constant')
|
||||
expected_prof = np.array([22, 33, 33, 44, 55, 55, 66, 77, 77, 88])
|
||||
# repeats are due to aliasing using nearest neighbor interpolation.
|
||||
# to see this, imagine a diagonal line with markers every unit of
|
||||
# length traversing a checkerboard pattern of squares also of unit
|
||||
# length. Because the line is diagonal, sometimes more than one
|
||||
# marker will fall on the same checkerboard box.
|
||||
assert_almost_equal(prof, expected_prof)
|
||||
|
||||
|
||||
def test_45deg_right_downward_interpolated():
|
||||
prof = profile_line(image, (2, 2), (8, 8), order=1, mode='constant')
|
||||
expected_prof = np.linspace(22, 88, 10)
|
||||
assert_almost_equal(prof, expected_prof)
|
||||
|
||||
|
||||
def test_45deg_right_upward():
|
||||
prof = profile_line(image, (8, 2), (2, 8), order=1, mode='constant')
|
||||
expected_prof = np.arange(82, 27, -6)
|
||||
assert_almost_equal(prof, expected_prof)
|
||||
|
||||
|
||||
def test_45deg_left_upward():
|
||||
prof = profile_line(image, (8, 8), (2, 2), order=1, mode='constant')
|
||||
expected_prof = np.arange(88, 21, -22. / 3)
|
||||
assert_almost_equal(prof, expected_prof)
|
||||
|
||||
|
||||
def test_45deg_left_downward():
|
||||
prof = profile_line(image, (2, 8), (8, 2), order=1, mode='constant')
|
||||
expected_prof = np.arange(28, 83, 6)
|
||||
assert_almost_equal(prof, expected_prof)
|
||||
|
||||
|
||||
def test_pythagorean_triangle_right_downward():
|
||||
prof = profile_line(image, (1, 1), (7, 9), order=0, mode='constant')
|
||||
expected_prof = np.array([11, 22, 23, 33, 34, 45, 56, 57, 67, 68, 79])
|
||||
assert_equal(prof, expected_prof)
|
||||
|
||||
|
||||
def test_pythagorean_triangle_right_downward_interpolated():
|
||||
prof = profile_line(image, (1, 1), (7, 9), order=1, mode='constant')
|
||||
expected_prof = np.linspace(11, 79, 11)
|
||||
assert_almost_equal(prof, expected_prof)
|
||||
|
||||
|
||||
pyth_image = np.zeros((6, 7), np.float)
|
||||
line = ((1, 2, 2, 3, 3, 4), (1, 2, 3, 3, 4, 5))
|
||||
below = ((2, 2, 3, 4, 4, 5), (0, 1, 2, 3, 4, 4))
|
||||
above = ((0, 1, 1, 2, 3, 3), (2, 2, 3, 4, 5, 6))
|
||||
pyth_image[line] = 1.8
|
||||
pyth_image[below] = 0.6
|
||||
pyth_image[above] = 0.6
|
||||
|
||||
|
||||
def test_pythagorean_triangle_right_downward_linewidth():
|
||||
prof = profile_line(pyth_image, (1, 1), (4, 5), linewidth=3, order=0,
|
||||
mode='constant')
|
||||
expected_prof = np.ones(6)
|
||||
assert_almost_equal(prof, expected_prof)
|
||||
|
||||
|
||||
def test_pythagorean_triangle_right_upward_linewidth():
|
||||
prof = profile_line(pyth_image[::-1, :], (4, 1), (1, 5),
|
||||
linewidth=3, order=0, mode='constant')
|
||||
expected_prof = np.ones(6)
|
||||
assert_almost_equal(prof, expected_prof)
|
||||
|
||||
|
||||
def test_pythagorean_triangle_transpose_left_down_linewidth():
|
||||
prof = profile_line(pyth_image.T[:, ::-1], (1, 4), (5, 1),
|
||||
linewidth=3, order=0, mode='constant')
|
||||
expected_prof = np.ones(6)
|
||||
assert_almost_equal(prof, expected_prof)
|
||||
|
||||
|
||||
def test_reduce_func_mean():
|
||||
prof = profile_line(pyth_image, (0, 1), (3, 1), linewidth=3, order=0,
|
||||
reduce_func=np.mean, mode='reflect')
|
||||
expected_prof = pyth_image[:4, :3].mean(1)
|
||||
assert_almost_equal(prof, expected_prof)
|
||||
|
||||
|
||||
def test_reduce_func_max():
|
||||
prof = profile_line(pyth_image, (0, 1), (3, 1), linewidth=3, order=0,
|
||||
reduce_func=np.max, mode='reflect')
|
||||
expected_prof = pyth_image[:4, :3].max(1)
|
||||
assert_almost_equal(prof, expected_prof)
|
||||
|
||||
|
||||
def test_reduce_func_sum():
|
||||
prof = profile_line(pyth_image, (0, 1), (3, 1), linewidth=3, order=0,
|
||||
reduce_func=np.sum, mode='reflect')
|
||||
expected_prof = pyth_image[:4, :3].sum(1)
|
||||
assert_almost_equal(prof, expected_prof)
|
||||
|
||||
|
||||
def test_reduce_func_mean_linewidth_1():
|
||||
prof = profile_line(pyth_image, (0, 1), (3, 1), linewidth=1, order=0,
|
||||
reduce_func=np.mean, mode='constant')
|
||||
expected_prof = pyth_image[:4, 1]
|
||||
assert_almost_equal(prof, expected_prof)
|
||||
|
||||
|
||||
def test_reduce_func_None_linewidth_1():
|
||||
prof = profile_line(pyth_image, (1, 2), (4, 2), linewidth=1,
|
||||
order=0, reduce_func=None, mode='constant')
|
||||
expected_prof = pyth_image[1:5, 2, np.newaxis]
|
||||
assert_almost_equal(prof, expected_prof)
|
||||
|
||||
|
||||
def test_reduce_func_None_linewidth_3():
|
||||
prof = profile_line(pyth_image, (1, 2), (4, 2), linewidth=3,
|
||||
order=0, reduce_func=None, mode='constant')
|
||||
expected_prof = pyth_image[1:5, 1:4]
|
||||
assert_almost_equal(prof, expected_prof)
|
||||
|
||||
|
||||
def test_reduce_func_lambda_linewidth_3():
|
||||
def reduce_func(x):
|
||||
return x + x ** 2
|
||||
prof = profile_line(pyth_image, (1, 2), (4, 2), linewidth=3, order=0,
|
||||
reduce_func=reduce_func, mode='constant')
|
||||
expected_prof = np.apply_along_axis(reduce_func,
|
||||
arr=pyth_image[1:5, 1:4], axis=1)
|
||||
assert_almost_equal(prof, expected_prof)
|
||||
|
||||
|
||||
def test_reduce_func_sqrt_linewidth_3():
|
||||
def reduce_func(x):
|
||||
return x ** 0.5
|
||||
prof = profile_line(pyth_image, (1, 2), (4, 2), linewidth=3,
|
||||
order=0, reduce_func=reduce_func,
|
||||
mode='constant')
|
||||
expected_prof = np.apply_along_axis(reduce_func,
|
||||
arr=pyth_image[1:5, 1:4], axis=1)
|
||||
assert_almost_equal(prof, expected_prof)
|
||||
|
||||
|
||||
def test_reduce_func_sumofsqrt_linewidth_3():
|
||||
def reduce_func(x):
|
||||
return np.sum(x ** 0.5)
|
||||
prof = profile_line(pyth_image, (1, 2), (4, 2), linewidth=3, order=0,
|
||||
reduce_func=reduce_func, mode='constant')
|
||||
expected_prof = np.apply_along_axis(reduce_func,
|
||||
arr=pyth_image[1:5, 1:4], axis=1)
|
||||
assert_almost_equal(prof, expected_prof)
|
||||
|
||||
|
||||
def test_oob_coodinates():
|
||||
offset = 2
|
||||
idx = pyth_image.shape[0] + offset
|
||||
prof = profile_line(pyth_image, (-offset, 2), (idx, 2), linewidth=1,
|
||||
order=0, reduce_func=None, mode='constant')
|
||||
expected_prof = np.vstack([np.zeros((offset, 1)),
|
||||
pyth_image[:, 2, np.newaxis],
|
||||
np.zeros((offset + 1, 1))])
|
||||
assert_almost_equal(prof, expected_prof)
|
||||
|
||||
|
||||
def test_bool_array_input():
|
||||
|
||||
shape = (200, 200)
|
||||
center_x, center_y = (140, 150)
|
||||
radius = 20
|
||||
x, y = np.meshgrid(range(shape[1]), range(shape[0]))
|
||||
mask = (y - center_y) ** 2 + (x - center_x) ** 2 < radius ** 2
|
||||
src = (center_y, center_x)
|
||||
phi = 4 * np.pi / 9.
|
||||
dy = 31 * np.cos(phi)
|
||||
dx = 31 * np.sin(phi)
|
||||
dst = (center_y + dy, center_x + dx)
|
||||
|
||||
profile_u8 = profile_line(mask.astype(np.uint8), src, dst)
|
||||
assert all(profile_u8[:radius] == 1)
|
||||
|
||||
profile_b = profile_line(mask, src, dst)
|
||||
assert all(profile_b[:radius] == 1)
|
||||
|
||||
assert all(profile_b == profile_u8)
|
575
venv/Lib/site-packages/skimage/measure/tests/test_regionprops.py
Normal file
575
venv/Lib/site-packages/skimage/measure/tests/test_regionprops.py
Normal file
|
@ -0,0 +1,575 @@
|
|||
import math
|
||||
|
||||
import numpy as np
|
||||
from numpy import array
|
||||
|
||||
from skimage._shared._warnings import expected_warnings
|
||||
from skimage.measure._regionprops import (regionprops, PROPS, perimeter,
|
||||
_parse_docs, _props_to_dict,
|
||||
regionprops_table, OBJECT_COLUMNS,
|
||||
COL_DTYPES)
|
||||
from skimage._shared import testing
|
||||
from skimage._shared.testing import (assert_array_equal, assert_almost_equal,
|
||||
assert_array_almost_equal, assert_equal)
|
||||
|
||||
|
||||
SAMPLE = np.array(
|
||||
[[0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0],
|
||||
[0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0],
|
||||
[1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0],
|
||||
[0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1],
|
||||
[0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1]]
|
||||
)
|
||||
INTENSITY_SAMPLE = SAMPLE.copy()
|
||||
INTENSITY_SAMPLE[1, 9:11] = 2
|
||||
|
||||
SAMPLE_3D = np.zeros((6, 6, 6), dtype=np.uint8)
|
||||
SAMPLE_3D[1:3, 1:3, 1:3] = 1
|
||||
SAMPLE_3D[3, 2, 2] = 1
|
||||
INTENSITY_SAMPLE_3D = SAMPLE_3D.copy()
|
||||
|
||||
|
||||
def test_all_props():
|
||||
region = regionprops(SAMPLE, INTENSITY_SAMPLE)[0]
|
||||
for prop in PROPS:
|
||||
try:
|
||||
assert_almost_equal(region[prop], getattr(region, PROPS[prop]))
|
||||
except TypeError: # the `slice` property causes this
|
||||
pass
|
||||
|
||||
|
||||
def test_all_props_3d():
|
||||
region = regionprops(SAMPLE_3D, INTENSITY_SAMPLE_3D)[0]
|
||||
for prop in PROPS:
|
||||
try:
|
||||
assert_almost_equal(region[prop], getattr(region, PROPS[prop]))
|
||||
except (NotImplementedError, TypeError):
|
||||
pass
|
||||
|
||||
|
||||
def test_dtype():
|
||||
regionprops(np.zeros((10, 10), dtype=np.int))
|
||||
regionprops(np.zeros((10, 10), dtype=np.uint))
|
||||
with testing.raises(TypeError):
|
||||
regionprops(np.zeros((10, 10), dtype=np.float))
|
||||
with testing.raises(TypeError):
|
||||
regionprops(np.zeros((10, 10), dtype=np.double))
|
||||
with testing.raises(TypeError):
|
||||
regionprops(np.zeros((10, 10), dtype=np.bool))
|
||||
|
||||
|
||||
def test_ndim():
|
||||
regionprops(np.zeros((10, 10), dtype=np.int))
|
||||
regionprops(np.zeros((10, 10, 1), dtype=np.int))
|
||||
regionprops(np.zeros((10, 10, 10), dtype=np.int))
|
||||
regionprops(np.zeros((1, 1), dtype=np.int))
|
||||
regionprops(np.zeros((1, 1, 1), dtype=np.int))
|
||||
with testing.raises(TypeError):
|
||||
regionprops(np.zeros((10, 10, 10, 2), dtype=np.int))
|
||||
|
||||
|
||||
def test_area():
|
||||
area = regionprops(SAMPLE)[0].area
|
||||
assert area == np.sum(SAMPLE)
|
||||
area = regionprops(SAMPLE_3D)[0].area
|
||||
assert area == np.sum(SAMPLE_3D)
|
||||
|
||||
|
||||
def test_bbox():
|
||||
bbox = regionprops(SAMPLE)[0].bbox
|
||||
assert_array_almost_equal(bbox, (0, 0, SAMPLE.shape[0], SAMPLE.shape[1]))
|
||||
|
||||
SAMPLE_mod = SAMPLE.copy()
|
||||
SAMPLE_mod[:, -1] = 0
|
||||
bbox = regionprops(SAMPLE_mod)[0].bbox
|
||||
assert_array_almost_equal(bbox, (0, 0, SAMPLE.shape[0], SAMPLE.shape[1]-1))
|
||||
|
||||
bbox = regionprops(SAMPLE_3D)[0].bbox
|
||||
assert_array_almost_equal(bbox, (1, 1, 1, 4, 3, 3))
|
||||
|
||||
|
||||
def test_bbox_area():
|
||||
padded = np.pad(SAMPLE, 5, mode='constant')
|
||||
bbox_area = regionprops(padded)[0].bbox_area
|
||||
assert_array_almost_equal(bbox_area, SAMPLE.size)
|
||||
|
||||
|
||||
def test_moments_central():
|
||||
mu = regionprops(SAMPLE)[0].moments_central
|
||||
# determined with OpenCV
|
||||
assert_almost_equal(mu[2, 0], 436.00000000000045)
|
||||
# different from OpenCV results, bug in OpenCV
|
||||
assert_almost_equal(mu[3, 0], -737.333333333333)
|
||||
assert_almost_equal(mu[1, 1], -87.33333333333303)
|
||||
assert_almost_equal(mu[2, 1], -127.5555555555593)
|
||||
assert_almost_equal(mu[0, 2], 1259.7777777777774)
|
||||
assert_almost_equal(mu[1, 2], 2000.296296296291)
|
||||
assert_almost_equal(mu[0, 3], -760.0246913580195)
|
||||
|
||||
|
||||
def test_centroid():
|
||||
centroid = regionprops(SAMPLE)[0].centroid
|
||||
# determined with MATLAB
|
||||
assert_array_almost_equal(centroid, (5.66666666666666, 9.444444444444444))
|
||||
|
||||
|
||||
def test_centroid_3d():
|
||||
centroid = regionprops(SAMPLE_3D)[0].centroid
|
||||
# determined by mean along axis 1 of SAMPLE_3D.nonzero()
|
||||
assert_array_almost_equal(centroid, (1.66666667, 1.55555556, 1.55555556))
|
||||
|
||||
|
||||
def test_convex_area():
|
||||
area = regionprops(SAMPLE)[0].convex_area
|
||||
# determined with MATLAB
|
||||
assert area == 124
|
||||
|
||||
|
||||
def test_convex_image():
|
||||
img = regionprops(SAMPLE)[0].convex_image
|
||||
# determined with MATLAB
|
||||
ref = np.array(
|
||||
[[0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0],
|
||||
[0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0],
|
||||
[0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0],
|
||||
[0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0],
|
||||
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
|
||||
[0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
|
||||
[0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]]
|
||||
)
|
||||
assert_array_equal(img, ref)
|
||||
|
||||
|
||||
def test_coordinates():
|
||||
sample = np.zeros((10, 10), dtype=np.int8)
|
||||
coords = np.array([[3, 2], [3, 3], [3, 4]])
|
||||
sample[coords[:, 0], coords[:, 1]] = 1
|
||||
prop_coords = regionprops(sample)[0].coords
|
||||
assert_array_equal(prop_coords, coords)
|
||||
|
||||
sample = np.zeros((6, 6, 6), dtype=np.int8)
|
||||
coords = np.array([[1, 1, 1], [1, 2, 1], [1, 3, 1]])
|
||||
sample[coords[:, 0], coords[:, 1], coords[:, 2]] = 1
|
||||
prop_coords = regionprops(sample)[0].coords
|
||||
assert_array_equal(prop_coords, coords)
|
||||
|
||||
|
||||
def test_slice():
|
||||
padded = np.pad(SAMPLE, ((2, 4), (5, 2)), mode='constant')
|
||||
nrow, ncol = SAMPLE.shape
|
||||
result = regionprops(padded)[0].slice
|
||||
expected = (slice(2, 2+nrow), slice(5, 5+ncol))
|
||||
assert_equal(result, expected)
|
||||
|
||||
|
||||
def test_eccentricity():
|
||||
eps = regionprops(SAMPLE)[0].eccentricity
|
||||
assert_almost_equal(eps, 0.814629313427)
|
||||
|
||||
img = np.zeros((5, 5), dtype=np.int)
|
||||
img[2, 2] = 1
|
||||
eps = regionprops(img)[0].eccentricity
|
||||
assert_almost_equal(eps, 0)
|
||||
|
||||
|
||||
def test_equiv_diameter():
|
||||
diameter = regionprops(SAMPLE)[0].equivalent_diameter
|
||||
# determined with MATLAB
|
||||
assert_almost_equal(diameter, 9.57461472963)
|
||||
|
||||
|
||||
def test_euler_number():
|
||||
en = regionprops(SAMPLE)[0].euler_number
|
||||
assert en == 1
|
||||
|
||||
SAMPLE_mod = SAMPLE.copy()
|
||||
SAMPLE_mod[7, -3] = 0
|
||||
en = regionprops(SAMPLE_mod)[0].euler_number
|
||||
assert en == 0
|
||||
|
||||
|
||||
def test_extent():
|
||||
extent = regionprops(SAMPLE)[0].extent
|
||||
assert_almost_equal(extent, 0.4)
|
||||
|
||||
|
||||
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,
|
||||
-2.72586158e-05,
|
||||
-6.48350653e-06
|
||||
])
|
||||
# bug in OpenCV caused in Central Moments calculation?
|
||||
assert_array_almost_equal(hu, ref)
|
||||
|
||||
|
||||
def test_image():
|
||||
img = regionprops(SAMPLE)[0].image
|
||||
assert_array_equal(img, SAMPLE)
|
||||
|
||||
img = regionprops(SAMPLE_3D)[0].image
|
||||
assert_array_equal(img, SAMPLE_3D[1:4, 1:3, 1:3])
|
||||
|
||||
|
||||
def test_label():
|
||||
label = regionprops(SAMPLE)[0].label
|
||||
assert_array_equal(label, 1)
|
||||
|
||||
label = regionprops(SAMPLE_3D)[0].label
|
||||
assert_array_equal(label, 1)
|
||||
|
||||
|
||||
def test_filled_area():
|
||||
area = regionprops(SAMPLE)[0].filled_area
|
||||
assert area == np.sum(SAMPLE)
|
||||
|
||||
SAMPLE_mod = SAMPLE.copy()
|
||||
SAMPLE_mod[7, -3] = 0
|
||||
area = regionprops(SAMPLE_mod)[0].filled_area
|
||||
assert area == np.sum(SAMPLE)
|
||||
|
||||
|
||||
def test_filled_image():
|
||||
img = regionprops(SAMPLE)[0].filled_image
|
||||
assert_array_equal(img, SAMPLE)
|
||||
|
||||
|
||||
def test_major_axis_length():
|
||||
length = regionprops(SAMPLE)[0].major_axis_length
|
||||
# MATLAB has different interpretation of ellipse than found in literature,
|
||||
# here implemented as found in literature
|
||||
assert_almost_equal(length, 16.7924234999)
|
||||
|
||||
|
||||
def test_max_intensity():
|
||||
intensity = regionprops(SAMPLE, intensity_image=INTENSITY_SAMPLE
|
||||
)[0].max_intensity
|
||||
assert_almost_equal(intensity, 2)
|
||||
|
||||
|
||||
def test_mean_intensity():
|
||||
intensity = regionprops(SAMPLE, intensity_image=INTENSITY_SAMPLE
|
||||
)[0].mean_intensity
|
||||
assert_almost_equal(intensity, 1.02777777777777)
|
||||
|
||||
|
||||
def test_min_intensity():
|
||||
intensity = regionprops(SAMPLE, intensity_image=INTENSITY_SAMPLE
|
||||
)[0].min_intensity
|
||||
assert_almost_equal(intensity, 1)
|
||||
|
||||
|
||||
def test_minor_axis_length():
|
||||
length = regionprops(SAMPLE)[0].minor_axis_length
|
||||
# MATLAB has different interpretation of ellipse than found in literature,
|
||||
# here implemented as found in literature
|
||||
assert_almost_equal(length, 9.739302807263)
|
||||
|
||||
|
||||
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], 680.0)
|
||||
assert_almost_equal(m[0, 2], 7682.0)
|
||||
assert_almost_equal(m[0, 3], 95588.0)
|
||||
assert_almost_equal(m[1, 0], 408.0)
|
||||
assert_almost_equal(m[1, 1], 3766.0)
|
||||
assert_almost_equal(m[1, 2], 43882.0)
|
||||
assert_almost_equal(m[2, 0], 2748.0)
|
||||
assert_almost_equal(m[2, 1], 24836.0)
|
||||
assert_almost_equal(m[3, 0], 19776.0)
|
||||
|
||||
|
||||
def test_moments_normalized():
|
||||
nu = regionprops(SAMPLE)[0].moments_normalized
|
||||
|
||||
# determined with OpenCV
|
||||
assert_almost_equal(nu[0, 2], 0.24301268861454037)
|
||||
assert_almost_equal(nu[0, 3], -0.017278118992041805)
|
||||
assert_almost_equal(nu[1, 1], -0.016846707818929982)
|
||||
assert_almost_equal(nu[1, 2], 0.045473992910668816)
|
||||
assert_almost_equal(nu[2, 0], 0.08410493827160502)
|
||||
assert_almost_equal(nu[2, 1], -0.002899800614433943)
|
||||
|
||||
|
||||
def test_orientation():
|
||||
orient = regionprops(SAMPLE)[0].orientation
|
||||
# determined with MATLAB
|
||||
assert_almost_equal(orient, -1.4663278802756865)
|
||||
# test diagonal regions
|
||||
diag = np.eye(10, dtype=int)
|
||||
orient_diag = regionprops(diag)[0].orientation
|
||||
assert_almost_equal(orient_diag, -math.pi / 4)
|
||||
orient_diag = regionprops(np.flipud(diag))[0].orientation
|
||||
assert_almost_equal(orient_diag, math.pi / 4)
|
||||
orient_diag = regionprops(np.fliplr(diag))[0].orientation
|
||||
assert_almost_equal(orient_diag, math.pi / 4)
|
||||
orient_diag = regionprops(np.fliplr(np.flipud(diag)))[0].orientation
|
||||
assert_almost_equal(orient_diag, -math.pi / 4)
|
||||
|
||||
|
||||
def test_perimeter():
|
||||
per = regionprops(SAMPLE)[0].perimeter
|
||||
assert_almost_equal(per, 55.2487373415)
|
||||
|
||||
per = perimeter(SAMPLE.astype('double'), neighbourhood=8)
|
||||
assert_almost_equal(per, 46.8284271247)
|
||||
|
||||
|
||||
def test_solidity():
|
||||
solidity = regionprops(SAMPLE)[0].solidity
|
||||
# determined with MATLAB
|
||||
assert_almost_equal(solidity, 0.580645161290323)
|
||||
|
||||
|
||||
def test_weighted_moments_central():
|
||||
wmu = regionprops(SAMPLE, intensity_image=INTENSITY_SAMPLE
|
||||
)[0].weighted_moments_central
|
||||
ref = np.array(
|
||||
[[7.4000000000e+01, 3.7303493627e-14, 1.2602837838e+03,
|
||||
-7.6561796932e+02],
|
||||
[-2.1316282073e-13, -8.7837837838e+01, 2.1571526662e+03,
|
||||
-4.2385971907e+03],
|
||||
[4.7837837838e+02, -1.4801314828e+02, 6.6989799420e+03,
|
||||
-9.9501164076e+03],
|
||||
[-7.5943608473e+02, -1.2714707125e+03, 1.5304076361e+04,
|
||||
-3.3156729271e+04]])
|
||||
|
||||
np.set_printoptions(precision=10)
|
||||
assert_array_almost_equal(wmu, ref)
|
||||
|
||||
|
||||
def test_weighted_centroid():
|
||||
centroid = regionprops(SAMPLE, intensity_image=INTENSITY_SAMPLE
|
||||
)[0].weighted_centroid
|
||||
assert_array_almost_equal(centroid, (5.540540540540, 9.445945945945))
|
||||
|
||||
|
||||
def test_weighted_moments_hu():
|
||||
whu = regionprops(SAMPLE, intensity_image=INTENSITY_SAMPLE
|
||||
)[0].weighted_moments_hu
|
||||
ref = np.array([
|
||||
3.1750587329e-01,
|
||||
2.1417517159e-02,
|
||||
2.3609322038e-02,
|
||||
1.2565683360e-03,
|
||||
8.3014209421e-07,
|
||||
-3.5073773473e-05,
|
||||
-6.7936409056e-06
|
||||
])
|
||||
assert_array_almost_equal(whu, ref)
|
||||
|
||||
|
||||
def test_weighted_moments():
|
||||
wm = regionprops(SAMPLE, intensity_image=INTENSITY_SAMPLE
|
||||
)[0].weighted_moments
|
||||
ref = np.array(
|
||||
[[7.4000000e+01, 6.9900000e+02, 7.8630000e+03, 9.7317000e+04],
|
||||
[4.1000000e+02, 3.7850000e+03, 4.4063000e+04, 5.7256700e+05],
|
||||
[2.7500000e+03, 2.4855000e+04, 2.9347700e+05, 3.9007170e+06],
|
||||
[1.9778000e+04, 1.7500100e+05, 2.0810510e+06, 2.8078871e+07]]
|
||||
)
|
||||
assert_array_almost_equal(wm, ref)
|
||||
|
||||
|
||||
def test_weighted_moments_normalized():
|
||||
wnu = regionprops(SAMPLE, intensity_image=INTENSITY_SAMPLE
|
||||
)[0].weighted_moments_normalized
|
||||
ref = np.array(
|
||||
[[ np.nan, np.nan, 0.2301467830, -0.0162529732],
|
||||
[ np.nan, -0.0160405109, 0.0457932622, -0.0104598869],
|
||||
[ 0.0873590903, -0.0031421072, 0.0165315478, -0.0028544152],
|
||||
[-0.0161217406, -0.0031376984, 0.0043903193, -0.0011057191]]
|
||||
)
|
||||
assert_array_almost_equal(wnu, ref)
|
||||
|
||||
|
||||
def test_label_sequence():
|
||||
a = np.empty((2, 2), dtype=np.int)
|
||||
a[:, :] = 2
|
||||
ps = regionprops(a)
|
||||
assert len(ps) == 1
|
||||
assert ps[0].label == 2
|
||||
|
||||
|
||||
def test_pure_background():
|
||||
a = np.zeros((2, 2), dtype=np.int)
|
||||
ps = regionprops(a)
|
||||
assert len(ps) == 0
|
||||
|
||||
|
||||
def test_invalid():
|
||||
ps = regionprops(SAMPLE)
|
||||
|
||||
def get_intensity_image():
|
||||
ps[0].intensity_image
|
||||
|
||||
with testing.raises(AttributeError):
|
||||
get_intensity_image()
|
||||
|
||||
|
||||
def test_invalid_size():
|
||||
wrong_intensity_sample = np.array([[1], [1]])
|
||||
with testing.raises(ValueError):
|
||||
regionprops(SAMPLE, wrong_intensity_sample)
|
||||
|
||||
|
||||
def test_equals():
|
||||
arr = np.zeros((100, 100), dtype=np.int)
|
||||
arr[0:25, 0:25] = 1
|
||||
arr[50:99, 50:99] = 2
|
||||
|
||||
regions = regionprops(arr)
|
||||
r1 = regions[0]
|
||||
|
||||
regions = regionprops(arr)
|
||||
r2 = regions[0]
|
||||
r3 = regions[1]
|
||||
|
||||
assert_equal(r1 == r2, True, "Same regionprops are not equal")
|
||||
assert_equal(r1 != r3, True, "Different regionprops are equal")
|
||||
|
||||
|
||||
def test_iterate_all_props():
|
||||
region = regionprops(SAMPLE)[0]
|
||||
p0 = {p: region[p] for p in region}
|
||||
|
||||
region = regionprops(SAMPLE, intensity_image=INTENSITY_SAMPLE)[0]
|
||||
p1 = {p: region[p] for p in region}
|
||||
|
||||
assert len(p0) < len(p1)
|
||||
|
||||
|
||||
def test_cache():
|
||||
SAMPLE_mod = SAMPLE.copy()
|
||||
region = regionprops(SAMPLE_mod)[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():
|
||||
def foo():
|
||||
"""foo"""
|
||||
|
||||
has_docstrings = bool(foo.__doc__)
|
||||
|
||||
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)
|
||||
if has_docstrings:
|
||||
assert_equal(nr_docs_parsed, nr_props)
|
||||
ds = docs['weighted_moments_normalized']
|
||||
assert 'iteration' not in ds
|
||||
assert len(ds.split('\n')) > 3
|
||||
else:
|
||||
assert_equal(nr_docs_parsed, 0)
|
||||
|
||||
|
||||
def test_props_to_dict():
|
||||
regions = regionprops(SAMPLE)
|
||||
out = _props_to_dict(regions)
|
||||
assert out == {'label': array([1]),
|
||||
'bbox-0': array([0]), 'bbox-1': array([0]),
|
||||
'bbox-2': array([10]), 'bbox-3': array([18])}
|
||||
|
||||
regions = regionprops(SAMPLE)
|
||||
out = _props_to_dict(regions, properties=('label', 'area', 'bbox'),
|
||||
separator='+')
|
||||
assert out == {'label': array([1]), 'area': array([72]),
|
||||
'bbox+0': array([0]), 'bbox+1': array([0]),
|
||||
'bbox+2': array([10]), 'bbox+3': array([18])}
|
||||
|
||||
|
||||
def test_regionprops_table():
|
||||
out = regionprops_table(SAMPLE)
|
||||
assert out == {'label': array([1]),
|
||||
'bbox-0': array([0]), 'bbox-1': array([0]),
|
||||
'bbox-2': array([10]), 'bbox-3': array([18])}
|
||||
|
||||
out = regionprops_table(SAMPLE, properties=('label', 'area', 'bbox'),
|
||||
separator='+')
|
||||
assert out == {'label': array([1]), 'area': array([72]),
|
||||
'bbox+0': array([0]), 'bbox+1': array([0]),
|
||||
'bbox+2': array([10]), 'bbox+3': array([18])}
|
||||
|
||||
out = regionprops_table(np.zeros((2, 2), dtype=int),
|
||||
properties=('label', 'area', 'bbox'),
|
||||
separator='+')
|
||||
assert len(out) == 6
|
||||
assert len(out['label']) == 0
|
||||
assert len(out['area']) == 0
|
||||
assert len(out['bbox+0']) == 0
|
||||
assert len(out['bbox+1']) == 0
|
||||
assert len(out['bbox+2']) == 0
|
||||
assert len(out['bbox+3']) == 0
|
||||
|
||||
|
||||
def test_props_dict_complete():
|
||||
region = regionprops(SAMPLE)[0]
|
||||
properties = [s for s in dir(region) if not s.startswith('_')]
|
||||
assert set(properties) == set(PROPS.values())
|
||||
|
||||
|
||||
def test_column_dtypes_complete():
|
||||
assert set(COL_DTYPES.keys()).union(OBJECT_COLUMNS) == set(PROPS.values())
|
||||
|
||||
|
||||
def test_column_dtypes_correct():
|
||||
msg = 'mismatch with expected type,'
|
||||
region = regionprops(SAMPLE, intensity_image=INTENSITY_SAMPLE)[0]
|
||||
for col in COL_DTYPES:
|
||||
r = region[col]
|
||||
|
||||
if col in OBJECT_COLUMNS:
|
||||
assert COL_DTYPES[col] == object
|
||||
continue
|
||||
|
||||
t = type(np.ravel(r)[0])
|
||||
|
||||
if np.issubdtype(t, np.floating):
|
||||
assert COL_DTYPES[col] == float, (
|
||||
f'{col} dtype {t} {msg} {COL_DTYPES[col]}'
|
||||
)
|
||||
elif np.issubdtype(t, np.integer):
|
||||
assert COL_DTYPES[col] == int, (
|
||||
f'{col} dtype {t} {msg} {COL_DTYPES[col]}'
|
||||
)
|
||||
else:
|
||||
assert False, (
|
||||
f'{col} dtype {t} {msg} {COL_DTYPES[col]}'
|
||||
)
|
||||
|
||||
|
||||
def test_deprecated_coords_argument():
|
||||
with expected_warnings(['coordinates keyword argument']):
|
||||
region = regionprops(SAMPLE, coordinates='rc')
|
||||
with testing.raises(ValueError):
|
||||
region = regionprops(SAMPLE, coordinates='xy')
|
|
@ -0,0 +1,84 @@
|
|||
import numpy as np
|
||||
|
||||
import skimage.data
|
||||
from skimage.measure import compare_nrmse, compare_psnr, compare_mse
|
||||
|
||||
from skimage._shared import testing
|
||||
from skimage._shared.testing import assert_equal, assert_almost_equal
|
||||
from skimage._shared._warnings import expected_warnings
|
||||
|
||||
|
||||
np.random.seed(5)
|
||||
cam = skimage.data.camera()
|
||||
sigma = 20.0
|
||||
cam_noisy = np.clip(cam + sigma * np.random.randn(*cam.shape), 0, 255)
|
||||
cam_noisy = cam_noisy.astype(cam.dtype)
|
||||
|
||||
|
||||
def test_PSNR_vs_IPOL():
|
||||
# Tests vs. imdiff result from the following IPOL article and code:
|
||||
# https://www.ipol.im/pub/art/2011/g_lmii/
|
||||
p_IPOL = 22.4497
|
||||
with expected_warnings(['DEPRECATED']):
|
||||
p = compare_psnr(cam, cam_noisy)
|
||||
assert_almost_equal(p, p_IPOL, decimal=4)
|
||||
|
||||
|
||||
def test_PSNR_float():
|
||||
with expected_warnings(['DEPRECATED']):
|
||||
p_uint8 = compare_psnr(cam, cam_noisy)
|
||||
p_float64 = compare_psnr(cam / 255., cam_noisy / 255.,
|
||||
data_range=1)
|
||||
assert_almost_equal(p_uint8, p_float64, decimal=5)
|
||||
|
||||
# mixed precision inputs
|
||||
with expected_warnings(['DEPRECATED']):
|
||||
p_mixed = compare_psnr(cam / 255., np.float32(cam_noisy / 255.),
|
||||
data_range=1)
|
||||
assert_almost_equal(p_mixed, p_float64, decimal=5)
|
||||
|
||||
# mismatched dtype results in a warning if data_range is unspecified
|
||||
with expected_warnings(['Inputs have mismatched dtype', 'DEPRECATED']):
|
||||
p_mixed = compare_psnr(cam / 255., np.float32(cam_noisy / 255.))
|
||||
assert_almost_equal(p_mixed, p_float64, decimal=5)
|
||||
|
||||
|
||||
def test_PSNR_errors():
|
||||
with expected_warnings(['DEPRECATED']):
|
||||
# shape mismatch
|
||||
with testing.raises(ValueError):
|
||||
compare_psnr(cam, cam[:-1, :])
|
||||
|
||||
|
||||
def test_NRMSE():
|
||||
x = np.ones(4)
|
||||
y = np.asarray([0., 2., 2., 2.])
|
||||
with expected_warnings(['DEPRECATED']):
|
||||
assert_equal(compare_nrmse(y, x, 'mean'), 1 / np.mean(y))
|
||||
assert_equal(compare_nrmse(y, x, 'Euclidean'), 1 / np.sqrt(3))
|
||||
assert_equal(compare_nrmse(y, x, 'min-max'), 1 / (y.max() - y.min()))
|
||||
|
||||
# mixed precision inputs are allowed
|
||||
assert_almost_equal(compare_nrmse(y, np.float32(x), 'min-max'),
|
||||
1 / (y.max() - y.min()))
|
||||
|
||||
|
||||
def test_NRMSE_no_int_overflow():
|
||||
camf = cam.astype(np.float32)
|
||||
cam_noisyf = cam_noisy.astype(np.float32)
|
||||
with expected_warnings(['DEPRECATED']):
|
||||
assert_almost_equal(compare_mse(cam, cam_noisy),
|
||||
compare_mse(camf, cam_noisyf))
|
||||
assert_almost_equal(compare_nrmse(cam, cam_noisy),
|
||||
compare_nrmse(camf, cam_noisyf))
|
||||
|
||||
|
||||
def test_NRMSE_errors():
|
||||
x = np.ones(4)
|
||||
with expected_warnings(['DEPRECATED']):
|
||||
# shape mismatch
|
||||
with testing.raises(ValueError):
|
||||
compare_nrmse(x[:-1], x)
|
||||
# invalid normalization name
|
||||
with testing.raises(ValueError):
|
||||
compare_nrmse(x, x, norm_type='foo')
|
|
@ -0,0 +1,240 @@
|
|||
import os
|
||||
import numpy as np
|
||||
|
||||
from skimage import data, data_dir
|
||||
from skimage.metrics import structural_similarity
|
||||
|
||||
from skimage._shared import testing
|
||||
from skimage._shared._warnings import expected_warnings
|
||||
from skimage._shared.testing import (assert_equal, assert_almost_equal,
|
||||
assert_array_almost_equal, fetch)
|
||||
|
||||
np.random.seed(5)
|
||||
cam = data.camera()
|
||||
sigma = 20.0
|
||||
cam_noisy = np.clip(cam + sigma * np.random.randn(*cam.shape), 0, 255)
|
||||
cam_noisy = cam_noisy.astype(cam.dtype)
|
||||
|
||||
np.random.seed(1234)
|
||||
|
||||
|
||||
def test_structural_similarity_patch_range():
|
||||
N = 51
|
||||
X = (np.random.rand(N, N) * 255).astype(np.uint8)
|
||||
Y = (np.random.rand(N, N) * 255).astype(np.uint8)
|
||||
|
||||
assert(structural_similarity(X, Y, win_size=N) < 0.1)
|
||||
assert_equal(structural_similarity(X, X, win_size=N), 1)
|
||||
|
||||
|
||||
def test_structural_similarity_image():
|
||||
N = 100
|
||||
X = (np.random.rand(N, N) * 255).astype(np.uint8)
|
||||
Y = (np.random.rand(N, N) * 255).astype(np.uint8)
|
||||
|
||||
S0 = structural_similarity(X, X, win_size=3)
|
||||
assert_equal(S0, 1)
|
||||
|
||||
S1 = structural_similarity(X, Y, win_size=3)
|
||||
assert(S1 < 0.3)
|
||||
|
||||
S2 = structural_similarity(X, Y, win_size=11, gaussian_weights=True)
|
||||
assert(S2 < 0.3)
|
||||
|
||||
mssim0, S3 = structural_similarity(X, Y, full=True)
|
||||
assert_equal(S3.shape, X.shape)
|
||||
mssim = structural_similarity(X, Y)
|
||||
assert_equal(mssim0, mssim)
|
||||
|
||||
# ssim of image with itself should be 1.0
|
||||
assert_equal(structural_similarity(X, X), 1.0)
|
||||
|
||||
|
||||
# Because we are forcing a random seed state, it is probably good to test
|
||||
# against a few seeds in case on seed gives a particularly bad example
|
||||
@testing.parametrize('seed', [1, 2, 3, 5, 8, 13])
|
||||
def test_structural_similarity_grad(seed):
|
||||
N = 30
|
||||
# NOTE: This test is known to randomly fail on some systems (Mac OS X 10.6)
|
||||
# And when testing tests in parallel. Therefore, we choose a few
|
||||
# seeds that are known to work.
|
||||
# The likely cause of this failure is that we are setting a hard
|
||||
# threshold on the value of the gradient. Often the computed gradient
|
||||
# is only slightly larger than what was measured.
|
||||
# X = np.random.rand(N, N) * 255
|
||||
# Y = np.random.rand(N, N) * 255
|
||||
rnd = np.random.RandomState(seed)
|
||||
X = rnd.rand(N, N) * 255
|
||||
Y = rnd.rand(N, N) * 255
|
||||
|
||||
f = structural_similarity(X, Y, data_range=255)
|
||||
g = structural_similarity(X, Y, data_range=255, gradient=True)
|
||||
|
||||
assert f < 0.05
|
||||
|
||||
assert g[0] < 0.05
|
||||
assert np.all(g[1] < 0.05)
|
||||
|
||||
mssim, grad, s = structural_similarity(X, Y, data_range=255,
|
||||
gradient=True, full=True)
|
||||
assert np.all(grad < 0.05)
|
||||
|
||||
|
||||
def test_structural_similarity_dtype():
|
||||
N = 30
|
||||
X = np.random.rand(N, N)
|
||||
Y = np.random.rand(N, N)
|
||||
|
||||
S1 = structural_similarity(X, Y)
|
||||
|
||||
X = (X * 255).astype(np.uint8)
|
||||
Y = (X * 255).astype(np.uint8)
|
||||
|
||||
S2 = structural_similarity(X, Y)
|
||||
|
||||
assert S1 < 0.1
|
||||
assert S2 < 0.1
|
||||
|
||||
|
||||
def test_structural_similarity_multichannel():
|
||||
N = 100
|
||||
X = (np.random.rand(N, N) * 255).astype(np.uint8)
|
||||
Y = (np.random.rand(N, N) * 255).astype(np.uint8)
|
||||
|
||||
S1 = structural_similarity(X, Y, win_size=3)
|
||||
|
||||
# replicate across three channels. should get identical value
|
||||
Xc = np.tile(X[..., np.newaxis], (1, 1, 3))
|
||||
Yc = np.tile(Y[..., np.newaxis], (1, 1, 3))
|
||||
S2 = structural_similarity(Xc, Yc, multichannel=True, win_size=3)
|
||||
assert_almost_equal(S1, S2)
|
||||
|
||||
# full case should return an image as well
|
||||
m, S3 = structural_similarity(Xc, Yc, multichannel=True, full=True)
|
||||
assert_equal(S3.shape, Xc.shape)
|
||||
|
||||
# gradient case
|
||||
m, grad = structural_similarity(Xc, Yc, multichannel=True, gradient=True)
|
||||
assert_equal(grad.shape, Xc.shape)
|
||||
|
||||
# full and gradient case
|
||||
m, grad, S3 = structural_similarity(Xc, Yc,
|
||||
multichannel=True,
|
||||
full=True,
|
||||
gradient=True)
|
||||
assert_equal(grad.shape, Xc.shape)
|
||||
assert_equal(S3.shape, Xc.shape)
|
||||
|
||||
# fail if win_size exceeds any non-channel dimension
|
||||
with testing.raises(ValueError):
|
||||
structural_similarity(Xc, Yc, win_size=7, multichannel=False)
|
||||
|
||||
|
||||
def test_structural_similarity_nD():
|
||||
# test 1D through 4D on small random arrays
|
||||
N = 10
|
||||
for ndim in range(1, 5):
|
||||
xsize = [N, ] * 5
|
||||
X = (np.random.rand(*xsize) * 255).astype(np.uint8)
|
||||
Y = (np.random.rand(*xsize) * 255).astype(np.uint8)
|
||||
|
||||
mssim = structural_similarity(X, Y, win_size=3)
|
||||
assert mssim < 0.05
|
||||
|
||||
|
||||
def test_structural_similarity_multichannel_chelsea():
|
||||
# color image example
|
||||
Xc = data.chelsea()
|
||||
sigma = 15.0
|
||||
Yc = np.clip(Xc + sigma * np.random.randn(*Xc.shape), 0, 255)
|
||||
Yc = Yc.astype(Xc.dtype)
|
||||
|
||||
# multichannel result should be mean of the individual channel results
|
||||
mssim = structural_similarity(Xc, Yc, multichannel=True)
|
||||
mssim_sep = [structural_similarity(Yc[..., c], Xc[..., c])
|
||||
for c in range(Xc.shape[-1])]
|
||||
assert_almost_equal(mssim, np.mean(mssim_sep))
|
||||
|
||||
# ssim of image with itself should be 1.0
|
||||
assert_equal(structural_similarity(Xc, Xc, multichannel=True), 1.0)
|
||||
|
||||
|
||||
def test_gaussian_mssim_vs_IPOL():
|
||||
# Tests vs. imdiff result from the following IPOL article and code:
|
||||
# https://www.ipol.im/pub/art/2011/g_lmii/
|
||||
mssim_IPOL = 0.327309966087341
|
||||
mssim = structural_similarity(cam, cam_noisy, gaussian_weights=True,
|
||||
use_sample_covariance=False)
|
||||
assert_almost_equal(mssim, mssim_IPOL, decimal=3)
|
||||
|
||||
|
||||
def test_gaussian_mssim_vs_author_ref():
|
||||
"""
|
||||
test vs. result from original author's Matlab implementation available at
|
||||
https://ece.uwaterloo.ca/~z70wang/research/ssim/
|
||||
|
||||
Matlab test code:
|
||||
img1 = imread('camera.png')
|
||||
img2 = imread('camera_noisy.png')
|
||||
mssim = ssim_index(img1, img2)
|
||||
"""
|
||||
mssim_matlab = 0.327314295673357
|
||||
mssim = structural_similarity(cam, cam_noisy, gaussian_weights=True,
|
||||
use_sample_covariance=False)
|
||||
assert_almost_equal(mssim, mssim_matlab, decimal=10)
|
||||
|
||||
|
||||
def test_gaussian_mssim_and_gradient_vs_Matlab():
|
||||
# comparison to Matlab implementation of N. Avanaki:
|
||||
# https://ece.uwaterloo.ca/~nnikvand/Coderep/SHINE%20TOOLBOX/SHINEtoolbox/
|
||||
# Note: final line of ssim_sens.m was modified to discard image borders
|
||||
|
||||
ref = np.load(fetch('data/mssim_matlab_output.npz'))
|
||||
grad_matlab = ref['grad_matlab']
|
||||
mssim_matlab = float(ref['mssim_matlab'])
|
||||
|
||||
mssim, grad = structural_similarity(cam, cam_noisy, gaussian_weights=True,
|
||||
gradient=True,
|
||||
use_sample_covariance=False)
|
||||
|
||||
assert_almost_equal(mssim, mssim_matlab, decimal=3)
|
||||
|
||||
# check almost equal aside from object borders
|
||||
assert_array_almost_equal(grad_matlab[5:-5], grad[5:-5])
|
||||
|
||||
|
||||
def test_mssim_vs_legacy():
|
||||
# check that ssim with default options matches skimage 0.11 result
|
||||
mssim_skimage_0pt11 = 0.34192589699605191
|
||||
mssim = structural_similarity(cam, cam_noisy)
|
||||
assert_almost_equal(mssim, mssim_skimage_0pt11)
|
||||
|
||||
|
||||
def test_mssim_mixed_dtype():
|
||||
mssim = structural_similarity(cam, cam_noisy)
|
||||
with expected_warnings(['Inputs have mismatched dtype']):
|
||||
mssim_mixed = structural_similarity(cam, cam_noisy.astype(np.float32))
|
||||
assert_almost_equal(mssim, mssim_mixed)
|
||||
|
||||
# no warning when user supplies data_range
|
||||
mssim_mixed = structural_similarity(cam, cam_noisy.astype(np.float32),
|
||||
data_range=255)
|
||||
assert_almost_equal(mssim, mssim_mixed)
|
||||
|
||||
|
||||
def test_invalid_input():
|
||||
# size mismatch
|
||||
X = np.zeros((9, 9), dtype=np.double)
|
||||
Y = np.zeros((8, 8), dtype=np.double)
|
||||
with testing.raises(ValueError):
|
||||
structural_similarity(X, Y)
|
||||
# win_size exceeds image extent
|
||||
with testing.raises(ValueError):
|
||||
structural_similarity(X, X, win_size=X.shape[0] + 1)
|
||||
# some kwarg inputs must be non-negative
|
||||
with testing.raises(ValueError):
|
||||
structural_similarity(X, X, K1=-0.1)
|
||||
with testing.raises(ValueError):
|
||||
structural_similarity(X, X, K2=-0.1)
|
||||
with testing.raises(ValueError):
|
||||
structural_similarity(X, X, sigma=-1.0)
|
Loading…
Add table
Add a link
Reference in a new issue