Fixed database typo and removed unnecessary class identifier.

This commit is contained in:
Batuhan Berk Başoğlu 2020-10-14 10:10:37 -04:00
parent 00ad49a143
commit 45fb349a7d
5098 changed files with 952558 additions and 85 deletions

View file

@ -0,0 +1,9 @@
from ..._shared.testing import setup_test, teardown_test
def setup():
setup_test()
def teardown():
teardown_test()

View file

@ -0,0 +1,18 @@
import numpy as np
from skimage.transform import frt2, ifrt2
def test_frt():
SIZE = 59
try:
import sympy.ntheory as sn
assert sn.isprime(SIZE) == True
except ImportError:
pass
# Generate a test image
L = np.tri(SIZE, dtype=np.int32) + np.tri(SIZE, dtype=np.int32)[::-1]
f = frt2(L)
fi = ifrt2(f)
assert len(np.nonzero(L - fi)[0]) == 0

View file

@ -0,0 +1,523 @@
import numpy as np
import re
from skimage.transform._geometric import GeometricTransform
from skimage.transform import (estimate_transform, matrix_transform,
EuclideanTransform, SimilarityTransform,
AffineTransform, FundamentalMatrixTransform,
EssentialMatrixTransform, ProjectiveTransform,
PolynomialTransform, PiecewiseAffineTransform)
from skimage._shared import testing
from skimage._shared.testing import assert_equal, assert_almost_equal
import textwrap
SRC = np.array([
[-12.3705, -10.5075],
[-10.7865, 15.4305],
[8.6985, 10.8675],
[11.4975, -9.5715],
[7.8435, 7.4835],
[-5.3325, 6.5025],
[6.7905, -6.3765],
[-6.1695, -0.8235],
])
DST = np.array([
[0, 0],
[0, 5800],
[4900, 5800],
[4900, 0],
[4479, 4580],
[1176, 3660],
[3754, 790],
[1024, 1931],
])
def test_estimate_transform():
for tform in ('euclidean', 'similarity', 'affine', 'projective',
'polynomial'):
estimate_transform(tform, SRC[:2, :], DST[:2, :])
with testing.raises(ValueError):
estimate_transform('foobar', SRC[:2, :], DST[:2, :])
def test_matrix_transform():
tform = AffineTransform(scale=(0.1, 0.5), rotation=2)
assert_equal(tform(SRC), matrix_transform(SRC, tform.params))
def test_euclidean_estimation():
# exact solution
tform = estimate_transform('euclidean', SRC[:2, :], SRC[:2, :] + 10)
assert_almost_equal(tform(SRC[:2, :]), SRC[:2, :] + 10)
assert_almost_equal(tform.params[0, 0], tform.params[1, 1])
assert_almost_equal(tform.params[0, 1], - tform.params[1, 0])
# over-determined
tform2 = estimate_transform('euclidean', SRC, DST)
assert_almost_equal(tform2.inverse(tform2(SRC)), SRC)
assert_almost_equal(tform2.params[0, 0], tform2.params[1, 1])
assert_almost_equal(tform2.params[0, 1], - tform2.params[1, 0])
# via estimate method
tform3 = EuclideanTransform()
tform3.estimate(SRC, DST)
assert_almost_equal(tform3.params, tform2.params)
def test_euclidean_init():
# init with implicit parameters
rotation = 1
translation = (1, 1)
tform = EuclideanTransform(rotation=rotation, translation=translation)
assert_almost_equal(tform.rotation, rotation)
assert_almost_equal(tform.translation, translation)
# init with transformation matrix
tform2 = EuclideanTransform(tform.params)
assert_almost_equal(tform2.rotation, rotation)
assert_almost_equal(tform2.translation, translation)
# test special case for scale if rotation=0
rotation = 0
translation = (1, 1)
tform = EuclideanTransform(rotation=rotation, translation=translation)
assert_almost_equal(tform.rotation, rotation)
assert_almost_equal(tform.translation, translation)
# test special case for scale if rotation=90deg
rotation = np.pi / 2
translation = (1, 1)
tform = EuclideanTransform(rotation=rotation, translation=translation)
assert_almost_equal(tform.rotation, rotation)
assert_almost_equal(tform.translation, translation)
def test_similarity_estimation():
# exact solution
tform = estimate_transform('similarity', SRC[:2, :], DST[:2, :])
assert_almost_equal(tform(SRC[:2, :]), DST[:2, :])
assert_almost_equal(tform.params[0, 0], tform.params[1, 1])
assert_almost_equal(tform.params[0, 1], - tform.params[1, 0])
# over-determined
tform2 = estimate_transform('similarity', SRC, DST)
assert_almost_equal(tform2.inverse(tform2(SRC)), SRC)
assert_almost_equal(tform2.params[0, 0], tform2.params[1, 1])
assert_almost_equal(tform2.params[0, 1], - tform2.params[1, 0])
# via estimate method
tform3 = SimilarityTransform()
tform3.estimate(SRC, DST)
assert_almost_equal(tform3.params, tform2.params)
def test_similarity_init():
# init with implicit parameters
scale = 0.1
rotation = 1
translation = (1, 1)
tform = SimilarityTransform(scale=scale, rotation=rotation,
translation=translation)
assert_almost_equal(tform.scale, scale)
assert_almost_equal(tform.rotation, rotation)
assert_almost_equal(tform.translation, translation)
# init with transformation matrix
tform2 = SimilarityTransform(tform.params)
assert_almost_equal(tform2.scale, scale)
assert_almost_equal(tform2.rotation, rotation)
assert_almost_equal(tform2.translation, translation)
# test special case for scale if rotation=0
scale = 0.1
rotation = 0
translation = (1, 1)
tform = SimilarityTransform(scale=scale, rotation=rotation,
translation=translation)
assert_almost_equal(tform.scale, scale)
assert_almost_equal(tform.rotation, rotation)
assert_almost_equal(tform.translation, translation)
# test special case for scale if rotation=90deg
scale = 0.1
rotation = np.pi / 2
translation = (1, 1)
tform = SimilarityTransform(scale=scale, rotation=rotation,
translation=translation)
assert_almost_equal(tform.scale, scale)
assert_almost_equal(tform.rotation, rotation)
assert_almost_equal(tform.translation, translation)
# test special case for scale where the rotation isn't exactly 90deg,
# but very close
scale = 1.0
rotation = np.pi / 2
translation = (0, 0)
params = np.array([[0, -1, 1.33226763e-15],
[1, 2.22044605e-16, -1.33226763e-15],
[0, 0, 1]])
tform = SimilarityTransform(params)
assert_almost_equal(tform.scale, scale)
assert_almost_equal(tform.rotation, rotation)
assert_almost_equal(tform.translation, translation)
def test_affine_estimation():
# exact solution
tform = estimate_transform('affine', SRC[:3, :], DST[:3, :])
assert_almost_equal(tform(SRC[:3, :]), DST[:3, :])
# over-determined
tform2 = estimate_transform('affine', SRC, DST)
assert_almost_equal(tform2.inverse(tform2(SRC)), SRC)
# via estimate method
tform3 = AffineTransform()
tform3.estimate(SRC, DST)
assert_almost_equal(tform3.params, tform2.params)
def test_affine_init():
# init with implicit parameters
scale = (0.1, 0.13)
rotation = 1
shear = 0.1
translation = (1, 1)
tform = AffineTransform(scale=scale, rotation=rotation, shear=shear,
translation=translation)
assert_almost_equal(tform.scale, scale)
assert_almost_equal(tform.rotation, rotation)
assert_almost_equal(tform.shear, shear)
assert_almost_equal(tform.translation, translation)
# init with transformation matrix
tform2 = AffineTransform(tform.params)
assert_almost_equal(tform2.scale, scale)
assert_almost_equal(tform2.rotation, rotation)
assert_almost_equal(tform2.shear, shear)
assert_almost_equal(tform2.translation, translation)
# scalar vs. tuple scale arguments
assert_almost_equal(AffineTransform(scale=0.5).scale, AffineTransform(scale=(0.5, 0.5)).scale)
def test_piecewise_affine():
tform = PiecewiseAffineTransform()
tform.estimate(SRC, DST)
# make sure each single affine transform is exactly estimated
assert_almost_equal(tform(SRC), DST)
assert_almost_equal(tform.inverse(DST), SRC)
def test_fundamental_matrix_estimation():
src = np.array([1.839035, 1.924743, 0.543582, 0.375221,
0.473240, 0.142522, 0.964910, 0.598376,
0.102388, 0.140092, 15.994343, 9.622164,
0.285901, 0.430055, 0.091150, 0.254594]).reshape(-1, 2)
dst = np.array([1.002114, 1.129644, 1.521742, 1.846002,
1.084332, 0.275134, 0.293328, 0.588992,
0.839509, 0.087290, 1.779735, 1.116857,
0.878616, 0.602447, 0.642616, 1.028681]).reshape(-1, 2)
tform = estimate_transform('fundamental', src, dst)
# Reference values obtained using COLMAP SfM library.
tform_ref = np.array([[-0.217859, 0.419282, -0.0343075],
[-0.0717941, 0.0451643, 0.0216073],
[0.248062, -0.429478, 0.0221019]])
assert_almost_equal(tform.params, tform_ref, 6)
def test_fundamental_matrix_residuals():
essential_matrix_tform = EssentialMatrixTransform(
rotation=np.eye(3), translation=np.array([1, 0, 0]))
tform = FundamentalMatrixTransform()
tform.params = essential_matrix_tform.params
src = np.array([[0, 0], [0, 0], [0, 0]])
dst = np.array([[2, 0], [2, 1], [2, 2]])
assert_almost_equal(tform.residuals(src, dst)**2, [0, 0.5, 2])
def test_fundamental_matrix_forward():
essential_matrix_tform = EssentialMatrixTransform(
rotation=np.eye(3), translation=np.array([1, 0, 0]))
tform = FundamentalMatrixTransform()
tform.params = essential_matrix_tform.params
src = np.array([[0, 0], [0, 1], [1, 1]])
assert_almost_equal(tform(src), [[0, -1, 0], [0, -1, 1], [0, -1, 1]])
def test_fundamental_matrix_inverse():
essential_matrix_tform = EssentialMatrixTransform(
rotation=np.eye(3), translation=np.array([1, 0, 0]))
tform = FundamentalMatrixTransform()
tform.params = essential_matrix_tform.params
src = np.array([[0, 0], [0, 1], [1, 1]])
assert_almost_equal(tform.inverse(src),
[[0, 1, 0], [0, 1, -1], [0, 1, -1]])
def test_essential_matrix_init():
tform = EssentialMatrixTransform(rotation=np.eye(3),
translation=np.array([0, 0, 1]))
assert_equal(tform.params,
np.array([0, -1, 0, 1, 0, 0, 0, 0, 0]).reshape(3, 3))
def test_essential_matrix_estimation():
src = np.array([1.839035, 1.924743, 0.543582, 0.375221,
0.473240, 0.142522, 0.964910, 0.598376,
0.102388, 0.140092, 15.994343, 9.622164,
0.285901, 0.430055, 0.091150, 0.254594]).reshape(-1, 2)
dst = np.array([1.002114, 1.129644, 1.521742, 1.846002,
1.084332, 0.275134, 0.293328, 0.588992,
0.839509, 0.087290, 1.779735, 1.116857,
0.878616, 0.602447, 0.642616, 1.028681]).reshape(-1, 2)
tform = estimate_transform('essential', src, dst)
# Reference values obtained using COLMAP SfM library.
tform_ref = np.array([[-0.0811666, 0.255449, -0.0478999],
[-0.192392, -0.0531675, 0.119547],
[0.177784, -0.22008, -0.015203]])
assert_almost_equal(tform.params, tform_ref, 6)
def test_essential_matrix_forward():
tform = EssentialMatrixTransform(rotation=np.eye(3),
translation=np.array([1, 0, 0]))
src = np.array([[0, 0], [0, 1], [1, 1]])
assert_almost_equal(tform(src), [[0, -1, 0], [0, -1, 1], [0, -1, 1]])
def test_essential_matrix_inverse():
tform = EssentialMatrixTransform(rotation=np.eye(3),
translation=np.array([1, 0, 0]))
src = np.array([[0, 0], [0, 1], [1, 1]])
assert_almost_equal(tform.inverse(src),
[[0, 1, 0], [0, 1, -1], [0, 1, -1]])
def test_essential_matrix_residuals():
tform = EssentialMatrixTransform(rotation=np.eye(3),
translation=np.array([1, 0, 0]))
src = np.array([[0, 0], [0, 0], [0, 0]])
dst = np.array([[2, 0], [2, 1], [2, 2]])
assert_almost_equal(tform.residuals(src, dst)**2, [0, 0.5, 2])
def test_projective_estimation():
# exact solution
tform = estimate_transform('projective', SRC[:4, :], DST[:4, :])
assert_almost_equal(tform(SRC[:4, :]), DST[:4, :])
# over-determined
tform2 = estimate_transform('projective', SRC, DST)
assert_almost_equal(tform2.inverse(tform2(SRC)), SRC)
# via estimate method
tform3 = ProjectiveTransform()
tform3.estimate(SRC, DST)
assert_almost_equal(tform3.params, tform2.params)
def test_projective_init():
tform = estimate_transform('projective', SRC, DST)
# init with transformation matrix
tform2 = ProjectiveTransform(tform.params)
assert_almost_equal(tform2.params, tform.params)
def test_polynomial_estimation():
# over-determined
tform = estimate_transform('polynomial', SRC, DST, order=10)
assert_almost_equal(tform(SRC), DST, 6)
# via estimate method
tform2 = PolynomialTransform()
tform2.estimate(SRC, DST, order=10)
assert_almost_equal(tform2.params, tform.params)
def test_polynomial_init():
tform = estimate_transform('polynomial', SRC, DST, order=10)
# init with transformation parameters
tform2 = PolynomialTransform(tform.params)
assert_almost_equal(tform2.params, tform.params)
def test_polynomial_default_order():
tform = estimate_transform('polynomial', SRC, DST)
tform2 = estimate_transform('polynomial', SRC, DST, order=2)
assert_almost_equal(tform2.params, tform.params)
def test_polynomial_inverse():
with testing.raises(Exception):
PolynomialTransform().inverse(0)
def test_union():
tform1 = SimilarityTransform(scale=0.1, rotation=0.3)
tform2 = SimilarityTransform(scale=0.1, rotation=0.9)
tform3 = SimilarityTransform(scale=0.1 ** 2, rotation=0.3 + 0.9)
tform = tform1 + tform2
assert_almost_equal(tform.params, tform3.params)
tform1 = AffineTransform(scale=(0.1, 0.1), rotation=0.3)
tform2 = SimilarityTransform(scale=0.1, rotation=0.9)
tform3 = SimilarityTransform(scale=0.1 ** 2, rotation=0.3 + 0.9)
tform = tform1 + tform2
assert_almost_equal(tform.params, tform3.params)
assert tform.__class__ == ProjectiveTransform
tform = AffineTransform(scale=(0.1, 0.1), rotation=0.3)
assert_almost_equal((tform + tform.inverse).params, np.eye(3))
tform1 = SimilarityTransform(scale=0.1, rotation=0.3)
tform2 = SimilarityTransform(scale=0.1, rotation=0.9)
tform3 = SimilarityTransform(scale=0.1 * 1/0.1, rotation=0.3 - 0.9)
tform = tform1 + tform2.inverse
assert_almost_equal(tform.params, tform3.params)
def test_union_differing_types():
tform1 = SimilarityTransform()
tform2 = PolynomialTransform()
with testing.raises(TypeError):
tform1.__add__(tform2)
def test_geometric_tform():
tform = GeometricTransform()
with testing.raises(NotImplementedError):
tform(0)
with testing.raises(NotImplementedError):
tform.inverse(0)
with testing.raises(NotImplementedError):
tform.__add__(0)
# See gh-3926 for discussion details
for i in range(20):
# Generate random Homography
H = np.random.rand(3, 3) * 100
H[2, H[2] == 0] += np.finfo(float).eps
H /= H[2, 2]
# Craft some src coords
src = np.array([
[(H[2, 1] + 1) / -H[2, 0], 1],
[1, (H[2, 0] + 1) / -H[2, 1]],
[1, 1],
])
# Prior to gh-3926, under the above circumstances,
# destination coordinates could be returned with nan/inf values.
tform = ProjectiveTransform(H) # Construct the transform
dst = tform(src) # Obtain the dst coords
# Ensure dst coords are finite numeric values
assert(np.isfinite(dst).all())
def test_invalid_input():
with testing.raises(ValueError):
ProjectiveTransform(np.zeros((2, 3)))
with testing.raises(ValueError):
AffineTransform(np.zeros((2, 3)))
with testing.raises(ValueError):
SimilarityTransform(np.zeros((2, 3)))
with testing.raises(ValueError):
EuclideanTransform(np.zeros((2, 3)))
with testing.raises(ValueError):
AffineTransform(matrix=np.zeros((2, 3)), scale=1)
with testing.raises(ValueError):
SimilarityTransform(matrix=np.zeros((2, 3)), scale=1)
with testing.raises(ValueError):
EuclideanTransform(
matrix=np.zeros((2, 3)), translation=(0, 0))
with testing.raises(ValueError):
PolynomialTransform(np.zeros((3, 3)))
with testing.raises(ValueError):
FundamentalMatrixTransform(matrix=np.zeros((3, 2)))
with testing.raises(ValueError):
EssentialMatrixTransform(matrix=np.zeros((3, 2)))
with testing.raises(ValueError):
EssentialMatrixTransform(rotation=np.zeros((3, 2)))
with testing.raises(ValueError):
EssentialMatrixTransform(
rotation=np.zeros((3, 3)))
with testing.raises(ValueError):
EssentialMatrixTransform(
rotation=np.eye(3))
with testing.raises(ValueError):
EssentialMatrixTransform(rotation=np.eye(3),
translation=np.zeros((2,)))
with testing.raises(ValueError):
EssentialMatrixTransform(rotation=np.eye(3),
translation=np.zeros((2,)))
with testing.raises(ValueError):
EssentialMatrixTransform(
rotation=np.eye(3), translation=np.zeros((3,)))
def test_degenerate():
src = dst = np.zeros((10, 2))
tform = SimilarityTransform()
tform.estimate(src, dst)
assert np.all(np.isnan(tform.params))
tform = AffineTransform()
tform.estimate(src, dst)
assert np.all(np.isnan(tform.params))
tform = ProjectiveTransform()
tform.estimate(src, dst)
assert np.all(np.isnan(tform.params))
# See gh-3926 for discussion details
tform = ProjectiveTransform()
for i in range(20):
# Some random coordinates
src = np.random.rand(4, 2) * 100
dst = np.random.rand(4, 2) * 100
# Degenerate the case by arranging points on a single line
src[:, 1] = np.random.rand()
# Prior to gh-3926, under the above circumstances,
# a transform could be returned with nan values.
assert(not tform.estimate(src, dst) or np.isfinite(tform.params).all())
def test_projective_repr():
tform = ProjectiveTransform()
want = re.escape(textwrap.dedent(
'''
<ProjectiveTransform(matrix=
[[1., 0., 0.],
[0., 1., 0.],
[0., 0., 1.]]) at
''').strip()) + ' 0x[a-f0-9]+' + re.escape('>')
# Hack the escaped regex to allow whitespace before each number for
# compatibility with different numpy versions.
want = want.replace('0\\.', ' *0\\.')
want = want.replace('1\\.', ' *1\\.')
assert re.match(want, repr(tform))
def test_projective_str():
tform = ProjectiveTransform()
want = re.escape(textwrap.dedent(
'''
<ProjectiveTransform(matrix=
[[1., 0., 0.],
[0., 1., 0.],
[0., 0., 1.]])>
''').strip())
# Hack the escaped regex to allow whitespace before each number for
# compatibility with different numpy versions.
want = want.replace('0\\.', ' *0\\.')
want = want.replace('1\\.', ' *1\\.')
print(want)
assert re.match(want, str(tform))

