Files
scikit-image/skimage/feature/tests/test_template.py
T
2012-05-08 21:32:08 -04:00

119 lines
3.8 KiB
Python

import numpy as np
from numpy.testing import assert_array_almost_equal as assert_close
from skimage.morphology import diamond
from skimage.feature import match_template, peak_local_max
def test_template():
size = 100
# Type conversion of image and target not required but prevents warnings.
image = np.zeros((400, 400), dtype=np.float32)
target = np.tri(size) + np.tri(size)[::-1]
target = target.astype(np.float32)
target_positions = [(50, 50), (200, 200)]
for x, y in target_positions:
image[x:x + size, y:y + size] = target
np.random.seed(1)
image += np.random.randn(400, 400) * 2
result = match_template(image, target)
delta = 5
positions = peak_local_max(result, min_distance=delta)
if len(positions) > 2:
# Keep the two maximum peaks.
intensities = result[tuple(positions.T)]
i_maxsort = np.argsort(intensities)[::-1]
positions = positions[i_maxsort][:2]
# Sort so that order matches `target_positions`.
positions = positions[np.argsort(positions[:, 0])]
for xy_target, xy in zip(target_positions, positions):
yield assert_close, xy, xy_target
def test_normalization():
"""Test that `match_template` gives the correct normalization.
Normalization gives 1 for a perfect match and -1 for an inverted-match.
This test adds positive and negative squares to a zero-array and matches
the array with a positive template.
"""
n = 5
N = 20
ipos, jpos = (2, 3)
ineg, jneg = (12, 11)
image = np.zeros((N, N))
image[ipos:ipos + n, jpos:jpos + n] = 10
image[ineg:ineg + n, jneg:jneg + n] = -10
# white square with a black border
template = np.zeros((n+2, n+2))
template[1:1+n, 1:1+n] = 1
result = match_template(image, template)
# get the max and min results.
sorted_result = np.argsort(result.flat)
iflat_min = sorted_result[0]
iflat_max = sorted_result[-1]
min_result = np.unravel_index(iflat_min, result.shape)
max_result = np.unravel_index(iflat_max, result.shape)
# shift result by 1 because of template border
assert np.all((np.array(min_result) + 1) == (ineg, jneg))
assert np.all((np.array(max_result) + 1) == (ipos, jpos))
assert np.allclose(result.flat[iflat_min], -1)
assert np.allclose(result.flat[iflat_max], 1)
def test_no_nans():
"""Test that `match_template` doesn't return NaN values.
When image values are only slightly different, floating-point errors can
cause a subtraction inside of a square root to go negative (without an
explicit check that was added to `match_template`).
"""
np.random.seed(1)
image = 10000 + np.random.normal(size=(20, 20))
template = np.ones((6, 6))
template[:3, :] = 0
result = match_template(image, template)
assert not np.any(np.isnan(result))
def test_switched_arguments():
image = np.ones((5, 5))
template = np.ones((3, 3))
np.testing.assert_raises(ValueError, match_template, template, image)
def test_pad_input():
template = 10.0 * diamond(2)
image = np.zeros((9, 19))
mid = slice(2, 7)
image[mid, :3] = -template[:, -3:] # half min template centered at 0
image[mid, 4:9] = template # full max template centered at 6
image[mid, -9:-4] = -template # full min template centered at 12
image[mid, -3:] = template[:, :3] # half max template centered at 18
result = match_template(image, template, pad_input=True)
# get the max and min results.
sorted_result = np.argsort(result.flat)
i, j = np.unravel_index(sorted_result[:2], result.shape)
assert_close(j, (12, 0))
i, j = np.unravel_index(sorted_result[-2:], result.shape)
assert_close(j, (18, 6))
if __name__ == "__main__":
from numpy import testing
testing.run_module_suite()