mirror of
https://github.com/wassname/scikit-image.git
synced 2026-07-17 11:32:45 +08:00
Merge pull request #1008 from ahojnnes/coverage
Improve coverage and docstrings for subpixel corner detection
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
"""
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user