View file

@ -0,0 +1,549 @@
import numpy as np
from skimage import transform
from skimage import data
from skimage.feature import canny
from skimage.draw import line, circle_perimeter, ellipse_perimeter
from skimage._shared import testing
from skimage._shared.testing import (assert_almost_equal, assert_equal,
test_parallel)
@test_parallel()
def test_hough_line():
# Generate a test image
img = np.zeros((100, 150), dtype=int)
rr, cc = line(60, 130, 80, 10)
img[rr, cc] = 1
out, angles, d = transform.hough_line(img)
y, x = np.where(out == out.max())
dist = d[y[0]]
theta = angles[x[0]]
assert_almost_equal(dist, 80.723, 1)
assert_almost_equal(theta, 1.41, 1)
def test_hough_line_angles():
img = np.zeros((10, 10))
img[0, 0] = 1
out, angles, d = transform.hough_line(img, np.linspace(0, 360, 10))
assert_equal(len(angles), 10)
def test_hough_line_bad_input():
img = np.zeros(100)
img[10] = 1
# Expected error, img must be 2D
with testing.raises(ValueError):
transform.hough_line(img, np.linspace(0, 360, 10))
def test_probabilistic_hough():
# Generate a test image
img = np.zeros((100, 100), dtype=int)
for i in range(25, 75):
img[100 - i, i] = 100
img[i, i] = 100
# decrease default theta sampling because similar orientations may confuse
# as mentioned in article of Galambos et al
theta = np.linspace(0, np.pi, 45)
lines = transform.probabilistic_hough_line(
img, threshold=10, line_length=10, line_gap=1, theta=theta)
# sort the lines according to the x-axis
sorted_lines = []
for line in lines:
line = list(line)
line.sort(key=lambda x: x[0])
sorted_lines.append(line)
assert([(25, 75), (74, 26)] in sorted_lines)
assert([(25, 25), (74, 74)] in sorted_lines)
# Execute with default theta
transform.probabilistic_hough_line(img, line_length=10, line_gap=3)
def test_probabilistic_hough_seed():
# Load image that is likely to give a randomly varying number of lines
image = data.checkerboard()
# Use constant seed to ensure a deterministic output
lines = transform.probabilistic_hough_line(image, threshold=50,
line_length=50, line_gap=1,
seed=1234)
assert len(lines) == 65
def test_probabilistic_hough_bad_input():
img = np.zeros(100)
img[10] = 1
# Expected error, img must be 2D
with testing.raises(ValueError):
transform.probabilistic_hough_line(img)
def test_hough_line_peaks():
img = np.zeros((100, 150), dtype=int)
rr, cc = line(60, 130, 80, 10)
img[rr, cc] = 1
out, angles, d = transform.hough_line(img)
out, theta, dist = transform.hough_line_peaks(out, angles, d)
assert_equal(len(dist), 1)
assert_almost_equal(dist[0], 80.723, 1)
assert_almost_equal(theta[0], 1.41, 1)
def test_hough_line_peaks_ordered():
# Regression test per PR #1421
testim = np.zeros((256, 64), dtype=np.bool)
testim[50:100, 20] = True
testim[85:200, 25] = True
testim[15:35, 50] = True
testim[1:-1, 58] = True
hough_space, angles, dists = transform.hough_line(testim)
hspace, _, _ = transform.hough_line_peaks(hough_space, angles, dists)
assert hspace[0] > hspace[1]
def test_hough_line_peaks_dist():
img = np.zeros((100, 100), dtype=np.bool_)
img[:, 30] = True
img[:, 40] = True
hspace, angles, dists = transform.hough_line(img)
assert len(transform.hough_line_peaks(hspace, angles, dists,
min_distance=5)[0]) == 2
assert len(transform.hough_line_peaks(hspace, angles, dists,
min_distance=15)[0]) == 1
def test_hough_line_peaks_angle():
check_hough_line_peaks_angle()
def check_hough_line_peaks_angle():
img = np.zeros((100, 100), dtype=np.bool_)
img[:, 0] = True
img[0, :] = True
hspace, angles, dists = transform.hough_line(img)
assert len(transform.hough_line_peaks(hspace, angles, dists,
min_angle=45)[0]) == 2
assert len(transform.hough_line_peaks(hspace, angles, dists,
min_angle=90)[0]) == 1
theta = np.linspace(0, np.pi, 100)
hspace, angles, dists = transform.hough_line(img, theta)
assert len(transform.hough_line_peaks(hspace, angles, dists,
min_angle=45)[0]) == 2
assert len(transform.hough_line_peaks(hspace, angles, dists,
min_angle=90)[0]) == 1
theta = np.linspace(np.pi / 3, 4. / 3 * np.pi, 100)
hspace, angles, dists = transform.hough_line(img, theta)
assert len(transform.hough_line_peaks(hspace, angles, dists,
min_angle=45)[0]) == 2
assert len(transform.hough_line_peaks(hspace, angles, dists,
min_angle=90)[0]) == 1
def test_hough_line_peaks_num():
img = np.zeros((100, 100), dtype=np.bool_)
img[:, 30] = True
img[:, 40] = True
hspace, angles, dists = transform.hough_line(img)
assert len(transform.hough_line_peaks(hspace, angles, dists,
min_distance=0, min_angle=0,
num_peaks=1)[0]) == 1
def test_hough_line_peaks_zero_input():
# Test to make sure empty input doesn't cause a failure
img = np.zeros((100, 100), dtype='uint8')
theta = np.linspace(0, np.pi, 100)
hspace, angles, dists = transform.hough_line(img, theta)
h, a, d = transform.hough_line_peaks(hspace, angles, dists)
assert_equal(a, np.array([]))
@test_parallel()
def test_hough_circle():
# Prepare picture
img = np.zeros((120, 100), dtype=int)
radius = 20
x_0, y_0 = (99, 50)
y, x = circle_perimeter(y_0, x_0, radius)
img[x, y] = 1
out1 = transform.hough_circle(img, radius)
out2 = transform.hough_circle(img, [radius])
assert_equal(out1, out2)
out = transform.hough_circle(img, np.array([radius], dtype=np.intp))
assert_equal(out, out1)
x, y = np.where(out[0] == out[0].max())
assert_equal(x[0], x_0)
assert_equal(y[0], y_0)
def test_hough_circle_extended():
# Prepare picture
# The circle center is outside the image
img = np.zeros((100, 100), dtype=int)
radius = 20
x_0, y_0 = (-5, 50)
y, x = circle_perimeter(y_0, x_0, radius)
img[x[np.where(x > 0)], y[np.where(x > 0)]] = 1
out = transform.hough_circle(img, np.array([radius], dtype=np.intp),
full_output=True)
x, y = np.where(out[0] == out[0].max())
# Offset for x_0, y_0
assert_equal(x[0], x_0 + radius)
assert_equal(y[0], y_0 + radius)
def test_hough_circle_peaks():
x_0, y_0, rad_0 = (99, 50, 20)
img = np.zeros((120, 100), dtype=int)
y, x = circle_perimeter(y_0, x_0, rad_0)
img[x, y] = 1
x_1, y_1, rad_1 = (49, 60, 30)
y, x = circle_perimeter(y_1, x_1, rad_1)
img[x, y] = 1
radii = [rad_0, rad_1]
hspaces = transform.hough_circle(img, radii)
out = transform.hough_circle_peaks(hspaces, radii, min_xdistance=1,
min_ydistance=1, threshold=None,
num_peaks=np.inf,
total_num_peaks=np.inf)
s = np.argsort(out[3]) # sort by radii
assert_equal(out[1][s], np.array([y_0, y_1]))
assert_equal(out[2][s], np.array([x_0, x_1]))
assert_equal(out[3][s], np.array([rad_0, rad_1]))
def test_hough_circle_peaks_total_peak():
img = np.zeros((120, 100), dtype=int)
x_0, y_0, rad_0 = (99, 50, 20)
y, x = circle_perimeter(y_0, x_0, rad_0)
img[x, y] = 1
x_1, y_1, rad_1 = (49, 60, 30)
y, x = circle_perimeter(y_1, x_1, rad_1)
img[x, y] = 1
radii = [rad_0, rad_1]
hspaces = transform.hough_circle(img, radii)
out = transform.hough_circle_peaks(hspaces, radii, min_xdistance=1,
min_ydistance=1, threshold=None,
num_peaks=np.inf, total_num_peaks=1)
assert_equal(out[1][0], np.array([y_1, ]))
assert_equal(out[2][0], np.array([x_1, ]))
assert_equal(out[3][0], np.array([rad_1, ]))
def test_hough_circle_peaks_min_distance():
x_0, y_0, rad_0 = (50, 50, 20)
img = np.zeros((120, 100), dtype=int)
y, x = circle_perimeter(y_0, x_0, rad_0)
img[x, y] = 1
x_1, y_1, rad_1 = (60, 60, 30)
y, x = circle_perimeter(y_1, x_1, rad_1)
# Add noise and create an imperfect circle to lower the peak in Hough space
y[::2] += 1
x[::2] += 1
img[x, y] = 1
x_2, y_2, rad_2 = (70, 70, 20)
y, x = circle_perimeter(y_2, x_2, rad_2)
# Add noise and create an imperfect circle to lower the peak in Hough space
y[::2] += 1
x[::2] += 1
img[x, y] = 1
radii = [rad_0, rad_1, rad_2]
hspaces = transform.hough_circle(img, radii)
out = transform.hough_circle_peaks(hspaces, radii, min_xdistance=15,
min_ydistance=15, threshold=None,
num_peaks=np.inf,
total_num_peaks=np.inf,
normalize=True)
# The second circle is too close to the first one
# and has a weaker peak in Hough space due to imperfectness.
# Therefore it got removed.
assert_equal(out[1], np.array([y_0, y_2]))
assert_equal(out[2], np.array([x_0, x_2]))
assert_equal(out[3], np.array([rad_0, rad_2]))
def test_hough_circle_peaks_total_peak_and_min_distance():
img = np.zeros((120, 120), dtype=int)
cx = cy = [40, 50, 60, 70, 80]
radii = range(20, 30, 2)
for i in range(len(cx)):
y, x = circle_perimeter(cy[i], cx[i], radii[i])
img[x, y] = 1
hspaces = transform.hough_circle(img, radii)
out = transform.hough_circle_peaks(hspaces, radii, min_xdistance=15,
min_ydistance=15, threshold=None,
num_peaks=np.inf,
total_num_peaks=2,
normalize=True)
# 2nd (4th) circle is removed as it is close to 1st (3rd) oneself.
# 5th is removed as total_num_peaks = 2
assert_equal(out[1], np.array(cy[:4:2]))
assert_equal(out[2], np.array(cx[:4:2]))
assert_equal(out[3], np.array(radii[:4:2]))
def test_hough_circle_peaks_normalize():
x_0, y_0, rad_0 = (50, 50, 20)
img = np.zeros((120, 100), dtype=int)
y, x = circle_perimeter(y_0, x_0, rad_0)
img[x, y] = 1
x_1, y_1, rad_1 = (60, 60, 30)
y, x = circle_perimeter(y_1, x_1, rad_1)
img[x, y] = 1
radii = [rad_0, rad_1]
hspaces = transform.hough_circle(img, radii)
out = transform.hough_circle_peaks(hspaces, radii, min_xdistance=15,
min_ydistance=15, threshold=None,
num_peaks=np.inf,
total_num_peaks=np.inf,
normalize=False)
# Two perfect circles are close but the second one is bigger.
# Therefore, it is picked due to its high peak.
assert_equal(out[1], np.array([y_1]))
assert_equal(out[2], np.array([x_1]))
assert_equal(out[3], np.array([rad_1]))
def test_hough_ellipse_zero_angle():
img = np.zeros((25, 25), dtype=int)
rx = 6
ry = 8
x0 = 12
y0 = 15
angle = 0
rr, cc = ellipse_perimeter(y0, x0, ry, rx)
img[rr, cc] = 1
result = transform.hough_ellipse(img, threshold=9)
best = result[-1]
assert_equal(best[1], y0)
assert_equal(best[2], x0)
assert_almost_equal(best[3], ry, decimal=1)
assert_almost_equal(best[4], rx, decimal=1)
assert_equal(best[5], angle)
# Check if I re-draw the ellipse, points are the same!
# ie check API compatibility between hough_ellipse and ellipse_perimeter
rr2, cc2 = ellipse_perimeter(y0, x0, int(best[3]), int(best[4]),
orientation=best[5])
assert_equal(rr, rr2)
assert_equal(cc, cc2)
def test_hough_ellipse_non_zero_posangle1():
# ry > rx, angle in [0:pi/2]
img = np.zeros((30, 24), dtype=int)
rx = 6
ry = 12
x0 = 10
y0 = 15
angle = np.pi / 1.35
rr, cc = ellipse_perimeter(y0, x0, ry, rx, orientation=angle)
img[rr, cc] = 1
result = transform.hough_ellipse(img, threshold=15, accuracy=3)
result.sort(order='accumulator')
best = result[-1]
assert_almost_equal(best[1] / 100., y0 / 100., decimal=1)
assert_almost_equal(best[2] / 100., x0 / 100., decimal=1)
assert_almost_equal(best[3] / 10., ry / 10., decimal=1)
assert_almost_equal(best[4] / 100., rx / 100., decimal=1)
assert_almost_equal(best[5], angle, decimal=1)
# Check if I re-draw the ellipse, points are the same!
# ie check API compatibility between hough_ellipse and ellipse_perimeter
rr2, cc2 = ellipse_perimeter(y0, x0, int(best[3]), int(best[4]),
orientation=best[5])
assert_equal(rr, rr2)
assert_equal(cc, cc2)
def test_hough_ellipse_non_zero_posangle2():
# ry < rx, angle in [0:pi/2]
img = np.zeros((30, 24), dtype=int)
rx = 12
ry = 6
x0 = 10
y0 = 15
angle = np.pi / 1.35
rr, cc = ellipse_perimeter(y0, x0, ry, rx, orientation=angle)
img[rr, cc] = 1
result = transform.hough_ellipse(img, threshold=15, accuracy=3)
result.sort(order='accumulator')
best = result[-1]
assert_almost_equal(best[1] / 100., y0 / 100., decimal=1)
assert_almost_equal(best[2] / 100., x0 / 100., decimal=1)
assert_almost_equal(best[3] / 10., ry / 10., decimal=1)
assert_almost_equal(best[4] / 100., rx / 100., decimal=1)
assert_almost_equal(best[5], angle, decimal=1)
# Check if I re-draw the ellipse, points are the same!
# ie check API compatibility between hough_ellipse and ellipse_perimeter
rr2, cc2 = ellipse_perimeter(y0, x0, int(best[3]), int(best[4]),
orientation=best[5])
assert_equal(rr, rr2)
assert_equal(cc, cc2)
def test_hough_ellipse_non_zero_posangle3():
# ry < rx, angle in [pi/2:pi]
img = np.zeros((30, 24), dtype=int)
rx = 12
ry = 6
x0 = 10
y0 = 15
angle = np.pi / 1.35 + np.pi / 2.
rr, cc = ellipse_perimeter(y0, x0, ry, rx, orientation=angle)
img[rr, cc] = 1
result = transform.hough_ellipse(img, threshold=15, accuracy=3)
result.sort(order='accumulator')
best = result[-1]
# Check if I re-draw the ellipse, points are the same!
# ie check API compatibility between hough_ellipse and ellipse_perimeter
rr2, cc2 = ellipse_perimeter(y0, x0, int(best[3]), int(best[4]),
orientation=best[5])
assert_equal(rr, rr2)
assert_equal(cc, cc2)
def test_hough_ellipse_non_zero_posangle4():
# ry < rx, angle in [pi:3pi/4]
img = np.zeros((30, 24), dtype=int)
rx = 12
ry = 6
x0 = 10
y0 = 15
angle = np.pi / 1.35 + np.pi
rr, cc = ellipse_perimeter(y0, x0, ry, rx, orientation=angle)
img[rr, cc] = 1
result = transform.hough_ellipse(img, threshold=15, accuracy=3)
result.sort(order='accumulator')
best = result[-1]
# Check if I re-draw the ellipse, points are the same!
# ie check API compatibility between hough_ellipse and ellipse_perimeter
rr2, cc2 = ellipse_perimeter(y0, x0, int(best[3]), int(best[4]),
orientation=best[5])
assert_equal(rr, rr2)
assert_equal(cc, cc2)
def test_hough_ellipse_non_zero_negangle1():
# ry > rx, angle in [0:-pi/2]
img = np.zeros((30, 24), dtype=int)
rx = 6
ry = 12
x0 = 10
y0 = 15
angle = - np.pi / 1.35
rr, cc = ellipse_perimeter(y0, x0, ry, rx, orientation=angle)
img[rr, cc] = 1
result = transform.hough_ellipse(img, threshold=15, accuracy=3)
result.sort(order='accumulator')
best = result[-1]
# Check if I re-draw the ellipse, points are the same!
# ie check API compatibility between hough_ellipse and ellipse_perimeter
rr2, cc2 = ellipse_perimeter(y0, x0, int(best[3]), int(best[4]),
orientation=best[5])
assert_equal(rr, rr2)
assert_equal(cc, cc2)
def test_hough_ellipse_non_zero_negangle2():
# ry < rx, angle in [0:-pi/2]
img = np.zeros((30, 24), dtype=int)
rx = 12
ry = 6
x0 = 10
y0 = 15
angle = - np.pi / 1.35
rr, cc = ellipse_perimeter(y0, x0, ry, rx, orientation=angle)
img[rr, cc] = 1
result = transform.hough_ellipse(img, threshold=15, accuracy=3)
result.sort(order='accumulator')
best = result[-1]
# Check if I re-draw the ellipse, points are the same!
# ie check API compatibility between hough_ellipse and ellipse_perimeter
rr2, cc2 = ellipse_perimeter(y0, x0, int(best[3]), int(best[4]),
orientation=best[5])
assert_equal(rr, rr2)
assert_equal(cc, cc2)
def test_hough_ellipse_non_zero_negangle3():
# ry < rx, angle in [-pi/2:-pi]
img = np.zeros((30, 24), dtype=int)
rx = 12
ry = 6
x0 = 10
y0 = 15
angle = - np.pi / 1.35 - np.pi / 2.
rr, cc = ellipse_perimeter(y0, x0, ry, rx, orientation=angle)
img[rr, cc] = 1
result = transform.hough_ellipse(img, threshold=15, accuracy=3)
result.sort(order='accumulator')
best = result[-1]
# Check if I re-draw the ellipse, points are the same!
# ie check API compatibility between hough_ellipse and ellipse_perimeter
rr2, cc2 = ellipse_perimeter(y0, x0, int(best[3]), int(best[4]),
orientation=best[5])
assert_equal(rr, rr2)
assert_equal(cc, cc2)
def test_hough_ellipse_non_zero_negangle4():
# ry < rx, angle in [-pi:-3pi/4]
img = np.zeros((30, 24), dtype=int)
rx = 12
ry = 6
x0 = 10
y0 = 15
angle = - np.pi / 1.35 - np.pi
rr, cc = ellipse_perimeter(y0, x0, ry, rx, orientation=angle)
img[rr, cc] = 1
result = transform.hough_ellipse(img, threshold=15, accuracy=3)
result.sort(order='accumulator')
best = result[-1]
# Check if I re-draw the ellipse, points are the same!
# ie check API compatibility between hough_ellipse and ellipse_perimeter
rr2, cc2 = ellipse_perimeter(y0, x0, int(best[3]), int(best[4]),
orientation=best[5])
assert_equal(rr, rr2)
assert_equal(cc, cc2)
def test_hough_ellipse_all_black_img():
assert(transform.hough_ellipse(np.zeros((100, 100))).shape == (0, 6))

