Merge pull request #1008 from ahojnnes/coverage

Improve coverage and docstrings for subpixel corner detection
This commit is contained in:
Stefan van der Walt
2014-05-12 23:17:50 +02:00
8 changed files with 99 additions and 17 deletions
+27 -8
View File
@@ -624,6 +624,13 @@ def corner_fast(image, n=12, threshold=0.15):
def corner_subpix(image, corners, window_size=11, alpha=0.99):
"""Determine subpixel position of corners.
A statistical test decides whether the corner is defined as the
intersection of two edges or a single peak. Depending on the classification
result, the subpixel corner location is determined based on the local
covariance of the grey-values. If the significance level for either
statistical test is not sufficient, the corner cannot be classified, and
the output subpixel position is set to NaN.
Parameters
----------
image : ndarray
@@ -633,7 +640,7 @@ def corner_subpix(image, corners, window_size=11, alpha=0.99):
window_size : int, optional
Search window size for subpixel estimation.
alpha : float, optional
Significance level for point classification.
Significance level for corner classification.
Returns
-------
@@ -737,8 +744,13 @@ def corner_subpix(image, corners, window_size=11, alpha=0.99):
b_edge[:] = byy_y + bxy_x, bxx_x + bxy_y
# estimated positions
est_dot = np.linalg.solve(N_dot, b_dot)
est_edge = np.linalg.solve(N_edge, b_edge)
try:
est_dot = np.linalg.solve(N_dot, b_dot)
est_edge = np.linalg.solve(N_edge, b_edge)
except np.linalg.LinAlgError:
# if image is constant the system is singular
corners_subpix[i, :] = np.nan, np.nan
continue
# residuals
ry_dot = y - est_dot[0]
@@ -759,12 +771,19 @@ def corner_subpix(image, corners, window_size=11, alpha=0.99):
+ winy_winy * rxx_dot)
var_edge = np.sum(winy_winy * ryy_edge + 2 * winx_winy * rxy_edge \
+ winx_winx * rxx_edge)
# test value (F-distributed)
t = var_edge / var_dot
# 1 for edge, -1 for dot, 0 for "not classified"
corner_class = (t < t_crit_edge) - (t > t_crit_dot)
if corner_class == - 1:
# test value (F-distributed)
if var_dot < np.spacing(1) and var_edge < np.spacing(1):
t = np.nan
elif var_dot == 0:
t = np.inf
else:
t = var_edge / var_dot
# 1 for edge, -1 for dot, 0 for "not classified"
corner_class = int(t < t_crit_edge) - int(t > t_crit_dot)
if corner_class == -1:
corners_subpix[i, :] = y0 + est_dot[0], x0 + est_dot[1]
elif corner_class == 0:
corners_subpix[i, :] = np.nan, np.nan
+20 -1
View File
@@ -188,7 +188,7 @@ def test_rotated_lena():
assert (np.sort(results[:, 1]) == np.sort(results_rotated[:, 0])).all()
def test_subpix():
def test_subpix_edge():
img = np.zeros((50, 50))
img[:25, :25] = 255
img[25:, 25:] = 255
@@ -197,6 +197,25 @@ def test_subpix():
assert_array_equal(subpix[0], (24.5, 24.5))
def test_subpix_dot():
img = np.zeros((50, 50))
img[25, 25] = 255
corner = peak_local_max(corner_harris(img), num_peaks=1)
subpix = corner_subpix(img, corner)
assert_array_equal(subpix[0], (25, 25))
def test_subpix_no_class():
img = np.zeros((50, 50))
subpix = corner_subpix(img, np.array([[25, 25]]))
assert_array_equal(subpix[0], (np.nan, np.nan))
img[25, 25] = 1e-10
corner = peak_local_max(corner_harris(img), num_peaks=1)
subpix = corner_subpix(img, np.array([[25, 25]]))
assert_array_equal(subpix[0], (np.nan, np.nan))
def test_subpix_border():
img = np.zeros((50, 50))
img[1:25,1:25] = 255
+3 -3
View File
@@ -384,10 +384,10 @@ def threshold_percentile(image, selem, out=None, mask=None, shift_x=False,
p0 : float in [0, ..., 1]
Set the percentile value.
out : 2-D array (same dtype as input image)
Returns
-------
out : 2-D array (same dtype as input image)
Output image.
local threshold : ndarray (same dtype as input)
The result of the local threshold.
"""
+2 -2
View File
@@ -131,11 +131,11 @@ def reconstruction(seed, mask, method='dilation', selem=None, offset=None):
if selem is None:
selem = np.ones([3] * seed.ndim, dtype=bool)
else:
selem = selem.copy()
selem = selem.astype(bool, copy=True)
if offset is None:
if not all([d % 2 == 1 for d in selem.shape]):
ValueError("Footprint dimensions must all be odd")
raise ValueError("Footprint dimensions must all be odd")
offset = np.array([d // 2 for d in selem.shape])
# Cross out the center of the selem
selem[[slice(d, d + 1) for d in offset]] = False
@@ -8,7 +8,8 @@ All rights reserved.
Original author: Lee Kamentsky
"""
import numpy as np
from numpy.testing import assert_array_almost_equal as assert_close
from numpy.testing import (assert_array_almost_equal as assert_close,
assert_raises)
from skimage.morphology.greyreconstruct import reconstruction
@@ -77,6 +78,25 @@ def test_fill_hole():
assert_close(result, np.array([0, 3, 6, 4, 4, 4, 4, 4, 2, 0]))
def test_invalid_seed():
seed = np.ones((5, 5))
mask = np.ones((5, 5))
assert_raises(ValueError, reconstruction, seed * 2, mask,
method='dilation')
assert_raises(ValueError, reconstruction, seed * 0.5, mask,
method='erosion')
def test_invalid_selem():
seed = np.ones((5, 5))
mask = np.ones((5, 5))
assert_raises(ValueError, reconstruction, seed, mask,
selem=np.ones((4, 4)))
assert_raises(ValueError, reconstruction, seed, mask,
selem=np.ones((3, 4)))
reconstruction(seed, mask, selem=np.ones((3, 3)))
if __name__ == '__main__':
from numpy import testing
testing.run_module_suite()
+7
View File
@@ -137,5 +137,12 @@ def test_mask():
assert_array_almost_equal(image_unwrapped_3d[:, :, -1], image[i, -1])
def test_invalid_input():
assert_raises(ValueError, unwrap_phase, np.zeros([]))
assert_raises(ValueError, unwrap_phase, np.zeros((1, 1, 1, 1)))
assert_raises(ValueError, unwrap_phase, np.zeros((1, 1)), 3 * [False])
assert_raises(ValueError, unwrap_phase, np.zeros((1, 1)), 'False')
if __name__ == "__main__":
run_module_suite()
+2 -2
View File
@@ -620,9 +620,9 @@ class SimilarityTransform(ProjectiveTransform):
@property
def scale(self):
if math.cos(self.rotation) == 0:
if abs(math.cos(self.rotation)) < np.spacing(1):
# sin(self.rotation) == 1
scale = self.params[0, 1]
scale = self.params[1, 0]
else:
scale = self.params[0, 0] / math.cos(self.rotation)
return scale
+17
View File
@@ -99,6 +99,17 @@ def test_similarity_init():
assert_array_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_array_almost_equal(tform.scale, scale)
assert_array_almost_equal(tform.rotation, rotation)
assert_array_almost_equal(tform.translation, translation)
def test_affine_estimation():
# exact solution
tform = estimate_transform('affine', SRC[:3, :], DST[:3, :])
@@ -208,6 +219,12 @@ def test_union():
assert tform.__class__ == ProjectiveTransform
def test_union_differing_types():
tform1 = SimilarityTransform()
tform2 = PolynomialTransform()
assert_raises(TypeError, tform1.__add__, tform2)
def test_geometric_tform():
tform = GeometricTransform()
assert_raises(NotImplementedError, tform, 0)