update
This commit is contained in:
0
.CondaPkg/env/Lib/site-packages/skimage/metrics/tests/__init__.py
vendored
Normal file
0
.CondaPkg/env/Lib/site-packages/skimage/metrics/tests/__init__.py
vendored
Normal file
BIN
.CondaPkg/env/Lib/site-packages/skimage/metrics/tests/__pycache__/__init__.cpython-312.pyc
vendored
Normal file
BIN
.CondaPkg/env/Lib/site-packages/skimage/metrics/tests/__pycache__/__init__.cpython-312.pyc
vendored
Normal file
Binary file not shown.
Binary file not shown.
BIN
.CondaPkg/env/Lib/site-packages/skimage/metrics/tests/__pycache__/test_set_metrics.cpython-312.pyc
vendored
Normal file
BIN
.CondaPkg/env/Lib/site-packages/skimage/metrics/tests/__pycache__/test_set_metrics.cpython-312.pyc
vendored
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
60
.CondaPkg/env/Lib/site-packages/skimage/metrics/tests/test_segmentation_metrics.py
vendored
Normal file
60
.CondaPkg/env/Lib/site-packages/skimage/metrics/tests/test_segmentation_metrics.py
vendored
Normal file
@@ -0,0 +1,60 @@
|
||||
import numpy as np
|
||||
import pytest
|
||||
|
||||
from skimage.metrics import (
|
||||
adapted_rand_error,
|
||||
variation_of_information,
|
||||
contingency_table,
|
||||
)
|
||||
|
||||
from skimage._shared.testing import (
|
||||
assert_equal,
|
||||
assert_almost_equal,
|
||||
assert_array_equal,
|
||||
)
|
||||
|
||||
|
||||
def test_contingency_table():
|
||||
im_true = np.array([1, 2, 3, 4])
|
||||
im_test = np.array([1, 1, 8, 8])
|
||||
|
||||
table1 = np.array(
|
||||
[
|
||||
[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
|
||||
[0.0, 0.25, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
|
||||
[0.0, 0.25, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
|
||||
[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.25],
|
||||
[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.25],
|
||||
]
|
||||
)
|
||||
|
||||
sparse_table2 = contingency_table(im_true, im_test, normalize=True)
|
||||
table2 = sparse_table2.toarray()
|
||||
assert_array_equal(table1, table2)
|
||||
|
||||
|
||||
def test_vi():
|
||||
im_true = np.array([1, 2, 3, 4])
|
||||
im_test = np.array([1, 1, 8, 8])
|
||||
assert_equal(np.sum(variation_of_information(im_true, im_test)), 1)
|
||||
|
||||
|
||||
def test_vi_ignore_labels():
|
||||
im1 = np.array([[1, 0], [2, 3]], dtype='uint8')
|
||||
im2 = np.array([[1, 1], [1, 0]], dtype='uint8')
|
||||
|
||||
false_splits, false_merges = variation_of_information(im1, im2, ignore_labels=[0])
|
||||
assert (false_splits, false_merges) == (0, 2 / 3)
|
||||
|
||||
|
||||
def test_are():
|
||||
im_true = np.array([[2, 1], [1, 2]])
|
||||
im_test = np.array([[1, 2], [3, 1]])
|
||||
assert_almost_equal(adapted_rand_error(im_true, im_test), (0.3333333, 0.5, 1.0))
|
||||
assert_almost_equal(adapted_rand_error(im_true, im_test, alpha=0), (0, 0.5, 1.0))
|
||||
assert_almost_equal(adapted_rand_error(im_true, im_test, alpha=1), (0.5, 0.5, 1.0))
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
adapted_rand_error(im_true, im_test, alpha=1.01)
|
||||
with pytest.raises(ValueError):
|
||||
adapted_rand_error(im_true, im_test, alpha=-0.01)
|
||||
179
.CondaPkg/env/Lib/site-packages/skimage/metrics/tests/test_set_metrics.py
vendored
Normal file
179
.CondaPkg/env/Lib/site-packages/skimage/metrics/tests/test_set_metrics.py
vendored
Normal file
@@ -0,0 +1,179 @@
|
||||
import numpy as np
|
||||
import pytest
|
||||
from numpy.testing import assert_almost_equal, assert_array_equal
|
||||
from scipy.spatial import distance
|
||||
|
||||
from skimage._shared._warnings import expected_warnings
|
||||
from skimage.metrics import hausdorff_distance, hausdorff_pair
|
||||
|
||||
|
||||
def test_hausdorff_empty():
|
||||
empty = np.zeros((0, 2), dtype=bool)
|
||||
non_empty = np.zeros((3, 2), dtype=bool)
|
||||
assert hausdorff_distance(empty, non_empty) == 0.0 # standard Hausdorff
|
||||
assert (
|
||||
hausdorff_distance(empty, non_empty, method="modified") == 0.0
|
||||
) # modified Hausdorff
|
||||
with expected_warnings(["One or both of the images is empty"]):
|
||||
assert_array_equal(hausdorff_pair(empty, non_empty), [(), ()])
|
||||
assert hausdorff_distance(non_empty, empty) == 0.0 # standard Hausdorff
|
||||
assert (
|
||||
hausdorff_distance(non_empty, empty, method="modified") == 0.0
|
||||
) # modified Hausdorff
|
||||
with expected_warnings(["One or both of the images is empty"]):
|
||||
assert_array_equal(hausdorff_pair(non_empty, empty), [(), ()])
|
||||
assert hausdorff_distance(empty, non_empty) == 0.0 # standard Hausdorff
|
||||
assert (
|
||||
hausdorff_distance(empty, non_empty, method="modified") == 0.0
|
||||
) # modified Hausdorff
|
||||
with expected_warnings(["One or both of the images is empty"]):
|
||||
assert_array_equal(hausdorff_pair(empty, non_empty), [(), ()])
|
||||
|
||||
|
||||
def test_hausdorff_simple():
|
||||
points_a = (3, 0)
|
||||
points_b = (6, 0)
|
||||
shape = (7, 1)
|
||||
coords_a = np.zeros(shape, dtype=bool)
|
||||
coords_b = np.zeros(shape, dtype=bool)
|
||||
coords_a[points_a] = True
|
||||
coords_b[points_b] = True
|
||||
dist = np.sqrt(sum((ca - cb) ** 2 for ca, cb in zip(points_a, points_b)))
|
||||
d = distance.cdist([points_a], [points_b])
|
||||
dist_modified = max(np.mean(np.min(d, axis=0)), np.mean(np.min(d, axis=1)))
|
||||
assert_almost_equal(hausdorff_distance(coords_a, coords_b), dist)
|
||||
assert_array_equal(hausdorff_pair(coords_a, coords_b), (points_a, points_b))
|
||||
assert_almost_equal(
|
||||
hausdorff_distance(
|
||||
coords_a,
|
||||
coords_b,
|
||||
method="modified",
|
||||
),
|
||||
dist_modified,
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("points_a", [(0, 0), (3, 0), (1, 4), (4, 1)])
|
||||
@pytest.mark.parametrize("points_b", [(0, 0), (3, 0), (1, 4), (4, 1)])
|
||||
def test_hausdorff_region_single(points_a, points_b):
|
||||
shape = (5, 5)
|
||||
coords_a = np.zeros(shape, dtype=bool)
|
||||
coords_b = np.zeros(shape, dtype=bool)
|
||||
coords_a[points_a] = True
|
||||
coords_b[points_b] = True
|
||||
|
||||
dist = np.sqrt(sum((ca - cb) ** 2 for ca, cb in zip(points_a, points_b)))
|
||||
d = distance.cdist([points_a], [points_b])
|
||||
dist_modified = max(np.mean(np.min(d, axis=0)), np.mean(np.min(d, axis=1)))
|
||||
assert_almost_equal(hausdorff_distance(coords_a, coords_b), dist)
|
||||
assert_array_equal(hausdorff_pair(coords_a, coords_b), (points_a, points_b))
|
||||
assert_almost_equal(
|
||||
hausdorff_distance(coords_a, coords_b, method="modified"), dist_modified
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("points_a", [(5, 4), (4, 5), (3, 4), (4, 3)])
|
||||
@pytest.mark.parametrize("points_b", [(6, 4), (2, 6), (2, 4), (4, 0)])
|
||||
def test_hausdorff_region_different_points(points_a, points_b):
|
||||
shape = (7, 7)
|
||||
coords_a = np.zeros(shape, dtype=bool)
|
||||
coords_b = np.zeros(shape, dtype=bool)
|
||||
coords_a[points_a] = True
|
||||
coords_b[points_b] = True
|
||||
|
||||
dist = np.sqrt(sum((ca - cb) ** 2 for ca, cb in zip(points_a, points_b)))
|
||||
d = distance.cdist([points_a], [points_b])
|
||||
dist_modified = max(np.mean(np.min(d, axis=0)), np.mean(np.min(d, axis=1)))
|
||||
assert_almost_equal(hausdorff_distance(coords_a, coords_b), dist)
|
||||
assert_array_equal(hausdorff_pair(coords_a, coords_b), (points_a, points_b))
|
||||
assert_almost_equal(
|
||||
hausdorff_distance(coords_a, coords_b, method="modified"), dist_modified
|
||||
)
|
||||
|
||||
|
||||
def test_gallery():
|
||||
shape = (60, 60)
|
||||
|
||||
# Create a diamond-like shape where the four corners form the 1st set
|
||||
# of points
|
||||
x_diamond = 30
|
||||
y_diamond = 30
|
||||
r = 10
|
||||
|
||||
plt_x = [0, 1, 0, -1]
|
||||
plt_y = [1, 0, -1, 0]
|
||||
|
||||
set_ax = [(x_diamond + r * x) for x in plt_x]
|
||||
set_ay = [(y_diamond + r * y) for y in plt_y]
|
||||
|
||||
# Create a kite-like shape where the four corners form the 2nd set of
|
||||
# points
|
||||
x_kite = 30
|
||||
y_kite = 30
|
||||
x_r = 15
|
||||
y_r = 20
|
||||
|
||||
set_bx = [(x_kite + x_r * x) for x in plt_x]
|
||||
set_by = [(y_kite + y_r * y) for y in plt_y]
|
||||
|
||||
# Set up the data to compute the Hausdorff distance
|
||||
coords_a = np.zeros(shape, dtype=bool)
|
||||
coords_b = np.zeros(shape, dtype=bool)
|
||||
|
||||
for x, y in zip(set_ax, set_ay):
|
||||
coords_a[(x, y)] = True
|
||||
|
||||
for x, y in zip(set_bx, set_by):
|
||||
coords_b[(x, y)] = True
|
||||
|
||||
# Test the Hausdorff function on the coordinates
|
||||
# Should return 10, the distance between the furthest tip of the kite and
|
||||
# its closest point on the diamond, which is the furthest someone can make
|
||||
# you travel to encounter your nearest neighboring point on the other set.
|
||||
assert_almost_equal(hausdorff_distance(coords_a, coords_b), 10.0)
|
||||
|
||||
# There are two pairs of points ((30, 20), (30, 10) or (30, 40), (30, 50)),
|
||||
# that are Hausdorff distance apart. This tests for either of them.
|
||||
hd_points = hausdorff_pair(coords_a, coords_b)
|
||||
assert (
|
||||
np.equal(hd_points, ((30, 20), (30, 10))).all()
|
||||
or np.equal(hd_points, ((30, 40), (30, 50))).all()
|
||||
)
|
||||
|
||||
# Test the Modified Hausdorff function on the coordinates
|
||||
# Should return 7.5.
|
||||
assert_almost_equal(hausdorff_distance(coords_a, coords_b, method="modified"), 7.5)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("points_a", [(0, 0, 1), (0, 1, 0), (1, 0, 0)])
|
||||
@pytest.mark.parametrize("points_b", [(0, 0, 2), (0, 2, 0), (2, 0, 0)])
|
||||
def test_3d_hausdorff_region(points_a, points_b):
|
||||
shape = (3, 3, 3)
|
||||
coords_a = np.zeros(shape, dtype=bool)
|
||||
coords_b = np.zeros(shape, dtype=bool)
|
||||
coords_a[points_a] = True
|
||||
coords_b[points_b] = True
|
||||
|
||||
dist = np.sqrt(sum((ca - cb) ** 2 for ca, cb in zip(points_a, points_b)))
|
||||
d = distance.cdist([points_a], [points_b])
|
||||
dist_modified = max(np.mean(np.min(d, axis=0)), np.mean(np.min(d, axis=1)))
|
||||
assert_almost_equal(hausdorff_distance(coords_a, coords_b), dist)
|
||||
assert_array_equal(hausdorff_pair(coords_a, coords_b), (points_a, points_b))
|
||||
assert_almost_equal(
|
||||
hausdorff_distance(coords_a, coords_b, method="modified"), dist_modified
|
||||
)
|
||||
|
||||
|
||||
def test_hausdorff_metrics_match():
|
||||
# Test that Hausdorff distance is the Euclidean distance between Hausdorff
|
||||
# pair
|
||||
points_a = (3, 0)
|
||||
points_b = (6, 0)
|
||||
shape = (7, 1)
|
||||
coords_a = np.zeros(shape, dtype=bool)
|
||||
coords_b = np.zeros(shape, dtype=bool)
|
||||
coords_a[points_a] = True
|
||||
coords_b[points_b] = True
|
||||
assert_array_equal(hausdorff_pair(coords_a, coords_b), (points_a, points_b))
|
||||
euclidean_distance = distance.euclidean(points_a, points_b)
|
||||
assert_almost_equal(euclidean_distance, hausdorff_distance(coords_a, coords_b))
|
||||
146
.CondaPkg/env/Lib/site-packages/skimage/metrics/tests/test_simple_metrics.py
vendored
Normal file
146
.CondaPkg/env/Lib/site-packages/skimage/metrics/tests/test_simple_metrics.py
vendored
Normal file
@@ -0,0 +1,146 @@
|
||||
import numpy as np
|
||||
import pytest
|
||||
from numpy.testing import assert_equal, assert_almost_equal
|
||||
|
||||
from skimage import data
|
||||
from skimage._shared._warnings import expected_warnings
|
||||
from skimage.metrics import (
|
||||
peak_signal_noise_ratio,
|
||||
normalized_root_mse,
|
||||
mean_squared_error,
|
||||
normalized_mutual_information,
|
||||
)
|
||||
|
||||
|
||||
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)
|
||||
|
||||
|
||||
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/.
|
||||
|
||||
Notes
|
||||
-----
|
||||
To generate p_IPOL, we need a local copy of cam_noisy:
|
||||
|
||||
>>> from skimage import io
|
||||
>>> io.imsave('/tmp/cam_noisy.png', cam_noisy)
|
||||
|
||||
Then, we use the following command:
|
||||
$ ./imdiff -m psnr <path to camera.png>/camera.png /tmp/cam_noisy.png
|
||||
|
||||
Values for current data.camera() calculated by Gregory Lee on Sep, 2020.
|
||||
Available at:
|
||||
https://github.com/scikit-image/scikit-image/pull/4913#issuecomment-700653165
|
||||
"""
|
||||
p_IPOL = 22.409353363576034
|
||||
p = peak_signal_noise_ratio(cam, cam_noisy)
|
||||
assert_almost_equal(p, p_IPOL, decimal=4)
|
||||
|
||||
|
||||
@pytest.mark.parametrize('dtype', [np.float16, np.float32, np.float64])
|
||||
def test_PSNR_float(dtype):
|
||||
p_uint8 = peak_signal_noise_ratio(cam, cam_noisy)
|
||||
camf = (cam / 255.0).astype(dtype, copy=False)
|
||||
camf_noisy = (cam_noisy / 255.0).astype(dtype, copy=False)
|
||||
p_float64 = peak_signal_noise_ratio(camf, camf_noisy, data_range=1)
|
||||
assert p_float64.dtype == np.float64
|
||||
decimal = 3 if dtype == np.float16 else 5
|
||||
assert_almost_equal(p_uint8, p_float64, decimal=decimal)
|
||||
|
||||
# mixed precision inputs
|
||||
p_mixed = peak_signal_noise_ratio(
|
||||
cam / 255.0, np.float32(cam_noisy / 255.0), data_range=1
|
||||
)
|
||||
|
||||
assert_almost_equal(p_mixed, p_float64, decimal=decimal)
|
||||
|
||||
# mismatched dtype results in a warning if data_range is unspecified
|
||||
with expected_warnings(['Inputs have mismatched dtype']):
|
||||
p_mixed = peak_signal_noise_ratio(cam / 255.0, np.float32(cam_noisy / 255.0))
|
||||
assert_almost_equal(p_mixed, p_float64, decimal=decimal)
|
||||
|
||||
# mismatched dtype results in a warning if data_range is unspecified
|
||||
with expected_warnings(['Inputs have mismatched dtype']):
|
||||
p_mixed = peak_signal_noise_ratio(cam / 255.0, np.float32(cam_noisy / 255.0))
|
||||
assert_almost_equal(p_mixed, p_float64, decimal=decimal)
|
||||
|
||||
|
||||
def test_PSNR_errors():
|
||||
# shape mismatch
|
||||
with pytest.raises(ValueError):
|
||||
peak_signal_noise_ratio(cam, cam[:-1, :])
|
||||
|
||||
|
||||
@pytest.mark.parametrize('dtype', [np.float16, np.float32, np.float64])
|
||||
def test_NRMSE(dtype):
|
||||
x = np.ones(4, dtype=dtype)
|
||||
y = np.asarray([0.0, 2.0, 2.0, 2.0], dtype=dtype)
|
||||
nrmse = normalized_root_mse(y, x, normalization='mean')
|
||||
assert nrmse.dtype == np.float64
|
||||
assert_equal(nrmse, 1 / np.mean(y, dtype=np.float64))
|
||||
assert_equal(normalized_root_mse(y, x, normalization='euclidean'), 1 / np.sqrt(3))
|
||||
assert_equal(
|
||||
normalized_root_mse(y, x, normalization='min-max'), 1 / (y.max() - y.min())
|
||||
)
|
||||
|
||||
# mixed precision inputs are allowed
|
||||
assert_almost_equal(
|
||||
normalized_root_mse(y, np.float32(x), normalization='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)
|
||||
assert_almost_equal(
|
||||
mean_squared_error(cam, cam_noisy), mean_squared_error(camf, cam_noisyf)
|
||||
)
|
||||
assert_almost_equal(
|
||||
normalized_root_mse(cam, cam_noisy), normalized_root_mse(camf, cam_noisyf)
|
||||
)
|
||||
|
||||
|
||||
def test_NRMSE_errors():
|
||||
x = np.ones(4)
|
||||
# shape mismatch
|
||||
with pytest.raises(ValueError):
|
||||
normalized_root_mse(x[:-1], x)
|
||||
# invalid normalization name
|
||||
with pytest.raises(ValueError):
|
||||
normalized_root_mse(x, x, normalization='foo')
|
||||
|
||||
|
||||
def test_nmi():
|
||||
assert_almost_equal(normalized_mutual_information(cam, cam), 2)
|
||||
assert normalized_mutual_information(
|
||||
cam, cam_noisy
|
||||
) < normalized_mutual_information(cam, cam)
|
||||
|
||||
|
||||
def test_nmi_different_sizes():
|
||||
assert normalized_mutual_information(cam[:, :400], cam[:400, :]) > 1
|
||||
|
||||
|
||||
@pytest.mark.parametrize('dtype', [np.float16, np.float32, np.float64])
|
||||
def test_nmi_random(dtype):
|
||||
rng = np.random.default_rng()
|
||||
random1 = rng.random((100, 100)).astype(dtype)
|
||||
random2 = rng.random((100, 100)).astype(dtype)
|
||||
nmi = normalized_mutual_information(random1, random2, bins=10)
|
||||
assert nmi.dtype == np.float64
|
||||
assert_almost_equal(nmi, 1, decimal=2)
|
||||
|
||||
|
||||
def test_nmi_random_3d():
|
||||
random1, random2 = np.random.random((2, 10, 100, 100))
|
||||
assert_almost_equal(
|
||||
normalized_mutual_information(random1, random2, bins=10),
|
||||
1,
|
||||
decimal=2,
|
||||
)
|
||||
277
.CondaPkg/env/Lib/site-packages/skimage/metrics/tests/test_structural_similarity.py
vendored
Normal file
277
.CondaPkg/env/Lib/site-packages/skimage/metrics/tests/test_structural_similarity.py
vendored
Normal file
@@ -0,0 +1,277 @@
|
||||
import numpy as np
|
||||
import pytest
|
||||
from numpy.testing import assert_equal, assert_almost_equal
|
||||
|
||||
from skimage import data
|
||||
from skimage._shared._warnings import expected_warnings
|
||||
from skimage._shared.utils import _supported_float_type
|
||||
from skimage.metrics import structural_similarity
|
||||
|
||||
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)
|
||||
|
||||
# structural_similarity of image with itself should be 1.0
|
||||
assert_equal(structural_similarity(X, X), 1.0)
|
||||
|
||||
|
||||
# FIXME: 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
|
||||
@pytest.mark.parametrize('seed', [1, 2, 3, 5, 8, 13])
|
||||
@pytest.mark.parametrize('dtype', [np.float16, np.float32, np.float64])
|
||||
def test_structural_similarity_grad(seed, dtype):
|
||||
N = 60
|
||||
# FIXME: 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.
|
||||
rng = np.random.default_rng(seed)
|
||||
X = rng.random((N, N)).astype(dtype, copy=False) * 255
|
||||
Y = rng.random((N, N)).astype(dtype, copy=False) * 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 s.dtype == _supported_float_type(dtype)
|
||||
assert grad.dtype == _supported_float_type(dtype)
|
||||
assert np.all(grad < 0.05)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
'dtype', [np.uint8, np.int32, np.float16, np.float32, np.float64]
|
||||
)
|
||||
def test_structural_similarity_dtype(dtype):
|
||||
N = 30
|
||||
X = np.random.rand(N, N)
|
||||
Y = np.random.rand(N, N)
|
||||
if np.dtype(dtype).kind in 'iub':
|
||||
data_range = 255.0
|
||||
X = (X * 255).astype(np.uint8)
|
||||
Y = (X * 255).astype(np.uint8)
|
||||
else:
|
||||
data_range = 1.0
|
||||
X = X.astype(dtype, copy=False)
|
||||
Y = Y.astype(dtype, copy=False)
|
||||
|
||||
S1 = structural_similarity(X, Y, data_range=data_range)
|
||||
assert S1.dtype == np.float64
|
||||
|
||||
assert S1 < 0.1
|
||||
|
||||
|
||||
@pytest.mark.parametrize('channel_axis', [0, 1, 2, -1])
|
||||
def test_structural_similarity_multichannel(channel_axis):
|
||||
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))
|
||||
|
||||
# move channels from last position to specified channel_axis
|
||||
Xc, Yc = (np.moveaxis(_arr, -1, channel_axis) for _arr in (Xc, Yc))
|
||||
|
||||
S2 = structural_similarity(Xc, Yc, channel_axis=channel_axis, win_size=3)
|
||||
assert_almost_equal(S1, S2)
|
||||
|
||||
# full case should return an image as well
|
||||
m, S3 = structural_similarity(Xc, Yc, channel_axis=channel_axis, full=True)
|
||||
assert_equal(S3.shape, Xc.shape)
|
||||
|
||||
# gradient case
|
||||
m, grad = structural_similarity(Xc, Yc, channel_axis=channel_axis, gradient=True)
|
||||
assert_equal(grad.shape, Xc.shape)
|
||||
|
||||
# full and gradient case
|
||||
m, grad, S3 = structural_similarity(
|
||||
Xc, Yc, channel_axis=channel_axis, 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 pytest.raises(ValueError):
|
||||
structural_similarity(Xc, Yc, win_size=7, channel_axis=None)
|
||||
|
||||
|
||||
@pytest.mark.parametrize('dtype', [np.uint8, np.float32, np.float64])
|
||||
def test_structural_similarity_nD(dtype):
|
||||
# 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(dtype)
|
||||
Y = (np.random.rand(*xsize) * 255).astype(dtype)
|
||||
|
||||
mssim = structural_similarity(X, Y, win_size=3, data_range=255.0)
|
||||
assert mssim.dtype == np.float64
|
||||
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, channel_axis=-1)
|
||||
mssim_sep = [
|
||||
structural_similarity(Yc[..., c], Xc[..., c]) for c in range(Xc.shape[-1])
|
||||
]
|
||||
assert_almost_equal(mssim, np.mean(mssim_sep))
|
||||
|
||||
# structural_similarity of image with itself should be 1.0
|
||||
assert_equal(structural_similarity(Xc, Xc, channel_axis=-1), 1.0)
|
||||
|
||||
|
||||
def test_gaussian_structural_similarity_vs_IPOL():
|
||||
"""Tests vs. imdiff result from the following IPOL article and code:
|
||||
https://www.ipol.im/pub/art/2011/g_lmii/.
|
||||
|
||||
Notes
|
||||
-----
|
||||
To generate mssim_IPOL, we need a local copy of cam_noisy:
|
||||
|
||||
>>> from skimage import io
|
||||
>>> io.imsave('/tmp/cam_noisy.png', cam_noisy)
|
||||
|
||||
Then, we use the following command:
|
||||
$ ./imdiff -m mssim <path to camera.png>/camera.png /tmp/cam_noisy.png
|
||||
|
||||
Values for current data.camera() calculated by Gregory Lee on Sep, 2020.
|
||||
Available at:
|
||||
https://github.com/scikit-image/scikit-image/pull/4913#issuecomment-700653165
|
||||
"""
|
||||
mssim_IPOL = 0.357959091663361
|
||||
assert cam.dtype == np.uint8
|
||||
assert cam_noisy.dtype == np.uint8
|
||||
mssim = structural_similarity(
|
||||
cam, cam_noisy, gaussian_weights=True, use_sample_covariance=False
|
||||
)
|
||||
assert_almost_equal(mssim, mssim_IPOL, decimal=3)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
'dtype', [np.uint8, np.int32, np.float16, np.float32, np.float64]
|
||||
)
|
||||
def test_mssim_vs_legacy(dtype):
|
||||
# check that ssim with default options matches skimage 0.17 result
|
||||
mssim_skimage_0pt17 = 0.3674518327910367
|
||||
assert cam.dtype == np.uint8
|
||||
assert cam_noisy.dtype == np.uint8
|
||||
mssim = structural_similarity(
|
||||
cam.astype(dtype), cam_noisy.astype(dtype), data_range=255
|
||||
)
|
||||
assert_almost_equal(mssim, mssim_skimage_0pt17)
|
||||
|
||||
|
||||
def test_ssim_warns_about_data_range():
|
||||
mssim = structural_similarity(cam, cam_noisy)
|
||||
with expected_warnings(['Setting data_range based on im1.dtype']):
|
||||
mssim_uint16 = structural_similarity(
|
||||
cam.astype(np.uint16), cam_noisy.astype(np.uint16)
|
||||
)
|
||||
# The value computed for mssim_uint16 is wrong, because the
|
||||
# dtype of im1 led to infer an erroneous data_range. The user
|
||||
# is getting a warning about avoiding mistakes.
|
||||
assert mssim_uint16 > 0.99
|
||||
|
||||
with expected_warnings(
|
||||
['Setting data_range based on im1.dtype', 'Inputs have mismatched dtypes']
|
||||
):
|
||||
mssim_mixed = structural_similarity(cam, cam_noisy.astype(np.int32))
|
||||
|
||||
# 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)
|
||||
|
||||
|
||||
@pytest.mark.parametrize('dtype', [np.float16, np.float32, np.float64])
|
||||
def test_structural_similarity_small_image(dtype):
|
||||
X = np.zeros((5, 5), dtype=dtype)
|
||||
# structural_similarity can be computed for small images if win_size is
|
||||
# a) odd and b) less than or equal to the images' smaller side
|
||||
assert_equal(structural_similarity(X, X, win_size=3, data_range=1.0), 1.0)
|
||||
assert_equal(structural_similarity(X, X, win_size=5, data_range=1.0), 1.0)
|
||||
# structural_similarity errors for small images if user doesn't specify
|
||||
# win_size
|
||||
with pytest.raises(ValueError):
|
||||
structural_similarity(X, X)
|
||||
|
||||
|
||||
@pytest.mark.parametrize('dtype', [np.float16, np.float32, np.float64])
|
||||
def test_structural_similarity_errors_on_float_without_data_range(dtype):
|
||||
X = np.zeros((64, 64), dtype=dtype)
|
||||
with pytest.raises(ValueError):
|
||||
structural_similarity(X, X)
|
||||
|
||||
|
||||
def test_invalid_input():
|
||||
# size mismatch
|
||||
X = np.zeros((9, 9), dtype=np.float64)
|
||||
Y = np.zeros((8, 8), dtype=np.float64)
|
||||
with pytest.raises(ValueError):
|
||||
structural_similarity(X, Y)
|
||||
# win_size exceeds image extent
|
||||
with pytest.raises(ValueError):
|
||||
structural_similarity(X, X, win_size=X.shape[0] + 1)
|
||||
# some kwarg inputs must be non-negative
|
||||
with pytest.raises(ValueError):
|
||||
structural_similarity(X, X, K1=-0.1)
|
||||
with pytest.raises(ValueError):
|
||||
structural_similarity(X, X, K2=-0.1)
|
||||
with pytest.raises(ValueError):
|
||||
structural_similarity(X, X, sigma=-1.0)
|
||||
Reference in New Issue
Block a user