View file

@ -0,0 +1,47 @@
import numpy as np
from skimage.transform import integral_image, integrate
from skimage._shared.testing import assert_equal
np.random.seed(0)
x = (np.random.rand(50, 50) * 255).astype(np.uint8)
s = integral_image(x)
def test_validity():
y = np.arange(12).reshape((4, 3))
y = (np.random.rand(50, 50) * 255).astype(np.uint8)
assert_equal(integral_image(y)[-1, -1],
y.sum())
def test_basic():
assert_equal(x[12:24, 10:20].sum(), integrate(s, (12, 10), (23, 19)))
assert_equal(x[:20, :20].sum(), integrate(s, (0, 0), (19, 19)))
assert_equal(x[:20, 10:20].sum(), integrate(s, (0, 10), (19, 19)))
assert_equal(x[10:20, :20].sum(), integrate(s, (10, 0), (19, 19)))
def test_single():
assert_equal(x[0, 0], integrate(s, (0, 0), (0, 0)))
assert_equal(x[10, 10], integrate(s, (10, 10), (10, 10)))
def test_vectorized_integrate():
r0 = np.array([12, 0, 0, 10, 0, 10, 30])
c0 = np.array([10, 0, 10, 0, 0, 10, 31])
r1 = np.array([23, 19, 19, 19, 0, 10, 49])
c1 = np.array([19, 19, 19, 19, 0, 10, 49])
expected = np.array([x[12:24, 10:20].sum(),
x[:20, :20].sum(),
x[:20, 10:20].sum(),
x[10:20, :20].sum(),
x[0, 0],
x[10, 10],
x[30:, 31:].sum()])
start_pts = [(r0[i], c0[i]) for i in range(len(r0))]
end_pts = [(r1[i], c1[i]) for i in range(len(r0))]
assert_equal(expected, integrate(s, start_pts, end_pts))

View file

@ -0,0 +1,147 @@
import math
import pytest
import numpy as np
from skimage import data
from skimage.transform import pyramids
from skimage._shared import testing
from skimage._shared.testing import (assert_array_equal, assert_, assert_equal,
assert_almost_equal)
image = data.astronaut()
image_gray = image[..., 0]
def test_pyramid_reduce_rgb():
rows, cols, dim = image.shape
out = pyramids.pyramid_reduce(image, downscale=2, multichannel=True)
assert_array_equal(out.shape, (rows / 2, cols / 2, dim))
def test_pyramid_reduce_gray():
rows, cols = image_gray.shape
out1 = pyramids.pyramid_reduce(image_gray, downscale=2,
multichannel=False)
assert_array_equal(out1.shape, (rows / 2, cols / 2))
assert_almost_equal(out1.ptp(), 1.0, decimal=2)
out2 = pyramids.pyramid_reduce(image_gray, downscale=2,
multichannel=False, preserve_range=True)
assert_almost_equal(out2.ptp() / image_gray.ptp(), 1.0, decimal=2)
def test_pyramid_reduce_nd():
for ndim in [1, 2, 3, 4]:
img = np.random.randn(*((8, ) * ndim))
out = pyramids.pyramid_reduce(img, downscale=2,
multichannel=False)
expected_shape = np.asarray(img.shape) / 2
assert_array_equal(out.shape, expected_shape)
def test_pyramid_expand_rgb():
rows, cols, dim = image.shape
out = pyramids.pyramid_expand(image, upscale=2,
multichannel=True)
assert_array_equal(out.shape, (rows * 2, cols * 2, dim))
def test_pyramid_expand_gray():
rows, cols = image_gray.shape
out = pyramids.pyramid_expand(image_gray, upscale=2,
multichannel=False)
assert_array_equal(out.shape, (rows * 2, cols * 2))
def test_pyramid_expand_nd():
for ndim in [1, 2, 3, 4]:
img = np.random.randn(*((4, ) * ndim))
out = pyramids.pyramid_expand(img, upscale=2,
multichannel=False)
expected_shape = np.asarray(img.shape) * 2
assert_array_equal(out.shape, expected_shape)
def test_build_gaussian_pyramid_rgb():
rows, cols, dim = image.shape
pyramid = pyramids.pyramid_gaussian(image, downscale=2,
multichannel=True)
for layer, out in enumerate(pyramid):
layer_shape = (rows / 2 ** layer, cols / 2 ** layer, dim)
assert_array_equal(out.shape, layer_shape)
def test_build_gaussian_pyramid_gray():
rows, cols = image_gray.shape
pyramid = pyramids.pyramid_gaussian(image_gray, downscale=2,
multichannel=False)
for layer, out in enumerate(pyramid):
layer_shape = (rows / 2 ** layer, cols / 2 ** layer)
assert_array_equal(out.shape, layer_shape)
def test_build_gaussian_pyramid_nd():
for ndim in [1, 2, 3, 4]:
img = np.random.randn(*((8, ) * ndim))
original_shape = np.asarray(img.shape)
pyramid = pyramids.pyramid_gaussian(img, downscale=2,
multichannel=False)
for layer, out in enumerate(pyramid):
layer_shape = original_shape / 2 ** layer
assert_array_equal(out.shape, layer_shape)
def test_build_laplacian_pyramid_rgb():
rows, cols, dim = image.shape
pyramid = pyramids.pyramid_laplacian(image, downscale=2,
multichannel=True)
for layer, out in enumerate(pyramid):
layer_shape = (rows / 2 ** layer, cols / 2 ** layer, dim)
assert_array_equal(out.shape, layer_shape)
def test_build_laplacian_pyramid_nd():
for ndim in [1, 2, 3, 4]:
img = np.random.randn(*(16, )*ndim)
original_shape = np.asarray(img.shape)
pyramid = pyramids.pyramid_laplacian(img, downscale=2,
multichannel=False)
for layer, out in enumerate(pyramid):
print(out.shape)
layer_shape = original_shape / 2 ** layer
assert_array_equal(out.shape, layer_shape)
def test_laplacian_pyramid_max_layers():
for downscale in [2, 3, 5, 7]:
img = np.random.randn(32, 8)
pyramid = pyramids.pyramid_laplacian(img, downscale=downscale,
multichannel=False)
max_layer = int(np.ceil(math.log(np.max(img.shape), downscale)))
for layer, out in enumerate(pyramid):
if layer < max_layer:
# should not reach all axes as size 1 prior to final level
assert_(np.max(out.shape) > 1)
# total number of images is max_layer + 1
assert_equal(max_layer, layer)
# final layer should be size 1 on all axes
assert_array_equal((out.shape), (1, 1))
def test_check_factor():
with testing.raises(ValueError):
pyramids._check_factor(0.99)
with testing.raises(ValueError):
pyramids._check_factor(- 2)
@pytest.mark.parametrize('dtype, expected',
zip(['float32', 'float64', 'uint8', 'int64'],
['float32', 'float64', 'float64', 'float64']))
def test_pyramid_gaussian_dtype_support(dtype, expected):
img = np.random.randn(32, 8).astype(dtype)
pyramid = pyramids.pyramid_gaussian(img)
assert np.all([im.dtype == expected for im in pyramid])

View file

@ -0,0 +1,473 @@
import itertools
import pytest
import numpy as np
from skimage.data import shepp_logan_phantom
from skimage.transform import radon, iradon, iradon_sart, rescale
from skimage._shared.utils import convert_to_float
from skimage._shared import testing
from skimage._shared.testing import test_parallel
from skimage._shared._warnings import expected_warnings
PHANTOM = shepp_logan_phantom()[::2, ::2]
PHANTOM = rescale(PHANTOM, 0.5, order=1,
mode='constant', anti_aliasing=False, multichannel=False)
def _debug_plot(original, result, sinogram=None):
from matplotlib import pyplot as plt
imkwargs = dict(cmap='gray', interpolation='nearest')
if sinogram is None:
plt.figure(figsize=(15, 6))
sp = 130
else:
plt.figure(figsize=(11, 11))
sp = 221
plt.subplot(sp + 0)
plt.imshow(sinogram, aspect='auto', **imkwargs)
plt.subplot(sp + 1)
plt.imshow(original, **imkwargs)
plt.subplot(sp + 2)
plt.imshow(result, vmin=original.min(), vmax=original.max(), **imkwargs)
plt.subplot(sp + 3)
plt.imshow(result - original, **imkwargs)
plt.colorbar()
plt.show()
def _rescale_intensity(x):
x = x.astype(float)
x -= x.min()
x /= x.max()
return x
def test_iradon_bias_circular_phantom():
"""
test that a uniform circular phantom has a small reconstruction bias
"""
pixels = 128
xy = np.arange(-pixels / 2, pixels / 2) + 0.5
x, y = np.meshgrid(xy, xy)
image = x**2 + y**2 <= (pixels/4)**2
theta = np.linspace(0., 180., max(image.shape), endpoint=False)
sinogram = radon(image, theta=theta)
reconstruction_fbp = iradon(sinogram, theta=theta)
error = reconstruction_fbp - image
tol = 5e-5
roi_err = np.abs(np.mean(error))
assert roi_err < tol
def check_radon_center(shape, circle, dtype, preserve_range):
# Create a test image with only a single non-zero pixel at the origin
image = np.zeros(shape, dtype=dtype)
image[(shape[0] // 2, shape[1] // 2)] = 1.
# Calculate the sinogram
theta = np.linspace(0., 180., max(shape), endpoint=False)
sinogram = radon(image, theta=theta, circle=circle,
preserve_range=preserve_range)
# The sinogram should be a straight, horizontal line
sinogram_max = np.argmax(sinogram, axis=0)
print(sinogram_max)
assert np.std(sinogram_max) < 1e-6
@testing.parametrize("shape", [(16, 16), (17, 17)])
@testing.parametrize("circle", [False, True])
@testing.parametrize("dtype", [np.float64, np.float32, np.uint8, bool])
@testing.parametrize("preserve_range", [False, True])
def test_radon_center(shape, circle, dtype, preserve_range):
check_radon_center(shape, circle, dtype, preserve_range)
@testing.parametrize("shape", [(32, 16), (33, 17)])
@testing.parametrize("circle", [False])
@testing.parametrize("dtype", [np.float64, np.float32, np.uint8, bool])
@testing.parametrize("preserve_range", [False, True])
def test_radon_center_rectangular(shape, circle, dtype, preserve_range):
check_radon_center(shape, circle, dtype, preserve_range)
def check_iradon_center(size, theta, circle):
debug = False
# Create a test sinogram corresponding to a single projection
# with a single non-zero pixel at the rotation center
if circle:
sinogram = np.zeros((size, 1), dtype=np.float)
sinogram[size // 2, 0] = 1.
else:
diagonal = int(np.ceil(np.sqrt(2) * size))
sinogram = np.zeros((diagonal, 1), dtype=np.float)
sinogram[sinogram.shape[0] // 2, 0] = 1.
maxpoint = np.unravel_index(np.argmax(sinogram), sinogram.shape)
print('shape of generated sinogram', sinogram.shape)
print('maximum in generated sinogram', maxpoint)
# Compare reconstructions for theta=angle and theta=angle + 180;
# these should be exactly equal
reconstruction = iradon(sinogram, theta=[theta], circle=circle)
reconstruction_opposite = iradon(sinogram, theta=[theta + 180],
circle=circle)
print('rms deviance:',
np.sqrt(np.mean((reconstruction_opposite - reconstruction)**2)))
if debug:
import matplotlib.pyplot as plt
imkwargs = dict(cmap='gray', interpolation='nearest')
plt.figure()
plt.subplot(221)
plt.imshow(sinogram, **imkwargs)
plt.subplot(222)
plt.imshow(reconstruction_opposite - reconstruction, **imkwargs)
plt.subplot(223)
plt.imshow(reconstruction, **imkwargs)
plt.subplot(224)
plt.imshow(reconstruction_opposite, **imkwargs)
plt.show()
assert np.allclose(reconstruction, reconstruction_opposite)
sizes_for_test_iradon_center = [16, 17]
thetas_for_test_iradon_center = [0, 90]
circles_for_test_iradon_center = [False, True]
@testing.parametrize("size, theta, circle",
itertools.product(sizes_for_test_iradon_center,
thetas_for_test_iradon_center,
circles_for_test_iradon_center))
def test_iradon_center(size, theta, circle):
check_iradon_center(size, theta, circle)
def check_radon_iradon(interpolation_type, filter_type):
debug = False
image = PHANTOM
reconstructed = iradon(radon(image, circle=False), filter_name=filter_type,
interpolation=interpolation_type, circle=False)
delta = np.mean(np.abs(image - reconstructed))
print('\n\tmean error:', delta)
if debug:
_debug_plot(image, reconstructed)
if filter_type in ('ramp', 'shepp-logan'):
if interpolation_type == 'nearest':
allowed_delta = 0.03
else:
allowed_delta = 0.025
else:
allowed_delta = 0.05
assert delta < allowed_delta
filter_types = ["ramp", "shepp-logan", "cosine", "hamming", "hann"]
interpolation_types = ['linear', 'nearest']
radon_iradon_inputs = list(itertools.product(interpolation_types,
filter_types))
# cubic interpolation is slow; only run one test for it
radon_iradon_inputs.append(('cubic', 'shepp-logan'))
@testing.parametrize("interpolation_type, filter_type",
radon_iradon_inputs)
def test_radon_iradon(interpolation_type, filter_type):
check_radon_iradon(interpolation_type, filter_type)
@pytest.mark.parametrize("filter_type", filter_types)
def test_iradon_new_signature(filter_type):
image = PHANTOM
sinogram = radon(image, circle=False)
with pytest.warns(FutureWarning):
assert np.array_equal(iradon(sinogram, filter=filter_type),
iradon(sinogram, filter_name=filter_type))
def test_iradon_angles():
"""
Test with different number of projections
"""
size = 100
# Synthetic data
image = np.tri(size) + np.tri(size)[::-1]
# Large number of projections: a good quality is expected
nb_angles = 200
theta = np.linspace(0, 180, nb_angles, endpoint=False)
radon_image_200 = radon(image, theta=theta, circle=False)
reconstructed = iradon(radon_image_200, circle=False)
delta_200 = np.mean(abs(_rescale_intensity(image) -
_rescale_intensity(reconstructed)))
assert delta_200 < 0.03
# Lower number of projections
nb_angles = 80
radon_image_80 = radon(image, theta=theta, circle=False)
# Test whether the sum of all projections is approximately the same
s = radon_image_80.sum(axis=0)
assert np.allclose(s, s[0], rtol=0.01)
reconstructed = iradon(radon_image_80, circle=False)
delta_80 = np.mean(abs(image / np.max(image) -
reconstructed / np.max(reconstructed)))
# Loss of quality when the number of projections is reduced
assert delta_80 > delta_200
def check_radon_iradon_minimal(shape, slices):
debug = False
theta = np.arange(180)
image = np.zeros(shape, dtype=np.float)
image[slices] = 1.
sinogram = radon(image, theta, circle=False)
reconstructed = iradon(sinogram, theta, circle=False)
print('\n\tMaximum deviation:', np.max(np.abs(image - reconstructed)))
if debug:
_debug_plot(image, reconstructed, sinogram)
if image.sum() == 1:
assert (np.unravel_index(np.argmax(reconstructed), image.shape)
== np.unravel_index(np.argmax(image), image.shape))
shapes = [(3, 3), (4, 4), (5, 5)]
def generate_test_data_for_radon_iradon_minimal(shapes):
def shape2coordinates(shape):
c0, c1 = shape[0] // 2, shape[1] // 2
coordinates = itertools.product((c0 - 1, c0, c0 + 1),
(c1 - 1, c1, c1 + 1))
return coordinates
def shape2shapeandcoordinates(shape):
return itertools.product([shape], shape2coordinates(shape))
return itertools.chain.from_iterable([shape2shapeandcoordinates(shape)
for shape in shapes])
@testing.parametrize("shape, coordinate",
generate_test_data_for_radon_iradon_minimal(shapes))
def test_radon_iradon_minimal(shape, coordinate):
check_radon_iradon_minimal(shape, coordinate)
def test_reconstruct_with_wrong_angles():
a = np.zeros((3, 3))
p = radon(a, theta=[0, 1, 2], circle=False)
iradon(p, theta=[0, 1, 2], circle=False)
with testing.raises(ValueError):
iradon(p, theta=[0, 1, 2, 3])
def _random_circle(shape):
# Synthetic random data, zero outside reconstruction circle
np.random.seed(98312871)
image = np.random.rand(*shape)
c0, c1 = np.ogrid[0:shape[0], 0:shape[1]]
r = np.sqrt((c0 - shape[0] // 2)**2 + (c1 - shape[1] // 2)**2)
radius = min(shape) // 2
image[r > radius] = 0.
return image
def test_radon_circle():
a = np.ones((10, 10))
with expected_warnings(['reconstruction circle']):
radon(a, circle=True)
# Synthetic data, circular symmetry
shape = (61, 79)
c0, c1 = np.ogrid[0:shape[0], 0:shape[1]]
r = np.sqrt((c0 - shape[0] // 2)**2 + (c1 - shape[1] // 2)**2)
radius = min(shape) // 2
image = np.clip(radius - r, 0, np.inf)
image = _rescale_intensity(image)
angles = np.linspace(0, 180, min(shape), endpoint=False)
sinogram = radon(image, theta=angles, circle=True)
assert np.all(sinogram.std(axis=1) < 1e-2)
# Synthetic data, random
image = _random_circle(shape)
sinogram = radon(image, theta=angles, circle=True)
mass = sinogram.sum(axis=0)
average_mass = mass.mean()
relative_error = np.abs(mass - average_mass) / average_mass
print(relative_error.max(), relative_error.mean())
assert np.all(relative_error < 3.2e-3)
def check_sinogram_circle_to_square(size):
from skimage.transform.radon_transform import _sinogram_circle_to_square
image = _random_circle((size, size))
theta = np.linspace(0., 180., size, False)
sinogram_circle = radon(image, theta, circle=True)
def argmax_shape(a):
return np.unravel_index(np.argmax(a), a.shape)
print('\n\targmax of circle:', argmax_shape(sinogram_circle))
sinogram_square = radon(image, theta, circle=False)
print('\targmax of square:', argmax_shape(sinogram_square))
sinogram_circle_to_square = _sinogram_circle_to_square(sinogram_circle)
print('\targmax of circle to square:',
argmax_shape(sinogram_circle_to_square))
error = abs(sinogram_square - sinogram_circle_to_square)
print(np.mean(error), np.max(error))
assert (argmax_shape(sinogram_square) ==
argmax_shape(sinogram_circle_to_square))
@testing.parametrize("size", (50, 51))
def test_sinogram_circle_to_square(size):
check_sinogram_circle_to_square(size)
def check_radon_iradon_circle(interpolation, shape, output_size):
# Forward and inverse radon on synthetic data
image = _random_circle(shape)
radius = min(shape) // 2
sinogram_rectangle = radon(image, circle=False)
reconstruction_rectangle = iradon(sinogram_rectangle,
output_size=output_size,
interpolation=interpolation,
circle=False)
sinogram_circle = radon(image, circle=True)
reconstruction_circle = iradon(sinogram_circle,
output_size=output_size,
interpolation=interpolation,
circle=True)
# Crop rectangular reconstruction to match circle=True reconstruction
width = reconstruction_circle.shape[0]
excess = int(np.ceil((reconstruction_rectangle.shape[0] - width) / 2))
s = np.s_[excess:width + excess, excess:width + excess]
reconstruction_rectangle = reconstruction_rectangle[s]
# Find the reconstruction circle, set reconstruction to zero outside
c0, c1 = np.ogrid[0:width, 0:width]
r = np.sqrt((c0 - width // 2)**2 + (c1 - width // 2)**2)
reconstruction_rectangle[r > radius] = 0.
print(reconstruction_circle.shape)
print(reconstruction_rectangle.shape)
np.allclose(reconstruction_rectangle, reconstruction_circle)
# if adding more shapes to test data, you might want to look at commit d0f2bac3f
shapes_radon_iradon_circle = ((61, 79), )
interpolations = ('nearest', 'linear')
output_sizes = (None,
min(shapes_radon_iradon_circle[0]),
max(shapes_radon_iradon_circle[0]),
97)
@testing.parametrize("shape, interpolation, output_size",
itertools.product(shapes_radon_iradon_circle,
interpolations, output_sizes))
def test_radon_iradon_circle(shape, interpolation, output_size):
check_radon_iradon_circle(interpolation, shape, output_size)
def test_order_angles_golden_ratio():
from skimage.transform.radon_transform import order_angles_golden_ratio
np.random.seed(1231)
lengths = [1, 4, 10, 180]
for l in lengths:
theta_ordered = np.linspace(0, 180, l, endpoint=False)
theta_random = np.random.uniform(0, 180, l)
for theta in (theta_random, theta_ordered):
indices = [x for x in order_angles_golden_ratio(theta)]
# no duplicate indices allowed
assert len(indices) == len(set(indices))
@test_parallel()
def test_iradon_sart():
debug = False
image = rescale(PHANTOM, 0.8, mode='reflect',
multichannel=False, anti_aliasing=False)
theta_ordered = np.linspace(0., 180., image.shape[0], endpoint=False)
theta_missing_wedge = np.linspace(0., 150., image.shape[0], endpoint=True)
for theta, error_factor in ((theta_ordered, 1.),
(theta_missing_wedge, 2.)):
sinogram = radon(image, theta, circle=True)
reconstructed = iradon_sart(sinogram, theta)
if debug:
from matplotlib import pyplot as plt
plt.figure()
plt.subplot(221)
plt.imshow(image, interpolation='nearest')
plt.subplot(222)
plt.imshow(sinogram, interpolation='nearest')
plt.subplot(223)
plt.imshow(reconstructed, interpolation='nearest')
plt.subplot(224)
plt.imshow(reconstructed - image, interpolation='nearest')
plt.show()
delta = np.mean(np.abs(reconstructed - image))
print('delta (1 iteration) =', delta)
assert delta < 0.02 * error_factor
reconstructed = iradon_sart(sinogram, theta, reconstructed)
delta = np.mean(np.abs(reconstructed - image))
print('delta (2 iterations) =', delta)
assert delta < 0.014 * error_factor
reconstructed = iradon_sart(sinogram, theta, clip=(0, 1))
delta = np.mean(np.abs(reconstructed - image))
print('delta (1 iteration, clip) =', delta)
assert delta < 0.018 * error_factor
np.random.seed(1239867)
shifts = np.random.uniform(-3, 3, sinogram.shape[1])
x = np.arange(sinogram.shape[0])
sinogram_shifted = np.vstack([np.interp(x + shifts[i], x,
sinogram[:, i])
for i in range(sinogram.shape[1])]).T
reconstructed = iradon_sart(sinogram_shifted, theta,
projection_shifts=shifts)
if debug:
from matplotlib import pyplot as plt
plt.figure()
plt.subplot(221)
plt.imshow(image, interpolation='nearest')
plt.subplot(222)
plt.imshow(sinogram_shifted, interpolation='nearest')
plt.subplot(223)
plt.imshow(reconstructed, interpolation='nearest')
plt.subplot(224)
plt.imshow(reconstructed - image, interpolation='nearest')
plt.show()
delta = np.mean(np.abs(reconstructed - image))
print('delta (1 iteration, shifted sinogram) =', delta)
assert delta < 0.022 * error_factor
def test_radon_dtype():
img = convert_to_float(PHANTOM, False)
img32 = img.astype(np.float32)
assert radon(img).dtype == img.dtype
assert radon(img32).dtype == img32.dtype
def test_iradon_sart_dtype():
sinogram = np.zeros((16, 1), dtype=int)
sinogram[8, 0] = 1.
sinogram64 = sinogram.astype('float64')
sinogram32 = sinogram.astype('float32')
with expected_warnings(['Input data is cast to float']):
assert iradon_sart(sinogram, theta=[0]).dtype == 'float64'
assert iradon_sart(sinogram64, theta=[0]).dtype == sinogram64.dtype
assert iradon_sart(sinogram32, theta=[0]).dtype == sinogram32.dtype
def test_iradon_wrong_dtype():
sinogram = np.zeros((16, 1))
with testing.raises(ValueError):
iradon_sart(sinogram, dtype=int)

View file

@ -0,0 +1,679 @@
import numpy as np
from scipy.ndimage import map_coordinates
from skimage.data import checkerboard, astronaut
from skimage.util.dtype import img_as_float
from skimage.color.colorconv import rgb2gray
from skimage.draw.draw import circle_perimeter_aa
from skimage.feature.peak import peak_local_max
from skimage._shared import testing
from skimage._shared.testing import (assert_almost_equal, assert_equal,
test_parallel)
from skimage._shared._warnings import expected_warnings
from skimage.transform._warps import (_stackcopy,
_linear_polar_mapping,
_log_polar_mapping, warp,
warp_coords, rotate, resize,
rescale, warp_polar, swirl,
downscale_local_mean)
from skimage.transform._geometric import (AffineTransform,
ProjectiveTransform,
SimilarityTransform)
np.random.seed(0)
def test_stackcopy():
layers = 4
x = np.empty((3, 3, layers))
y = np.eye(3, 3)
_stackcopy(x, y)
for i in range(layers):
assert_almost_equal(x[..., i], y)
def test_warp_tform():
x = np.zeros((5, 5), dtype=np.double)
x[2, 2] = 1
theta = - np.pi / 2
tform = SimilarityTransform(scale=1, rotation=theta, translation=(0, 4))
x90 = warp(x, tform, order=1)
assert_almost_equal(x90, np.rot90(x))
x90 = warp(x, tform.inverse, order=1)
assert_almost_equal(x90, np.rot90(x))
def test_warp_callable():
x = np.zeros((5, 5), dtype=np.double)
x[2, 2] = 1
refx = np.zeros((5, 5), dtype=np.double)
refx[1, 1] = 1
def shift(xy):
return xy + 1
outx = warp(x, shift, order=1)
assert_almost_equal(outx, refx)
@test_parallel()
def test_warp_matrix():
x = np.zeros((5, 5), dtype=np.double)
x[2, 2] = 1
refx = np.zeros((5, 5), dtype=np.double)
refx[1, 1] = 1
matrix = np.array([[1, 0, 1], [0, 1, 1], [0, 0, 1]])
# _warp_fast
outx = warp(x, matrix, order=1)
assert_almost_equal(outx, refx)
# check for ndimage.map_coordinates
outx = warp(x, matrix, order=5)
def test_warp_nd():
for dim in range(2, 8):
shape = dim * (5,)
x = np.zeros(shape, dtype=np.double)
x_c = dim * (2,)
x[x_c] = 1
refx = np.zeros(shape, dtype=np.double)
refx_c = dim * (1,)
refx[refx_c] = 1
coord_grid = dim * (slice(0, 5, 1),)
coords = np.array(np.mgrid[coord_grid]) + 1
outx = warp(x, coords, order=0, cval=0)
assert_almost_equal(outx, refx)
def test_warp_clip():
x = np.zeros((5, 5), dtype=np.double)
x[2, 2] = 1
outx = rescale(x, 3, order=3, clip=False,
multichannel=False, anti_aliasing=False, mode='constant')
assert outx.min() < 0
outx = rescale(x, 3, order=3, clip=True,
multichannel=False, anti_aliasing=False, mode='constant')
assert_almost_equal(outx.min(), 0)
assert_almost_equal(outx.max(), 1)
def test_homography():
x = np.zeros((5, 5), dtype=np.double)
x[1, 1] = 1
theta = -np.pi / 2
M = np.array([[np.cos(theta), - np.sin(theta), 0],
[np.sin(theta), np.cos(theta), 4],
[0, 0, 1]])
x90 = warp(x,
inverse_map=ProjectiveTransform(M).inverse,
order=1)
assert_almost_equal(x90, np.rot90(x))
def test_rotate():
x = np.zeros((5, 5), dtype=np.double)
x[1, 1] = 1
x90 = rotate(x, 90)
assert_almost_equal(x90, np.rot90(x))
def test_rotate_resize():
x = np.zeros((10, 10), dtype=np.double)
x45 = rotate(x, 45, resize=False)
assert x45.shape == (10, 10)
x45 = rotate(x, 45, resize=True)
# new dimension should be d = sqrt(2 * (10/2)^2)
assert x45.shape == (14, 14)
def test_rotate_center():
x = np.zeros((10, 10), dtype=np.double)
x[4, 4] = 1
refx = np.zeros((10, 10), dtype=np.double)
refx[2, 5] = 1
x20 = rotate(x, 20, order=0, center=(0, 0))
assert_almost_equal(x20, refx)
x0 = rotate(x20, -20, order=0, center=(0, 0))
assert_almost_equal(x0, x)
def test_rotate_resize_center():
x = np.zeros((10, 10), dtype=np.double)
x[0, 0] = 1
ref_x45 = np.zeros((14, 14), dtype=np.double)
ref_x45[6, 0] = 1
ref_x45[7, 0] = 1
x45 = rotate(x, 45, resize=True, center=(3, 3), order=0)
# new dimension should be d = sqrt(2 * (10/2)^2)
assert x45.shape == (14, 14)
assert_equal(x45, ref_x45)
def test_rotate_resize_90():
x90 = rotate(np.zeros((470, 230), dtype=np.double), 90, resize=True)
assert x90.shape == (230, 470)
def test_rescale():
# same scale factor
x = np.zeros((5, 5), dtype=np.double)
x[1, 1] = 1
scaled = rescale(x, 2, order=0,
multichannel=False, anti_aliasing=False, mode='constant')
ref = np.zeros((10, 10))
ref[2:4, 2:4] = 1
assert_almost_equal(scaled, ref)
# different scale factors
x = np.zeros((5, 5), dtype=np.double)
x[1, 1] = 1
scaled = rescale(x, (2, 1), order=0,
multichannel=False, anti_aliasing=False, mode='constant')
ref = np.zeros((10, 5))
ref[2:4, 1] = 1
assert_almost_equal(scaled, ref)
def test_rescale_invalid_scale():
x = np.zeros((10, 10, 3))
with testing.raises(ValueError):
rescale(x, (2, 2),
multichannel=False, anti_aliasing=False, mode='constant')
with testing.raises(ValueError):
rescale(x, (2, 2, 2),
multichannel=True, anti_aliasing=False, mode='constant')
def test_rescale_multichannel():
# 1D + channels
x = np.zeros((8, 3), dtype=np.double)
scaled = rescale(x, 2, order=0, multichannel=True, anti_aliasing=False,
mode='constant')
assert_equal(scaled.shape, (16, 3))
# 2D
scaled = rescale(x, 2, order=0, multichannel=False, anti_aliasing=False,
mode='constant')
assert_equal(scaled.shape, (16, 6))
# 2D + channels
x = np.zeros((8, 8, 3), dtype=np.double)
scaled = rescale(x, 2, order=0, multichannel=True, anti_aliasing=False,
mode='constant')
assert_equal(scaled.shape, (16, 16, 3))
# 3D
scaled = rescale(x, 2, order=0, multichannel=False, anti_aliasing=False,
mode='constant')
assert_equal(scaled.shape, (16, 16, 6))
# 3D + channels
x = np.zeros((8, 8, 8, 3), dtype=np.double)
scaled = rescale(x, 2, order=0, multichannel=True, anti_aliasing=False,
mode='constant')
assert_equal(scaled.shape, (16, 16, 16, 3))
# 4D
scaled = rescale(x, 2, order=0, multichannel=False, anti_aliasing=False,
mode='constant')
assert_equal(scaled.shape, (16, 16, 16, 6))
def test_rescale_multichannel_multiscale():
x = np.zeros((5, 5, 3), dtype=np.double)
scaled = rescale(x, (2, 1), order=0, multichannel=True,
anti_aliasing=False, mode='constant')
assert_equal(scaled.shape, (10, 5, 3))
def test_rescale_multichannel_defaults():
x = np.zeros((8, 3), dtype=np.double)
scaled = rescale(x, 2, order=0, anti_aliasing=False, mode='constant')
assert_equal(scaled.shape, (16, 6))
x = np.zeros((8, 8, 3), dtype=np.double)
scaled = rescale(x, 2, order=0, anti_aliasing=False, mode='constant')
assert_equal(scaled.shape, (16, 16, 6))
def test_resize2d():
x = np.zeros((5, 5), dtype=np.double)
x[1, 1] = 1
resized = resize(x, (10, 10), order=0, anti_aliasing=False,
mode='constant')
ref = np.zeros((10, 10))
ref[2:4, 2:4] = 1
assert_almost_equal(resized, ref)
def test_resize3d_keep():
# keep 3rd dimension
x = np.zeros((5, 5, 3), dtype=np.double)
x[1, 1, :] = 1
resized = resize(x, (10, 10), order=0, anti_aliasing=False,
mode='constant')
with testing.raises(ValueError):
# output_shape too short
resize(x, (10, ), order=0, anti_aliasing=False, mode='constant')
ref = np.zeros((10, 10, 3))
ref[2:4, 2:4, :] = 1
assert_almost_equal(resized, ref)
resized = resize(x, (10, 10, 3), order=0, anti_aliasing=False,
mode='constant')
assert_almost_equal(resized, ref)
def test_resize3d_resize():
# resize 3rd dimension
x = np.zeros((5, 5, 3), dtype=np.double)
x[1, 1, :] = 1
resized = resize(x, (10, 10, 1), order=0, anti_aliasing=False,
mode='constant')
ref = np.zeros((10, 10, 1))
ref[2:4, 2:4] = 1
assert_almost_equal(resized, ref)
def test_resize3d_2din_3dout():
# 3D output with 2D input
x = np.zeros((5, 5), dtype=np.double)
x[1, 1] = 1
resized = resize(x, (10, 10, 1), order=0, anti_aliasing=False,
mode='constant')
ref = np.zeros((10, 10, 1))
ref[2:4, 2:4] = 1
assert_almost_equal(resized, ref)
def test_resize2d_4d():
# resize with extra output dimensions
x = np.zeros((5, 5), dtype=np.double)
x[1, 1] = 1
out_shape = (10, 10, 1, 1)
resized = resize(x, out_shape, order=0, anti_aliasing=False,
mode='constant')
ref = np.zeros(out_shape)
ref[2:4, 2:4, ...] = 1
assert_almost_equal(resized, ref)
def test_resize_nd():
for dim in range(1, 6):
shape = 2 + np.arange(dim) * 2
x = np.ones(shape)
out_shape = np.asarray(shape) * 1.5
resized = resize(x, out_shape, order=0, mode='reflect',
anti_aliasing=False)
expected_shape = 1.5 * shape
assert_equal(resized.shape, expected_shape)
assert np.all(resized == 1)
def test_resize3d_bilinear():
# bilinear 3rd dimension
x = np.zeros((5, 5, 2), dtype=np.double)
x[1, 1, 0] = 0
x[1, 1, 1] = 1
resized = resize(x, (10, 10, 1), order=1, mode='constant',
anti_aliasing=False)
ref = np.zeros((10, 10, 1))
ref[1:5, 1:5, :] = 0.03125
ref[1:5, 2:4, :] = 0.09375
ref[2:4, 1:5, :] = 0.09375
ref[2:4, 2:4, :] = 0.28125
assert_almost_equal(resized, ref)
def test_resize_dtype():
x = np.zeros((5, 5))
x_f32 = x.astype(np.float32)
x_u8 = x.astype(np.uint8)
x_b = x.astype(bool)
assert resize(x, (10, 10), preserve_range=False).dtype == x.dtype
assert resize(x, (10, 10), preserve_range=True).dtype == x.dtype
assert resize(x_u8, (10, 10), preserve_range=False).dtype == np.double
assert resize(x_u8, (10, 10), preserve_range=True).dtype == np.double
assert resize(x_b, (10, 10), preserve_range=False).dtype == np.double
assert resize(x_b, (10, 10), preserve_range=True).dtype == np.double
assert resize(x_f32, (10, 10), preserve_range=False).dtype == x_f32.dtype
assert resize(x_f32, (10, 10), preserve_range=True).dtype == x_f32.dtype
def test_swirl():
image = img_as_float(checkerboard())
swirl_params = {'radius': 80, 'rotation': 0, 'order': 2, 'mode': 'reflect'}
with expected_warnings(['Bi-quadratic.*bug']):
swirled = swirl(image, strength=10, **swirl_params)
unswirled = swirl(swirled, strength=-10, **swirl_params)
assert np.mean(np.abs(image - unswirled)) < 0.01
swirl_params.pop('mode')
with expected_warnings(['Bi-quadratic.*bug']):
swirled = swirl(image, strength=10, **swirl_params)
unswirled = swirl(swirled, strength=-10, **swirl_params)
assert np.mean(np.abs(image[1:-1, 1:-1] - unswirled[1:-1, 1:-1])) < 0.01
def test_const_cval_out_of_range():
img = np.random.randn(100, 100)
cval = - 10
warped = warp(img, AffineTransform(translation=(10, 10)), cval=cval)
assert np.sum(warped == cval) == (2 * 100 * 10 - 10 * 10)
def test_warp_identity():
img = img_as_float(rgb2gray(astronaut()))
assert len(img.shape) == 2
assert np.allclose(img, warp(img, AffineTransform(rotation=0)))
assert not np.allclose(img, warp(img, AffineTransform(rotation=0.1)))
rgb_img = np.transpose(np.asarray([img, np.zeros_like(img), img]),
(1, 2, 0))
warped_rgb_img = warp(rgb_img, AffineTransform(rotation=0.1))
assert np.allclose(rgb_img, warp(rgb_img, AffineTransform(rotation=0)))
assert not np.allclose(rgb_img, warped_rgb_img)
# assert no cross-talk between bands
assert np.all(0 == warped_rgb_img[:, :, 1])
def test_warp_coords_example():
image = astronaut().astype(np.float32)
assert 3 == image.shape[2]
tform = SimilarityTransform(translation=(0, -10))
coords = warp_coords(tform, (30, 30, 3))
map_coordinates(image[:, :, 0], coords[:2])
def test_downsize():
x = np.zeros((10, 10), dtype=np.double)
x[2:4, 2:4] = 1
scaled = resize(x, (5, 5), order=0, anti_aliasing=False, mode='constant')
assert_equal(scaled.shape, (5, 5))
assert_equal(scaled[1, 1], 1)
assert_equal(scaled[2:, :].sum(), 0)
assert_equal(scaled[:, 2:].sum(), 0)
def test_downsize_anti_aliasing():
x = np.zeros((10, 10), dtype=np.double)
x[2, 2] = 1
scaled = resize(x, (5, 5), order=1, anti_aliasing=True, mode='constant')
assert_equal(scaled.shape, (5, 5))
assert np.all(scaled[:3, :3] > 0)
assert_equal(scaled[3:, :].sum(), 0)
assert_equal(scaled[:, 3:].sum(), 0)
sigma = 0.125
out_size = (5, 5)
resize(x, out_size, order=1, mode='constant',
anti_aliasing=True, anti_aliasing_sigma=sigma)
resize(x, out_size, order=1, mode='edge',
anti_aliasing=True, anti_aliasing_sigma=sigma)
resize(x, out_size, order=1, mode='symmetric',
anti_aliasing=True, anti_aliasing_sigma=sigma)
resize(x, out_size, order=1, mode='reflect',
anti_aliasing=True, anti_aliasing_sigma=sigma)
resize(x, out_size, order=1, mode='wrap',
anti_aliasing=True, anti_aliasing_sigma=sigma)
with testing.raises(ValueError): # Unknown mode, or cannot translate mode
resize(x, out_size, order=1, mode='non-existent',
anti_aliasing=True, anti_aliasing_sigma=sigma)
def test_downsize_anti_aliasing_invalid_stddev():
x = np.zeros((10, 10), dtype=np.double)
with testing.raises(ValueError):
resize(x, (5, 5), order=0, anti_aliasing=True, anti_aliasing_sigma=-1,
mode='constant')
with expected_warnings(["Anti-aliasing standard deviation greater"]):
resize(x, (5, 15), order=0, anti_aliasing=True,
anti_aliasing_sigma=(1, 1), mode="reflect")
resize(x, (5, 15), order=0, anti_aliasing=True,
anti_aliasing_sigma=(0, 1), mode="reflect")
def test_downscale():
x = np.zeros((10, 10), dtype=np.double)
x[2:4, 2:4] = 1
scaled = rescale(x, 0.5, order=0, anti_aliasing=False,
multichannel=False, mode='constant')
assert_equal(scaled.shape, (5, 5))
assert_equal(scaled[1, 1], 1)
assert_equal(scaled[2:, :].sum(), 0)
assert_equal(scaled[:, 2:].sum(), 0)
def test_downscale_anti_aliasing():
x = np.zeros((10, 10), dtype=np.double)
x[2, 2] = 1
scaled = rescale(x, 0.5, order=1, anti_aliasing=True,
multichannel=False, mode='constant')
assert_equal(scaled.shape, (5, 5))
assert np.all(scaled[:3, :3] > 0)
assert_equal(scaled[3:, :].sum(), 0)
assert_equal(scaled[:, 3:].sum(), 0)
def test_downscale_local_mean():
image1 = np.arange(4 * 6).reshape(4, 6)
out1 = downscale_local_mean(image1, (2, 3))
expected1 = np.array([[4., 7.],
[16., 19.]])
assert_equal(expected1, out1)
image2 = np.arange(5 * 8).reshape(5, 8)
out2 = downscale_local_mean(image2, (4, 5))
expected2 = np.array([[14., 10.8],
[8.5, 5.7]])
assert_equal(expected2, out2)
def test_invalid():
with testing.raises(ValueError):
warp(np.ones((4, 3, 3, 3)),
SimilarityTransform())
def test_inverse():
tform = SimilarityTransform(scale=0.5, rotation=0.1)
inverse_tform = SimilarityTransform(matrix=np.linalg.inv(tform.params))
image = np.arange(10 * 10).reshape(10, 10).astype(np.double)
assert_equal(warp(image, inverse_tform), warp(image, tform.inverse))
def test_slow_warp_nonint_oshape():
image = np.random.rand(5, 5)
with testing.raises(ValueError):
warp(image, lambda xy: xy,
output_shape=(13.1, 19.5))
warp(image, lambda xy: xy, output_shape=(13.0001, 19.9999))
def test_keep_range():
image = np.linspace(0, 2, 25).reshape(5, 5)
out = rescale(image, 2, preserve_range=False, clip=True, order=0,
mode='constant', multichannel=False, anti_aliasing=False)
assert out.min() == 0
assert out.max() == 2
out = rescale(image, 2, preserve_range=True, clip=True, order=0,
mode='constant', multichannel=False, anti_aliasing=False)
assert out.min() == 0
assert out.max() == 2
out = rescale(image.astype(np.uint8), 2, preserve_range=False,
mode='constant', multichannel=False, anti_aliasing=False,
clip=True, order=0)
assert out.min() == 0
assert out.max() == 2 / 255.0
def test_zero_image_size():
with testing.raises(ValueError):
warp(np.zeros(0),
SimilarityTransform())
with testing.raises(ValueError):
warp(np.zeros((0, 10)),
SimilarityTransform())
with testing.raises(ValueError):
warp(np.zeros((10, 0)),
SimilarityTransform())
with testing.raises(ValueError):
warp(np.zeros((10, 10, 0)),
SimilarityTransform())
def test_linear_polar_mapping():
output_coords = np.array([[0, 0],
[0, 90],
[0, 180],
[0, 270],
[99, 0],
[99, 180],
[99, 270],
[99, 45]])
ground_truth = np.array([[100, 100],
[100, 100],
[100, 100],
[100, 100],
[199, 100],
[1, 100],
[100, 1],
[170.00357134, 170.00357134]])
k_angle = 360 / (2 * np.pi)
k_radius = 1
center = (100, 100)
coords = _linear_polar_mapping(output_coords, k_angle, k_radius, center)
assert np.allclose(coords, ground_truth)
def test_log_polar_mapping():
output_coords = np.array([[0, 0],
[0, 90],
[0, 180],
[0, 270],
[99, 0],
[99, 180],
[99, 270],
[99, 45]])
ground_truth = np.array([[101, 100],
[100, 101],
[99, 100],
[100, 99],
[195.4992586, 100],
[4.5007414, 100],
[100, 4.5007414],
[167.52817336, 167.52817336]])
k_angle = 360 / (2 * np.pi)
k_radius = 100 / np.log(100)
center = (100, 100)
coords = _log_polar_mapping(output_coords, k_angle, k_radius, center)
assert np.allclose(coords, ground_truth)
def test_linear_warp_polar():
radii = [5, 10, 15, 20]
image = np.zeros([51, 51])
for rad in radii:
rr, cc, val = circle_perimeter_aa(25, 25, rad)
image[rr, cc] = val
warped = warp_polar(image, radius=25)
profile = warped.mean(axis=0)
peaks = peak_local_max(profile)
assert np.alltrue([peak in radii for peak in peaks])
def test_log_warp_polar():
radii = [np.exp(2), np.exp(3), np.exp(4), np.exp(5),
np.exp(5)-1, np.exp(5)+1]
radii = [int(x) for x in radii]
image = np.zeros([301, 301])
for rad in radii:
rr, cc, val = circle_perimeter_aa(150, 150, rad)
image[rr, cc] = val
warped = warp_polar(image, radius=200, scaling='log')
profile = warped.mean(axis=0)
peaks_coord = peak_local_max(profile)
peaks_coord.sort(axis=0)
gaps = peaks_coord[1:] - peaks_coord[:-1]
assert np.alltrue([x >= 38 and x <= 40 for x in gaps])
def test_invalid_scaling_polar():
with testing.raises(ValueError):
warp_polar(np.zeros((10, 10)), (5, 5), scaling='invalid')
with testing.raises(ValueError):
warp_polar(np.zeros((10, 10)), (5, 5), scaling=None)
def test_invalid_dimensions_polar():
with testing.raises(ValueError):
warp_polar(np.zeros((10, 10, 3)), (5, 5))
with testing.raises(ValueError):
warp_polar(np.zeros((10, 10)), (5, 5), multichannel=True)
with testing.raises(ValueError):
warp_polar(np.zeros((10, 10, 10, 3)), (5, 5), multichannel=True)
def test_bool_img_rescale():
img = np.ones((12, 18), dtype=bool)
img[2:-2, 4:-4] = False
res = rescale(img, 0.5)
expected = np.ones((6, 9))
expected[1:-1, 2:-2] = False
assert_equal(res, expected)
def test_bool_img_resize():
img = np.ones((12, 18), dtype=bool)
img[2:-2, 4:-4] = False
res = resize(img, (6, 9))
expected = np.ones((6, 9))
expected[1:-1, 2:-2] = False
assert_equal(res, expected)
def test_boll_array_warnings():
img = np.zeros((10, 10), dtype=bool)
with expected_warnings(['Input image dtype is bool']):
rescale(img, 0.5, anti_aliasing=True)
with expected_warnings(['Input image dtype is bool']):
resize(img, (5, 5), anti_aliasing=True)
with expected_warnings(['Input image dtype is bool']):
rescale(img, 0.5, order=1)
with expected_warnings(['Input image dtype is bool']):
resize(img, (5, 5), order=1)
with expected_warnings(['Input image dtype is bool']):
warp(img, np.eye(3), order=1)