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,445 @@
import numpy as np
from skimage.draw import disk
from skimage.draw.draw3d import ellipsoid
from skimage.feature import blob_dog, blob_log, blob_doh
from skimage.feature.blob import _blob_overlap
import math
from numpy.testing import assert_almost_equal
def test_blob_dog():
r2 = math.sqrt(2)
img = np.ones((512, 512))
xs, ys = disk((400, 130), 5)
img[xs, ys] = 255
xs, ys = disk((100, 300), 25)
img[xs, ys] = 255
xs, ys = disk((200, 350), 45)
img[xs, ys] = 255
blobs = blob_dog(img, min_sigma=5, max_sigma=50)
radius = lambda x: r2 * x[2]
s = sorted(blobs, key=radius)
thresh = 5
b = s[0]
assert abs(b[0] - 400) <= thresh
assert abs(b[1] - 130) <= thresh
assert abs(radius(b) - 5) <= thresh
b = s[1]
assert abs(b[0] - 100) <= thresh
assert abs(b[1] - 300) <= thresh
assert abs(radius(b) - 25) <= thresh
b = s[2]
assert abs(b[0] - 200) <= thresh
assert abs(b[1] - 350) <= thresh
assert abs(radius(b) - 45) <= thresh
# Testing no peaks
img_empty = np.zeros((100,100))
assert blob_dog(img_empty).size == 0
# Testing 3D
r = 10
pad = 10
im3 = ellipsoid(r, r, r)
im3 = np.pad(im3, pad, mode='constant')
blobs = blob_dog(im3, min_sigma=3, max_sigma=10,
sigma_ratio=1.2, threshold=0.1)
b = blobs[0]
assert b.shape == (4,)
assert b[0] == r + pad + 1
assert b[1] == r + pad + 1
assert b[2] == r + pad + 1
assert abs(math.sqrt(3) * b[3] - r) < 1
# Testing 3D anisotropic
r = 10
pad = 10
im3 = ellipsoid(r / 2, r, r)
im3 = np.pad(im3, pad, mode='constant')
blobs = blob_dog(
im3,
min_sigma=[1.5, 3, 3],
max_sigma=[5, 10, 10],
sigma_ratio=1.2,
threshold=0.1
)
b = blobs[0]
assert b.shape == (6,)
assert b[0] == r / 2 + pad + 1
assert b[1] == r + pad + 1
assert b[2] == r + pad + 1
assert abs(math.sqrt(3) * b[3] - r / 2) < 1
assert abs(math.sqrt(3) * b[4] - r) < 1
assert abs(math.sqrt(3) * b[5] - r) < 1
# Testing exclude border
# image where blob is 5 px from borders, radius 5
img = np.ones((512, 512))
xs, ys = disk((5, 5), 5)
img[xs, ys] = 255
def test_blob_dog_excl_border():
img = np.ones((512, 512))
xs, ys = disk((5, 5), 5)
img[xs, ys] = 255
blobs = blob_dog(
img,
min_sigma=1.5,
max_sigma=5,
sigma_ratio=1.2,
)
assert blobs.shape[0] == 1
b = blobs[0]
assert b[0] == b[1] == 5, "blob should be 5 px from x and y borders"
blobs = blob_dog(
img,
min_sigma=1.5,
max_sigma=5,
sigma_ratio=1.2,
exclude_border=6,
)
msg = "zero blobs should be detected, as only blob is 5 px from border"
assert blobs.shape[0] == 0, msg
def test_blob_log():
r2 = math.sqrt(2)
img = np.ones((256, 256))
xs, ys = disk((200, 65), 5)
img[xs, ys] = 255
xs, ys = disk((80, 25), 15)
img[xs, ys] = 255
xs, ys = disk((50, 150), 25)
img[xs, ys] = 255
xs, ys = disk((100, 175), 30)
img[xs, ys] = 255
blobs = blob_log(img, min_sigma=5, max_sigma=20, threshold=1)
radius = lambda x: r2 * x[2]
s = sorted(blobs, key=radius)
thresh = 3
b = s[0]
assert abs(b[0] - 200) <= thresh
assert abs(b[1] - 65) <= thresh
assert abs(radius(b) - 5) <= thresh
b = s[1]
assert abs(b[0] - 80) <= thresh
assert abs(b[1] - 25) <= thresh
assert abs(radius(b) - 15) <= thresh
b = s[2]
assert abs(b[0] - 50) <= thresh
assert abs(b[1] - 150) <= thresh
assert abs(radius(b) - 25) <= thresh
b = s[3]
assert abs(b[0] - 100) <= thresh
assert abs(b[1] - 175) <= thresh
assert abs(radius(b) - 30) <= thresh
# Testing log scale
blobs = blob_log(
img,
min_sigma=5,
max_sigma=20,
threshold=1,
log_scale=True)
b = s[0]
assert abs(b[0] - 200) <= thresh
assert abs(b[1] - 65) <= thresh
assert abs(radius(b) - 5) <= thresh
b = s[1]
assert abs(b[0] - 80) <= thresh
assert abs(b[1] - 25) <= thresh
assert abs(radius(b) - 15) <= thresh
b = s[2]
assert abs(b[0] - 50) <= thresh
assert abs(b[1] - 150) <= thresh
assert abs(radius(b) - 25) <= thresh
b = s[3]
assert abs(b[0] - 100) <= thresh
assert abs(b[1] - 175) <= thresh
assert abs(radius(b) - 30) <= thresh
# Testing no peaks
img_empty = np.zeros((100,100))
assert blob_log(img_empty).size == 0
def test_blob_log_3d():
# Testing 3D
r = 6
pad = 10
im3 = ellipsoid(r, r, r)
im3 = np.pad(im3, pad, mode='constant')
blobs = blob_log(im3, min_sigma=3, max_sigma=10)
b = blobs[0]
assert b.shape == (4,)
assert b[0] == r + pad + 1
assert b[1] == r + pad + 1
assert b[2] == r + pad + 1
assert abs(math.sqrt(3) * b[3] - r) < 1
def test_blob_log_3d_anisotropic():
# Testing 3D anisotropic
r = 6
pad = 10
im3 = ellipsoid(r / 2, r, r)
im3 = np.pad(im3, pad, mode='constant')
blobs = blob_log(
im3,
min_sigma=[1, 2, 2],
max_sigma=[5, 10, 10],
)
b = blobs[0]
assert b.shape == (6,)
assert b[0] == r / 2 + pad + 1
assert b[1] == r + pad + 1
assert b[2] == r + pad + 1
assert abs(math.sqrt(3) * b[3] - r / 2) < 1
assert abs(math.sqrt(3) * b[4] - r) < 1
assert abs(math.sqrt(3) * b[5] - r) < 1
def test_blob_log_exclude_border():
# image where blob is 5 px from borders, radius 5
img = np.ones((512, 512))
xs, ys = disk((5, 5), 5)
img[xs, ys] = 255
blobs = blob_log(
img,
min_sigma=1.5,
max_sigma=5,
)
assert blobs.shape[0] == 1
b = blobs[0]
assert b[0] == b[1] == 5, "blob should be 5 px from x and y borders"
blobs = blob_log(
img,
min_sigma=1.5,
max_sigma=5,
exclude_border=6,
)
msg = "zero blobs should be detected, as only blob is 5 px from border"
assert blobs.shape[0] == 0, msg
def test_blob_doh():
img = np.ones((512, 512), dtype=np.uint8)
xs, ys = disk((400, 130), 20)
img[xs, ys] = 255
xs, ys = disk((460, 50), 30)
img[xs, ys] = 255
xs, ys = disk((100, 300), 40)
img[xs, ys] = 255
xs, ys = disk((200, 350), 50)
img[xs, ys] = 255
blobs = blob_doh(
img,
min_sigma=1,
max_sigma=60,
num_sigma=10,
threshold=.05)
radius = lambda x: x[2]
s = sorted(blobs, key=radius)
thresh = 4
b = s[0]
assert abs(b[0] - 400) <= thresh
assert abs(b[1] - 130) <= thresh
assert abs(radius(b) - 20) <= thresh
b = s[1]
assert abs(b[0] - 460) <= thresh
assert abs(b[1] - 50) <= thresh
assert abs(radius(b) - 30) <= thresh
b = s[2]
assert abs(b[0] - 100) <= thresh
assert abs(b[1] - 300) <= thresh
assert abs(radius(b) - 40) <= thresh
b = s[3]
assert abs(b[0] - 200) <= thresh
assert abs(b[1] - 350) <= thresh
assert abs(radius(b) - 50) <= thresh
def test_blob_doh_log_scale():
img = np.ones((512, 512), dtype=np.uint8)
xs, ys = disk((400, 130), 20)
img[xs, ys] = 255
xs, ys = disk((460, 50), 30)
img[xs, ys] = 255
xs, ys = disk((100, 300), 40)
img[xs, ys] = 255
xs, ys = disk((200, 350), 50)
img[xs, ys] = 255
blobs = blob_doh(
img,
min_sigma=1,
max_sigma=60,
num_sigma=10,
log_scale=True,
threshold=.05)
radius = lambda x: x[2]
s = sorted(blobs, key=radius)
thresh = 10
b = s[0]
assert abs(b[0] - 400) <= thresh
assert abs(b[1] - 130) <= thresh
assert abs(radius(b) - 20) <= thresh
b = s[2]
assert abs(b[0] - 460) <= thresh
assert abs(b[1] - 50) <= thresh
assert abs(radius(b) - 30) <= thresh
b = s[1]
assert abs(b[0] - 100) <= thresh
assert abs(b[1] - 300) <= thresh
assert abs(radius(b) - 40) <= thresh
b = s[3]
assert abs(b[0] - 200) <= thresh
assert abs(b[1] - 350) <= thresh
assert abs(radius(b) - 50) <= thresh
def test_blob_doh_no_peaks():
# Testing no peaks
img_empty = np.zeros((100,100))
assert blob_doh(img_empty).size == 0
def test_blob_doh_overlap():
img = np.ones((256, 256), dtype=np.uint8)
xs, ys = disk((100, 100), 20)
img[xs, ys] = 255
xs, ys = disk((120, 100), 30)
img[xs, ys] = 255
blobs = blob_doh(
img,
min_sigma=1,
max_sigma=60,
num_sigma=10,
threshold=.05
)
assert len(blobs) == 1
def test_blob_log_overlap_3d():
r1, r2 = 7, 6
pad1, pad2 = 11, 12
blob1 = ellipsoid(r1, r1, r1)
blob1 = np.pad(blob1, pad1, mode='constant')
blob2 = ellipsoid(r2, r2, r2)
blob2 = np.pad(blob2, [(pad2, pad2), (pad2 - 9, pad2 + 9),
(pad2, pad2)],
mode='constant')
im3 = np.logical_or(blob1, blob2)
blobs = blob_log(im3, min_sigma=2, max_sigma=10, overlap=0.1)
assert len(blobs) == 1
def test_blob_overlap_3d_anisotropic():
# Two spheres with distance between centers equal to radius
# One sphere is much smaller than the other so about half of it is within
# the bigger sphere.
s3 = math.sqrt(3)
overlap = _blob_overlap(np.array([0, 0, 0, 2 / s3, 10 / s3, 10 / s3]),
np.array([0, 0, 10, 0.2 / s3, 1 / s3, 1 / s3]),
sigma_dim=3)
assert_almost_equal(overlap, 0.48125)
overlap = _blob_overlap(np.array([0, 0, 0, 2 / s3, 10 / s3, 10 / s3]),
np.array([2, 0, 0, 0.2 / s3, 1 / s3, 1 / s3]),
sigma_dim=3)
assert_almost_equal(overlap, 0.48125)
def test_blob_log_anisotropic():
image = np.zeros((50, 50))
image[20, 10:20] = 1
isotropic_blobs = blob_log(image, min_sigma=0.5, max_sigma=2, num_sigma=3)
assert len(isotropic_blobs) > 1 # many small blobs found in line
ani_blobs = blob_log(image, min_sigma=[0.5, 5], max_sigma=[2, 20],
num_sigma=3) # 10x anisotropy, line is 1x10
assert len(ani_blobs) == 1 # single anisotropic blob found
def test_blob_log_overlap_3d_anisotropic():
r1, r2 = 7, 6
pad1, pad2 = 11, 12
blob1 = ellipsoid(r1, r1, r1)
blob1 = np.pad(blob1, pad1, mode='constant')
blob2 = ellipsoid(r2, r2, r2)
blob2 = np.pad(blob2, [(pad2, pad2), (pad2 - 9, pad2 + 9),
(pad2, pad2)],
mode='constant')
im3 = np.logical_or(blob1, blob2)
blobs = blob_log(im3, min_sigma=[2, 2.01, 2.005],
max_sigma=10, overlap=0.1)
assert len(blobs) == 1
# Two circles with distance between centers equal to radius
overlap = _blob_overlap(np.array([0, 0, 10 / math.sqrt(2)]),
np.array([0, 10, 10 / math.sqrt(2)]))
assert_almost_equal(overlap,
1./math.pi * (2 * math.acos(1./2) - math.sqrt(3)/2.))
def test_no_blob():
im = np.zeros((10, 10))
blobs = blob_log(im, min_sigma=2, max_sigma=5, num_sigma=4)
assert len(blobs) == 0

View file

@ -0,0 +1,80 @@
import pytest
import numpy as np
from skimage._shared.testing import assert_array_equal
from skimage import data
from skimage.feature import BRIEF, corner_peaks, corner_harris
from skimage._shared import testing
def test_color_image_unsupported_error():
"""Brief descriptors can be evaluated on gray-scale images only."""
img = np.zeros((20, 20, 3))
keypoints = np.asarray([[7, 5], [11, 13]])
with testing.raises(ValueError):
BRIEF().extract(img, keypoints)
@pytest.mark.parametrize('dtype', ['float32', 'float64', 'uint8', 'int'])
def test_normal_mode(dtype):
"""Verify the computed BRIEF descriptors with expected for normal mode."""
img = data.coins().astype(dtype)
keypoints = corner_peaks(corner_harris(img), min_distance=5,
threshold_abs=0, threshold_rel=0.1)
extractor = BRIEF(descriptor_size=8, sigma=2)
extractor.extract(img, keypoints[:8])
expected = np.array([[1, 0, 1, 0, 0, 1, 0, 1],
[1, 1, 1, 0, 1, 0, 1, 1],
[1, 0, 1, 0, 0, 1, 0, 1],
[0, 1, 0, 0, 1, 0, 1, 0],
[1, 1, 1, 0, 0, 0, 1, 1],
[1, 1, 1, 0, 1, 1, 1, 1],
[1, 0, 1, 0, 0, 1, 0, 1],
[0, 0, 0, 0, 0, 1, 0, 0]], dtype=bool)
assert_array_equal(extractor.descriptors, expected)
@pytest.mark.parametrize('dtype', ['float32', 'float64', 'uint8', 'int'])
def test_uniform_mode(dtype):
"""Verify the computed BRIEF descriptors with expected for uniform mode."""
img = data.coins().astype(dtype)
keypoints = corner_peaks(corner_harris(img), min_distance=5,
threshold_abs=0, threshold_rel=0.1)
extractor = BRIEF(descriptor_size=8, sigma=2, mode='uniform')
extractor.extract(img, keypoints[:8])
expected = np.array([[1, 1, 0, 0, 0, 0, 0, 0],
[1, 1, 1, 0, 0, 1, 0, 0],
[1, 1, 0, 0, 1, 0, 0, 0],
[0, 0, 0, 1, 1, 1, 1, 1],
[1, 1, 1, 0, 0, 1, 0, 0],
[1, 1, 1, 1, 0, 1, 0, 0],
[1, 1, 0, 0, 0, 1, 0, 0],
[0, 1, 1, 1, 0, 1, 1, 1]], dtype=bool)
assert_array_equal(extractor.descriptors, expected)
def test_unsupported_mode():
with testing.raises(ValueError):
BRIEF(mode='foobar')
@pytest.mark.parametrize('dtype', ['float32', 'float64', 'uint8', 'int'])
def test_border(dtype):
img = np.zeros((100, 100), dtype=dtype)
keypoints = np.array([[1, 1], [20, 20], [50, 50], [80, 80]])
extractor = BRIEF(patch_size=41)
extractor.extract(img, keypoints)
assert extractor.descriptors.shape[0] == 3
assert_array_equal(extractor.mask, (False, True, True, True))

View file

@ -0,0 +1,121 @@
import unittest
import numpy as np
from skimage._shared.testing import assert_equal
from scipy.ndimage import binary_dilation, binary_erosion
import skimage.feature as F
from skimage import data, img_as_float
class TestCanny(unittest.TestCase):
def test_00_00_zeros(self):
'''Test that the Canny filter finds no points for a blank field'''
result = F.canny(np.zeros((20, 20)), 4, 0, 0, np.ones((20, 20), bool))
self.assertFalse(np.any(result))
def test_00_01_zeros_mask(self):
'''Test that the Canny filter finds no points in a masked image'''
result = (F.canny(np.random.uniform(size=(20, 20)), 4, 0, 0,
np.zeros((20, 20), bool)))
self.assertFalse(np.any(result))
def test_01_01_circle(self):
'''Test that the Canny filter finds the outlines of a circle'''
i, j = np.mgrid[-200:200, -200:200].astype(float) / 200
c = np.abs(np.sqrt(i * i + j * j) - .5) < .02
result = F.canny(c.astype(float), 4, 0, 0, np.ones(c.shape, bool))
#
# erode and dilate the circle to get rings that should contain the
# outlines
#
cd = binary_dilation(c, iterations=3)
ce = binary_erosion(c, iterations=3)
cde = np.logical_and(cd, np.logical_not(ce))
self.assertTrue(np.all(cde[result]))
#
# The circle has a radius of 100. There are two rings here, one
# for the inside edge and one for the outside. So that's
# 100 * 2 * 2 * 3 for those places where pi is still 3.
# The edge contains both pixels if there's a tie, so we
# bump the count a little.
point_count = np.sum(result)
self.assertTrue(point_count > 1200)
self.assertTrue(point_count < 1600)
def test_01_02_circle_with_noise(self):
'''Test that the Canny filter finds the circle outlines
in a noisy image'''
np.random.seed(0)
i, j = np.mgrid[-200:200, -200:200].astype(float) / 200
c = np.abs(np.sqrt(i * i + j * j) - .5) < .02
cf = c.astype(float) * .5 + np.random.uniform(size=c.shape) * .5
result = F.canny(cf, 4, .1, .2, np.ones(c.shape, bool))
#
# erode and dilate the circle to get rings that should contain the
# outlines
#
cd = binary_dilation(c, iterations=4)
ce = binary_erosion(c, iterations=4)
cde = np.logical_and(cd, np.logical_not(ce))
self.assertTrue(np.all(cde[result]))
point_count = np.sum(result)
self.assertTrue(point_count > 1200)
self.assertTrue(point_count < 1600)
def test_image_shape(self):
self.assertRaises(ValueError, F.canny, np.zeros((20, 20, 20)), 4, 0, 0)
def test_mask_none(self):
result1 = F.canny(np.zeros((20, 20)), 4, 0, 0, np.ones((20, 20), bool))
result2 = F.canny(np.zeros((20, 20)), 4, 0, 0)
self.assertTrue(np.all(result1 == result2))
def test_use_quantiles(self):
image = img_as_float(data.camera()[::50, ::50])
# Correct output produced manually with quantiles
# of 0.8 and 0.6 for high and low respectively
correct_output = np.array([[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, 1, 1, 1, 0, 0, 0, 0],
[0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0],
[0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0],
[0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0],
[0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0],
[0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0],
[0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0],
[0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]], dtype=bool)
result = F.canny(image, low_threshold=0.6, high_threshold=0.8, use_quantiles=True)
assert_equal(result, correct_output)
def test_invalid_use_quantiles(self):
image = img_as_float(data.camera()[::50, ::50])
self.assertRaises(ValueError, F.canny, image, use_quantiles=True,
low_threshold=0.5, high_threshold=3.6)
self.assertRaises(ValueError, F.canny, image, use_quantiles=True,
low_threshold=-5, high_threshold=0.5)
self.assertRaises(ValueError, F.canny, image, use_quantiles=True,
low_threshold=99, high_threshold=0.9)
self.assertRaises(ValueError, F.canny, image, use_quantiles=True,
low_threshold=0.5, high_threshold=-100)
# Example from issue #4282
image = data.camera()
self.assertRaises(ValueError, F.canny, image, use_quantiles=True,
low_threshold=50, high_threshold=150)
def test_dtype(self):
"""Check that the same output is produced regardless of image dtype."""
image_uint8 = data.camera()
image_float = img_as_float(image_uint8)
result_uint8 = F.canny(image_uint8)
result_float = F.canny(image_float)
assert_equal(result_uint8, result_float)

View file

@ -0,0 +1,23 @@
import numpy as np
import skimage.data as data
from skimage.feature import Cascade
def test_detector_astronaut():
# Load the trained file from the module root.
trained_file = data.lbp_frontal_face_cascade_filename()
# Initialize the detector cascade.
detector = Cascade(trained_file)
img = data.astronaut()
detected = detector.detect_multi_scale(img=img,
scale_factor=1.2,
step_ratio=1,
min_size=(60, 60),
max_size=(123, 123))
assert len(detected) == 1, 'One face should be detected.'

View file

@ -0,0 +1,105 @@
import numpy as np
from skimage._shared.testing import assert_array_equal
from skimage.data import moon
from skimage.feature import CENSURE
from skimage._shared.testing import test_parallel
from skimage._shared import testing
from skimage.transform import rescale
img = moon()
np.random.seed(0)
def test_censure_on_rectangular_images():
"""Censure feature detector should work on 2D image of any shape."""
rect_image = np.random.rand(300, 200)
square_image = np.random.rand(200, 200)
CENSURE().detect((square_image))
CENSURE().detect((rect_image))
def test_keypoints_censure_color_image_unsupported_error():
"""Censure keypoints can be extracted from gray-scale images only."""
with testing.raises(ValueError):
CENSURE().detect(np.zeros((20, 20, 3)))
def test_keypoints_censure_mode_validity_error():
"""Mode argument in keypoints_censure can be either DoB, Octagon or
STAR."""
with testing.raises(ValueError):
CENSURE(mode='dummy')
def test_keypoints_censure_scale_range_error():
"""Difference between the the max_scale and min_scale parameters in
keypoints_censure should be greater than or equal to two."""
with testing.raises(ValueError):
CENSURE(min_scale=1, max_scale=2)
def test_keypoints_censure_moon_image_dob():
"""Verify the actual Censure keypoints and their corresponding scale with
the expected values for DoB filter."""
detector = CENSURE()
detector.detect(img)
expected_keypoints = np.array([[ 21, 497],
[ 36, 46],
[119, 350],
[185, 177],
[287, 250],
[357, 239],
[463, 116],
[464, 132],
[467, 260]])
expected_scales = np.array([3, 4, 4, 2, 2, 3, 2, 2, 2])
assert_array_equal(expected_keypoints, detector.keypoints)
assert_array_equal(expected_scales, detector.scales)
@test_parallel()
def test_keypoints_censure_moon_image_octagon():
"""Verify the actual Censure keypoints and their corresponding scale with
the expected values for Octagon filter."""
detector = CENSURE(mode='octagon')
# quarter scale image for speed
detector.detect(rescale(img, 0.25,
multichannel=False,
anti_aliasing=False,
mode='constant'))
expected_keypoints = np.array([[ 23, 27],
[ 29, 89],
[ 31, 87],
[106, 59],
[111, 67]])
expected_scales = np.array([3, 2, 5, 2, 4])
assert_array_equal(expected_keypoints, detector.keypoints)
assert_array_equal(expected_scales, detector.scales)
def test_keypoints_censure_moon_image_star():
"""Verify the actual Censure keypoints and their corresponding scale with
the expected values for STAR filter."""
detector = CENSURE(mode='star')
# quarter scale image for speed
detector.detect(rescale(img, 0.25,
multichannel=False,
anti_aliasing=False,
mode='constant'))
expected_keypoints = np.array([[ 23, 27],
[ 29, 89],
[ 30, 86],
[107, 59],
[109, 64],
[111, 67],
[113, 70]])
expected_scales = np.array([3, 2, 4, 2, 5, 3, 2])
assert_array_equal(expected_keypoints, detector.keypoints)
assert_array_equal(expected_scales, detector.scales)

View file

@ -0,0 +1,493 @@
import numpy as np
from skimage._shared.testing import assert_array_equal, assert_almost_equal
from skimage import data
from skimage import img_as_float
from skimage import draw
from skimage.color import rgb2gray
from skimage.morphology import octagon
from skimage._shared.testing import test_parallel
from skimage._shared._warnings import expected_warnings
from skimage._shared import testing
import pytest
from skimage.feature import (corner_moravec, corner_harris, corner_shi_tomasi,
corner_subpix, peak_local_max, corner_peaks,
corner_kitchen_rosenfeld, corner_foerstner,
corner_fast, corner_orientations,
structure_tensor, structure_tensor_eigvals,
hessian_matrix, hessian_matrix_eigvals,
hessian_matrix_det, shape_index)
@pytest.fixture
def im3d():
r = 10
pad = 10
im3 = draw.ellipsoid(r, r, r)
im3 = np.pad(im3, pad, mode='constant').astype(np.uint8)
return im3
def test_structure_tensor():
square = np.zeros((5, 5))
square[2, 2] = 1
Axx, Axy, Ayy = structure_tensor(square, sigma=0.1)
assert_array_equal(Axx, np.array([[ 0, 0, 0, 0, 0],
[ 0, 1, 0, 1, 0],
[ 0, 4, 0, 4, 0],
[ 0, 1, 0, 1, 0],
[ 0, 0, 0, 0, 0]]))
assert_array_equal(Axy, np.array([[ 0, 0, 0, 0, 0],
[ 0, 1, 0, -1, 0],
[ 0, 0, 0, -0, 0],
[ 0, -1, -0, 1, 0],
[ 0, 0, 0, 0, 0]]))
assert_array_equal(Ayy, np.array([[ 0, 0, 0, 0, 0],
[ 0, 1, 4, 1, 0],
[ 0, 0, 0, 0, 0],
[ 0, 1, 4, 1, 0],
[ 0, 0, 0, 0, 0]]))
def test_hessian_matrix():
square = np.zeros((5, 5))
square[2, 2] = 4
Hrr, Hrc, Hcc = hessian_matrix(square, sigma=0.1, order='rc')
assert_almost_equal(Hrr, np.array([[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[2, 0, -2, 0, 2],
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0]]))
assert_almost_equal(Hrc, np.array([[0, 0, 0, 0, 0],
[0, 1, 0, -1, 0],
[0, 0, 0, 0, 0],
[0, -1, 0, 1, 0],
[0, 0, 0, 0, 0]]))
assert_almost_equal(Hcc, np.array([[0, 0, 2, 0, 0],
[0, 0, 0, 0, 0],
[0, 0, -2, 0, 0],
[0, 0, 0, 0, 0],
[0, 0, 2, 0, 0]]))
def test_hessian_matrix_3d():
cube = np.zeros((5, 5, 5))
cube[2, 2, 2] = 4
Hs = hessian_matrix(cube, sigma=0.1, order='rc')
assert len(Hs) == 6, ("incorrect number of Hessian images (%i) for 3D" %
len(Hs))
assert_almost_equal(Hs[2][:, 2, :], np.array([[0, 0, 0, 0, 0],
[0, 1, 0, -1, 0],
[0, 0, 0, 0, 0],
[0, -1, 0, 1, 0],
[0, 0, 0, 0, 0]]))
def test_structure_tensor_eigvals():
square = np.zeros((5, 5))
square[2, 2] = 1
Axx, Axy, Ayy = structure_tensor(square, sigma=0.1)
l1, l2 = structure_tensor_eigvals(Axx, Axy, Ayy)
assert_array_equal(l1, np.array([[0, 0, 0, 0, 0],
[0, 2, 4, 2, 0],
[0, 4, 0, 4, 0],
[0, 2, 4, 2, 0],
[0, 0, 0, 0, 0]]))
assert_array_equal(l2, np.array([[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]]))
def test_hessian_matrix_eigvals():
square = np.zeros((5, 5))
square[2, 2] = 4
H = hessian_matrix(square, sigma=0.1, order='rc')
l1, l2 = hessian_matrix_eigvals(H)
assert_almost_equal(l1, np.array([[0, 0, 2, 0, 0],
[0, 1, 0, 1, 0],
[2, 0, -2, 0, 2],
[0, 1, 0, 1, 0],
[0, 0, 2, 0, 0]]))
assert_almost_equal(l2, np.array([[0, 0, 0, 0, 0],
[0, -1, 0, -1, 0],
[0, 0, -2, 0, 0],
[0, -1, 0, -1, 0],
[0, 0, 0, 0, 0]]))
def test_hessian_matrix_eigvals_3d(im3d):
H = hessian_matrix(im3d)
E = hessian_matrix_eigvals(H)
# test descending order:
e0, e1, e2 = E
assert np.all(e0 >= e1) and np.all(e1 >= e2)
E0, E1, E2 = E[:, E.shape[1] // 2] # cross section
row_center, col_center = np.array(E0.shape) // 2
circles = [draw.circle_perimeter(row_center, col_center, radius,
shape=E0.shape)
for radius in range(1, E0.shape[1] // 2 - 1)]
response0 = np.array([np.mean(E0[c]) for c in circles])
response2 = np.array([np.mean(E2[c]) for c in circles])
# eigenvalues are negative just inside the sphere, positive just outside
assert np.argmin(response2) < np.argmax(response0)
assert np.min(response2) < 0
assert np.max(response0) > 0
@test_parallel()
def test_hessian_matrix_det():
image = np.zeros((5, 5))
image[2, 2] = 1
det = hessian_matrix_det(image, 5)
assert_almost_equal(det, 0, decimal=3)
def test_hessian_matrix_det_3d(im3d):
D = hessian_matrix_det(im3d)
D0 = D[D.shape[0] // 2]
row_center, col_center = np.array(D0.shape) // 2
# testing in 3D is hard. We test this by showing that you get the
# expected flat-then-low-then-high 2nd derivative response in a circle
# around the midplane of the sphere.
circles = [draw.circle_perimeter(row_center, col_center, r, shape=D0.shape)
for r in range(1, D0.shape[1] // 2 - 1)]
response = np.array([np.mean(D0[c]) for c in circles])
lowest = np.argmin(response)
highest = np.argmax(response)
assert lowest < highest
assert response[lowest] < 0
assert response[highest] > 0
def test_shape_index():
# software floating point arm doesn't raise a warning on divide by zero
# https://github.com/scikit-image/scikit-image/issues/3335
square = np.zeros((5, 5))
square[2, 2] = 4
with expected_warnings([r'divide by zero|\A\Z', r'invalid value|\A\Z']):
s = shape_index(square, sigma=0.1)
assert_almost_equal(
s, np.array([[ np.nan, np.nan, -0.5, np.nan, np.nan],
[ np.nan, 0, np.nan, 0, np.nan],
[ -0.5, np.nan, -1, np.nan, -0.5],
[ np.nan, 0, np.nan, 0, np.nan],
[ np.nan, np.nan, -0.5, np.nan, np.nan]])
)
@test_parallel()
def test_square_image():
im = np.zeros((50, 50)).astype(float)
im[:25, :25] = 1.
# Moravec
results = peak_local_max(corner_moravec(im),
min_distance=10, threshold_rel=0)
# interest points along edge
assert len(results) == 57
# Harris
results = peak_local_max(corner_harris(im, method='k'),
min_distance=10, threshold_rel=0)
# interest at corner
assert len(results) == 1
results = peak_local_max(corner_harris(im, method='eps'),
min_distance=10, threshold_rel=0)
# interest at corner
assert len(results) == 1
# Shi-Tomasi
results = peak_local_max(corner_shi_tomasi(im),
min_distance=10, threshold_rel=0)
# interest at corner
assert len(results) == 1
def test_noisy_square_image():
im = np.zeros((50, 50)).astype(float)
im[:25, :25] = 1.
np.random.seed(seed=1234)
im = im + np.random.uniform(size=im.shape) * .2
# Moravec
results = peak_local_max(corner_moravec(im),
min_distance=10, threshold_rel=0)
# undefined number of interest points
assert results.any()
# Harris
results = peak_local_max(corner_harris(im, method='k'),
min_distance=10, threshold_rel=0)
assert len(results) == 1
results = peak_local_max(corner_harris(im, method='eps'),
min_distance=10, threshold_rel=0)
assert len(results) == 1
# Shi-Tomasi
results = peak_local_max(corner_shi_tomasi(im, sigma=1.5),
min_distance=10, threshold_rel=0)
assert len(results) == 1
def test_squared_dot():
im = np.zeros((50, 50))
im[4:8, 4:8] = 1
im = img_as_float(im)
# Moravec fails
# Harris
results = peak_local_max(corner_harris(im),
min_distance=10, threshold_rel=0)
assert (results == np.array([[6, 6]])).all()
# Shi-Tomasi
results = peak_local_max(corner_shi_tomasi(im),
min_distance=10, threshold_rel=0)
assert (results == np.array([[6, 6]])).all()
def test_rotated_img():
"""
The harris filter should yield the same results with an image and it's
rotation.
"""
im = img_as_float(data.astronaut().mean(axis=2))
im_rotated = im.T
# Moravec
results = peak_local_max(corner_moravec(im),
min_distance=10, threshold_rel=0)
results_rotated = peak_local_max(corner_moravec(im_rotated),
min_distance=10, threshold_rel=0)
assert (np.sort(results[:, 0]) == np.sort(results_rotated[:, 1])).all()
assert (np.sort(results[:, 1]) == np.sort(results_rotated[:, 0])).all()
# Harris
results = peak_local_max(corner_harris(im),
min_distance=10, threshold_rel=0)
results_rotated = peak_local_max(corner_harris(im_rotated),
min_distance=10, threshold_rel=0)
assert (np.sort(results[:, 0]) == np.sort(results_rotated[:, 1])).all()
assert (np.sort(results[:, 1]) == np.sort(results_rotated[:, 0])).all()
# Shi-Tomasi
results = peak_local_max(corner_shi_tomasi(im),
min_distance=10, threshold_rel=0)
results_rotated = peak_local_max(corner_shi_tomasi(im_rotated),
min_distance=10, threshold_rel=0)
assert (np.sort(results[:, 0]) == np.sort(results_rotated[:, 1])).all()
assert (np.sort(results[:, 1]) == np.sort(results_rotated[:, 0])).all()
def test_subpix_edge():
img = np.zeros((50, 50))
img[:25, :25] = 255
img[25:, 25:] = 255
corner = peak_local_max(corner_harris(img),
min_distance=10, threshold_rel=0, num_peaks=1)
subpix = corner_subpix(img, corner)
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),
min_distance=10, threshold_rel=0, 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),
min_distance=10, threshold_rel=0, 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
img[25:-1, 25:-1] = 255
corner = corner_peaks(corner_harris(img), threshold_rel=0)
subpix = corner_subpix(img, corner, window_size=11)
ref = np.array([[24.5, 24.5],
[0.52040816, 0.52040816],
[0.52040816, 24.47959184],
[24.47959184, 0.52040816],
[24.52040816, 48.47959184],
[48.47959184, 24.52040816],
[48.47959184, 48.47959184]])
assert_almost_equal(subpix, ref)
def test_num_peaks():
"""For a bunch of different values of num_peaks, check that
peak_local_max returns exactly the right amount of peaks. Test
is run on the astronaut image in order to produce a sufficient number of corners"""
img_corners = corner_harris(rgb2gray(data.astronaut()))
for i in range(20):
n = np.random.randint(1, 21)
results = peak_local_max(img_corners,
min_distance=10, threshold_rel=0, num_peaks=n)
assert (results.shape[0] == n)
def test_corner_peaks():
response = np.zeros((10, 10))
response[2:5, 2:5] = 1
response[8:10, 0:2] = 1
corners = corner_peaks(response, exclude_border=False, min_distance=10,
threshold_rel=0)
assert corners.shape == (1, 2)
corners = corner_peaks(response, exclude_border=False, min_distance=5,
threshold_rel=0)
assert corners.shape == (2, 2)
with pytest.warns(FutureWarning,
match="Until version 0.16, threshold_rel.*"):
corners = corner_peaks(response, exclude_border=False, min_distance=1)
assert corners.shape == (5, 2)
corners = corner_peaks(response, exclude_border=False, min_distance=1,
indices=False)
assert np.sum(corners) == 5
def test_blank_image_nans():
"""Some of the corner detectors had a weakness in terms of returning
NaN when presented with regions of constant intensity. This should
be fixed by now. We test whether each detector returns something
finite in the case of constant input"""
detectors = [corner_moravec, corner_harris, corner_shi_tomasi,
corner_kitchen_rosenfeld, corner_foerstner]
constant_image = np.zeros((20, 20))
for det in detectors:
response = det(constant_image)
assert np.all(np.isfinite(response))
def test_corner_fast_image_unsupported_error():
img = np.zeros((20, 20, 3))
with testing.raises(ValueError):
corner_fast(img)
@test_parallel()
def test_corner_fast_astronaut():
img = rgb2gray(data.astronaut())
expected = np.array([[444, 310],
[374, 171],
[249, 171],
[492, 139],
[403, 162],
[496, 266],
[362, 328],
[476, 250],
[353, 172],
[346, 279],
[494, 169],
[177, 156],
[413, 181],
[213, 117],
[390, 149],
[140, 205],
[232, 266],
[489, 155],
[387, 195],
[101, 198],
[363, 192],
[364, 147],
[300, 244],
[325, 245],
[141, 242],
[401, 197],
[197, 148],
[339, 242],
[188, 113],
[362, 252],
[379, 183],
[358, 307],
[245, 137],
[369, 159],
[464, 251],
[305, 57],
[223, 375]])
actual = corner_peaks(corner_fast(img, 12, 0.3),
min_distance=10, threshold_rel=0)
assert_array_equal(actual, expected)
def test_corner_orientations_image_unsupported_error():
img = np.zeros((20, 20, 3))
with testing.raises(ValueError):
corner_orientations(
img,
np.asarray([[7, 7]]), np.ones((3, 3)))
def test_corner_orientations_even_shape_error():
img = np.zeros((20, 20))
with testing.raises(ValueError):
corner_orientations(
img,
np.asarray([[7, 7]]), np.ones((4, 4)))
@test_parallel()
def test_corner_orientations_astronaut():
img = rgb2gray(data.astronaut())
corners = corner_peaks(corner_fast(img, 11, 0.35),
min_distance=10, threshold_abs=0, threshold_rel=0.1)
expected = np.array([-4.40598471e-01, -1.46554357e+00,
2.39291733e+00, -1.63869275e+00,
1.45931342e+00, -1.64397304e+00,
-1.76069982e+00, 1.09650167e+00,
-1.65449964e+00, 1.19134149e+00,
5.46905279e-02, 2.17103132e+00,
8.12701702e-01, -1.22091334e-01,
-2.01162417e+00, 1.25854853e+00,
3.05330950e+00, 2.01197383e+00,
1.07812134e+00, 3.09780364e+00,
-3.49561988e-01, 2.43573659e+00,
3.14918803e-01, -9.88548213e-01,
-1.88247204e-01, 2.47305654e+00,
-2.99143370e+00, 1.47154532e+00,
-6.61151410e-01, -1.68885773e+00,
-3.09279990e-01, -2.81524886e+00,
-1.75220190e+00, -1.69230287e+00,
-7.52950306e-04])
actual = corner_orientations(img, corners, octagon(3, 2))
assert_almost_equal(actual, expected)
def test_corner_orientations_square():
square = np.zeros((12, 12))
square[3:9, 3:9] = 1
corners = corner_peaks(corner_fast(square, 9),
min_distance=1, threshold_rel=0)
actual_orientations = corner_orientations(square, corners, octagon(3, 2))
actual_orientations_degrees = np.rad2deg(actual_orientations)
expected_orientations_degree = np.array([45, 135, -45, -135])
assert_array_equal(actual_orientations_degrees,
expected_orientations_degree)

View file

@ -0,0 +1,102 @@
import numpy as np
from skimage._shared.testing import assert_almost_equal
from numpy import sqrt, ceil
from skimage import data
from skimage import img_as_float
from skimage.feature import daisy
from skimage._shared import testing
def test_daisy_color_image_unsupported_error():
img = np.zeros((20, 20, 3))
with testing.raises(ValueError):
daisy(img)
def test_daisy_desc_dims():
img = img_as_float(data.astronaut()[:128, :128].mean(axis=2))
rings = 2
histograms = 4
orientations = 3
descs = daisy(img, rings=rings, histograms=histograms,
orientations=orientations)
assert(descs.shape[2] == (rings * histograms + 1) * orientations)
rings = 4
histograms = 5
orientations = 13
descs = daisy(img, rings=rings, histograms=histograms,
orientations=orientations)
assert(descs.shape[2] == (rings * histograms + 1) * orientations)
def test_descs_shape():
img = img_as_float(data.astronaut()[:256, :256].mean(axis=2))
radius = 20
step = 8
descs = daisy(img, radius=radius, step=step)
assert(descs.shape[0] == ceil((img.shape[0] - radius * 2) / float(step)))
assert(descs.shape[1] == ceil((img.shape[1] - radius * 2) / float(step)))
img = img[:-1, :-2]
radius = 5
step = 3
descs = daisy(img, radius=radius, step=step)
assert(descs.shape[0] == ceil((img.shape[0] - radius * 2) / float(step)))
assert(descs.shape[1] == ceil((img.shape[1] - radius * 2) / float(step)))
def test_daisy_sigmas_and_radii():
img = img_as_float(data.astronaut()[:64, :64].mean(axis=2))
sigmas = [1, 2, 3]
radii = [1, 2]
daisy(img, sigmas=sigmas, ring_radii=radii)
def test_daisy_incompatible_sigmas_and_radii():
img = img_as_float(data.astronaut()[:64, :64].mean(axis=2))
sigmas = [1, 2]
radii = [1, 2]
with testing.raises(ValueError):
daisy(img, sigmas=sigmas, ring_radii=radii)
def test_daisy_normalization():
img = img_as_float(data.astronaut()[:64, :64].mean(axis=2))
descs = daisy(img, normalization='l1')
for i in range(descs.shape[0]):
for j in range(descs.shape[1]):
assert_almost_equal(np.sum(descs[i, j, :]), 1)
descs_ = daisy(img)
assert_almost_equal(descs, descs_)
descs = daisy(img, normalization='l2')
for i in range(descs.shape[0]):
for j in range(descs.shape[1]):
assert_almost_equal(sqrt(np.sum(descs[i, j, :] ** 2)), 1)
orientations = 8
descs = daisy(img, orientations=orientations, normalization='daisy')
desc_dims = descs.shape[2]
for i in range(descs.shape[0]):
for j in range(descs.shape[1]):
for k in range(0, desc_dims, orientations):
assert_almost_equal(sqrt(np.sum(
descs[i, j, k:k + orientations] ** 2)), 1)
img = np.zeros((50, 50))
descs = daisy(img, normalization='off')
for i in range(descs.shape[0]):
for j in range(descs.shape[1]):
assert_almost_equal(np.sum(descs[i, j, :]), 0)
with testing.raises(ValueError):
daisy(img, normalization='does_not_exist')
def test_daisy_visualization():
img = img_as_float(data.astronaut()[:32, :32].mean(axis=2))
descs, descs_img = daisy(img, visualize=True)
assert(descs_img.shape == (32, 32, 3))

View file

@ -0,0 +1,153 @@
from random import shuffle
from itertools import chain
import pytest
import numpy as np
from numpy.testing import assert_allclose
from numpy.testing import assert_array_equal
from skimage.transform import integral_image
from skimage.feature import haar_like_feature
from skimage.feature import haar_like_feature_coord
from skimage.feature import draw_haar_like_feature
def test_haar_like_feature_error():
img = np.ones((5, 5), dtype=np.float32)
img_ii = integral_image(img)
feature_type = 'unknown_type'
with pytest.raises(ValueError):
haar_like_feature(img_ii, 0, 0, 5, 5, feature_type=feature_type)
haar_like_feature_coord(5, 5, feature_type=feature_type)
draw_haar_like_feature(img, 0, 0, 5, 5, feature_type=feature_type)
feat_coord, feat_type = haar_like_feature_coord(5, 5, 'type-2-x')
with pytest.raises(ValueError):
haar_like_feature(img_ii, 0, 0, 5, 5, feature_type=feat_type[:3],
feature_coord=feat_coord)
@pytest.mark.parametrize("dtype", [np.uint8, np.int8,
np.float32, np.float64])
@pytest.mark.parametrize("feature_type,shape_feature,expected_feature_value",
[('type-2-x', (84,), [0.]),
('type-2-y', (84,), [0.]),
('type-3-x', (42,), [-4., -3., -2., -1.]),
('type-3-y', (42,), [-4., -3., -2., -1.]),
('type-4', (36,), [0.])])
def test_haar_like_feature(feature_type, shape_feature,
expected_feature_value, dtype):
# test Haar-like feature on a basic one image
img = np.ones((5, 5), dtype=dtype)
img_ii = integral_image(img)
haar_feature = haar_like_feature(img_ii, 0, 0, 5, 5,
feature_type=feature_type)
assert_allclose(np.sort(np.unique(haar_feature)), expected_feature_value)
@pytest.mark.parametrize("dtype", [np.uint8, np.int8,
np.float32, np.float64])
@pytest.mark.parametrize("feature_type", ['type-2-x', 'type-2-y',
'type-3-x', 'type-3-y',
'type-4'])
def test_haar_like_feature_fused_type(dtype, feature_type):
# check that the input type is kept
img = np.ones((5, 5), dtype=dtype)
img_ii = integral_image(img)
expected_dtype = img_ii.dtype
# to avoid overflow, unsigned type are converted to signed
if 'uint' in expected_dtype.name:
expected_dtype = np.dtype(expected_dtype.name.replace('u', ''))
haar_feature = haar_like_feature(img_ii, 0, 0, 5, 5,
feature_type=feature_type)
assert haar_feature.dtype == expected_dtype
def test_haar_like_feature_list():
img = np.ones((5, 5), dtype=np.int8)
img_ii = integral_image(img)
feature_type = ['type-2-x', 'type-2-y', 'type-3-x', 'type-3-y', 'type-4']
haar_list = haar_like_feature(img_ii, 0, 0, 5, 5,
feature_type=feature_type)
haar_all = haar_like_feature(img_ii, 0, 0, 5, 5)
assert_array_equal(haar_list, haar_all)
@pytest.mark.parametrize("feature_type", ['type-2-x', 'type-2-y',
'type-3-x', 'type-3-y',
'type-4',
['type-2-y', 'type-3-x',
'type-4']])
def test_haar_like_feature_precomputed(feature_type):
img = np.ones((5, 5), dtype=np.int8)
img_ii = integral_image(img)
if isinstance(feature_type, list):
# shuffle the index of the feature to be sure that we are output
# the features in the same order
shuffle(feature_type)
feat_coord, feat_type = zip(*[haar_like_feature_coord(5, 5, feat_t)
for feat_t in feature_type])
feat_coord = np.concatenate(feat_coord)
feat_type = np.concatenate(feat_type)
else:
feat_coord, feat_type = haar_like_feature_coord(5, 5, feature_type)
haar_feature_precomputed = haar_like_feature(img_ii, 0, 0, 5, 5,
feature_type=feat_type,
feature_coord=feat_coord)
haar_feature = haar_like_feature(img_ii, 0, 0, 5, 5, feature_type)
assert_array_equal(haar_feature_precomputed, haar_feature)
@pytest.mark.parametrize("feature_type,height,width,expected_coord",
[('type-2-x', 2, 2,
[[[(0, 0), (0, 0)], [(0, 1), (0, 1)]],
[[(1, 0), (1, 0)], [(1, 1), (1, 1)]]]),
('type-2-y', 2, 2,
[[[(0, 0), (0, 0)], [(1, 0), (1, 0)]],
[[(0, 1), (0, 1)], [(1, 1), (1, 1)]]]),
('type-3-x', 3, 3,
[[[(0, 0), (0, 0)], [(0, 1), (0, 1)],
[(0, 2), (0, 2)]],
[[(0, 0), (1, 0)], [(0, 1), (1, 1)],
[(0, 2), (1, 2)]],
[[(1, 0), (1, 0)], [(1, 1), (1, 1)],
[(1, 2), (1, 2)]],
[[(1, 0), (2, 0)], [(1, 1), (2, 1)],
[(1, 2), (2, 2)]],
[[(2, 0), (2, 0)], [(2, 1), (2, 1)],
[(2, 2), (2, 2)]]]),
('type-3-y', 3, 3,
[[[(0, 0), (0, 0)], [(1, 0), (1, 0)],
[(2, 0), (2, 0)]],
[[(0, 0), (0, 1)], [(1, 0), (1, 1)],
[(2, 0), (2, 1)]],
[[(0, 1), (0, 1)], [(1, 1), (1, 1)],
[(2, 1), (2, 1)]],
[[(0, 1), (0, 2)], [(1, 1), (1, 2)],
[(2, 1), (2, 2)]],
[[(0, 2), (0, 2)], [(1, 2), (1, 2)],
[(2, 2), (2, 2)]]]),
('type-4', 2, 2,
[[[(0, 0), (0, 0)], [(0, 1), (0, 1)],
[(1, 1), (1, 1)], [(1, 0), (1, 0)]]])])
def test_haar_like_feature_coord(feature_type, height, width, expected_coord):
feat_coord, feat_type = haar_like_feature_coord(width, height,
feature_type)
# convert the output to a full numpy array just for comparison
feat_coord = np.array([hf for hf in feat_coord])
assert_array_equal(feat_coord, expected_coord)
assert np.all(feat_type == feature_type)
@pytest.mark.parametrize("max_n_features,nnz_values", [(None, 46),
(1, 8)])
def test_draw_haar_like_feature(max_n_features, nnz_values):
img = np.zeros((5, 5), dtype=np.float32)
coord, _ = haar_like_feature_coord(5, 5, 'type-4')
image = draw_haar_like_feature(img, 0, 0, 5, 5, coord,
max_n_features=max_n_features,
random_state=0)
assert image.shape == (5, 5, 3)
assert np.count_nonzero(image) == nnz_values

View file

@ -0,0 +1,256 @@
import os
import numpy as np
from scipy import ndimage as ndi
from skimage import color
from skimage import data
from skimage import feature
from skimage import img_as_float
from skimage import draw
from skimage._shared.testing import assert_almost_equal, fetch
from skimage._shared import testing
def test_hog_output_size():
img = img_as_float(data.astronaut()[:256, :].mean(axis=2))
fd = feature.hog(img, orientations=9, pixels_per_cell=(8, 8),
cells_per_block=(1, 1), block_norm='L1')
assert len(fd) == 9 * (256 // 8) * (512 // 8)
def test_hog_output_correctness_l1_norm():
img = color.rgb2gray(data.astronaut())
correct_output = np.load(fetch('data/astronaut_GRAY_hog_L1.npy'))
output = feature.hog(img, orientations=9, pixels_per_cell=(8, 8),
cells_per_block=(3, 3), block_norm='L1',
feature_vector=True, transform_sqrt=False,
visualize=False)
assert_almost_equal(output, correct_output)
def test_hog_output_correctness_l2hys_norm():
img = color.rgb2gray(data.astronaut())
correct_output = np.load(fetch('data/astronaut_GRAY_hog_L2-Hys.npy'))
output = feature.hog(img, orientations=9, pixels_per_cell=(8, 8),
cells_per_block=(3, 3), block_norm='L2-Hys',
feature_vector=True, transform_sqrt=False,
visualize=False)
assert_almost_equal(output, correct_output)
def test_hog_image_size_cell_size_mismatch():
image = data.camera()[:150, :200]
fd = feature.hog(image, orientations=9, pixels_per_cell=(8, 8),
cells_per_block=(1, 1), block_norm='L1')
assert len(fd) == 9 * (150 // 8) * (200 // 8)
def test_hog_basic_orientations_and_data_types():
# scenario:
# 1) create image (with float values) where upper half is filled by
# zeros, bottom half by 100
# 2) create unsigned integer version of this image
# 3) calculate feature.hog() for both images, both with 'transform_sqrt'
# option enabled and disabled
# 4) verify that all results are equal where expected
# 5) verify that computed feature vector is as expected
# 6) repeat the scenario for 90, 180 and 270 degrees rotated images
# size of testing image
width = height = 35
image0 = np.zeros((height, width), dtype='float')
image0[height // 2:] = 100
for rot in range(4):
# rotate by 0, 90, 180 and 270 degrees
image_float = np.rot90(image0, rot)
# create uint8 image from image_float
image_uint8 = image_float.astype('uint8')
(hog_float, hog_img_float) = feature.hog(
image_float, orientations=4, pixels_per_cell=(8, 8),
cells_per_block=(1, 1), visualize=True, transform_sqrt=False,
block_norm='L1')
(hog_uint8, hog_img_uint8) = feature.hog(
image_uint8, orientations=4, pixels_per_cell=(8, 8),
cells_per_block=(1, 1), visualize=True, transform_sqrt=False,
block_norm='L1')
(hog_float_norm, hog_img_float_norm) = feature.hog(
image_float, orientations=4, pixels_per_cell=(8, 8),
cells_per_block=(1, 1), visualize=True, transform_sqrt=True,
block_norm='L1')
(hog_uint8_norm, hog_img_uint8_norm) = feature.hog(
image_uint8, orientations=4, pixels_per_cell=(8, 8),
cells_per_block=(1, 1), visualize=True, transform_sqrt=True,
block_norm='L1')
# set to True to enable manual debugging with graphical output,
# must be False for automatic testing
if False:
import matplotlib.pyplot as plt
plt.figure()
plt.subplot(2, 3, 1)
plt.imshow(image_float)
plt.colorbar()
plt.title('image')
plt.subplot(2, 3, 2)
plt.imshow(hog_img_float)
plt.colorbar()
plt.title('HOG result visualisation (float img)')
plt.subplot(2, 3, 5)
plt.imshow(hog_img_uint8)
plt.colorbar()
plt.title('HOG result visualisation (uint8 img)')
plt.subplot(2, 3, 3)
plt.imshow(hog_img_float_norm)
plt.colorbar()
plt.title('HOG result (transform_sqrt) visualisation (float img)')
plt.subplot(2, 3, 6)
plt.imshow(hog_img_uint8_norm)
plt.colorbar()
plt.title('HOG result (transform_sqrt) visualisation (uint8 img)')
plt.show()
# results (features and visualisation) for float and uint8 images must
# be almost equal
assert_almost_equal(hog_float, hog_uint8)
assert_almost_equal(hog_img_float, hog_img_uint8)
# resulting features should be almost equal
# when 'transform_sqrt' is enabled
# or disabled (for current simple testing image)
assert_almost_equal(hog_float, hog_float_norm, decimal=4)
assert_almost_equal(hog_float, hog_uint8_norm, decimal=4)
# reshape resulting feature vector to matrix with 4 columns (each
# corresponding to one of 4 directions); only one direction should
# contain nonzero values (this is manually determined for testing
# image)
actual = np.max(hog_float.reshape(-1, 4), axis=0)
if rot in [0, 2]:
# image is rotated by 0 and 180 degrees
desired = [0, 0, 1, 0]
elif rot in [1, 3]:
# image is rotated by 90 and 270 degrees
desired = [1, 0, 0, 0]
else:
raise Exception('Result is not determined for this rotation.')
assert_almost_equal(actual, desired, decimal=2)
def test_hog_orientations_circle():
# scenario:
# 1) create image with blurred circle in the middle
# 2) calculate feature.hog()
# 3) verify that the resulting feature vector contains uniformly
# distributed values for all orientations, i.e. no orientation is
# lost or emphasized
# 4) repeat the scenario for other 'orientations' option
# size of testing image
width = height = 100
image = np.zeros((height, width))
rr, cc = draw.disk((int(height / 2), int(width / 2)), int(width / 3))
image[rr, cc] = 100
image = ndi.gaussian_filter(image, 2)
for orientations in range(2, 15):
(hog, hog_img) = feature.hog(image, orientations=orientations,
pixels_per_cell=(8, 8),
cells_per_block=(1, 1), visualize=True,
transform_sqrt=False,
block_norm='L1')
# set to True to enable manual debugging with graphical output,
# must be False for automatic testing
if False:
import matplotlib.pyplot as plt
plt.figure()
plt.subplot(1, 2, 1)
plt.imshow(image)
plt.colorbar()
plt.title('image_float')
plt.subplot(1, 2, 2)
plt.imshow(hog_img)
plt.colorbar()
plt.title('HOG result visualisation, '
'orientations=%d' % (orientations))
plt.show()
# reshape resulting feature vector to matrix with N columns (each
# column corresponds to one direction),
hog_matrix = hog.reshape(-1, orientations)
# compute mean values in the resulting feature vector for each
# direction, these values should be almost equal to the global mean
# value (since the image contains a circle), i.e., all directions have
# same contribution to the result
actual = np.mean(hog_matrix, axis=0)
desired = np.mean(hog_matrix)
assert_almost_equal(actual, desired, decimal=1)
def test_hog_visualization_orientation():
"""Test that the visualization produces a line with correct orientation
The hog visualization is expected to draw line segments perpendicular to
the midpoints of orientation bins. This example verifies that when
orientations=3 and the gradient is entirely in the middle bin (bisected
by the y-axis), the line segment drawn by the visualization is horizontal.
"""
width = height = 11
image = np.zeros((height, width), dtype='float')
image[height // 2:] = 1
_, hog_image = feature.hog(
image,
orientations=3,
pixels_per_cell=(width, height),
cells_per_block=(1, 1),
visualize=True,
block_norm='L1'
)
middle_index = height // 2
indices_excluding_middle = [x for x in range(height) if x != middle_index]
assert (hog_image[indices_excluding_middle, :] == 0).all()
assert (hog_image[middle_index, 1:-1] > 0).all()
def test_hog_block_normalization_incorrect_error():
img = np.eye(4)
with testing.raises(ValueError):
feature.hog(img, block_norm='Linf')
@testing.parametrize("shape,multichannel", [
((3, 3, 3), False),
((3, 3), True),
((3, 3, 3, 3), True),
])
def test_hog_incorrect_dimensions(shape, multichannel):
img = np.zeros(shape)
with testing.raises(ValueError):
feature.hog(img, multichannel=multichannel, block_norm='L1')
def test_hog_output_equivariance_multichannel():
img = data.astronaut()
img[:, :, (1, 2)] = 0
hog_ref = feature.hog(img, multichannel=True, block_norm='L1')
for n in (1, 2):
hog_fact = feature.hog(np.roll(img, n, axis=2), multichannel=True,
block_norm='L1')
assert_almost_equal(hog_ref, hog_fact)

View file

@ -0,0 +1,179 @@
import numpy as np
from skimage._shared.testing import assert_equal
from skimage import data
from skimage import transform
from skimage.color import rgb2gray
from skimage.feature import (BRIEF, match_descriptors,
corner_peaks, corner_harris)
from skimage._shared import testing
def test_binary_descriptors_unequal_descriptor_sizes_error():
"""Sizes of descriptors of keypoints to be matched should be equal."""
descs1 = np.array([[True, True, False, True],
[False, True, False, True]])
descs2 = np.array([[True, False, False, True, False],
[False, True, True, True, False]])
with testing.raises(ValueError):
match_descriptors(descs1, descs2)
def test_binary_descriptors():
descs1 = np.array([[True, True, False, True, True],
[False, True, False, True, True]])
descs2 = np.array([[True, False, False, True, False],
[False, False, True, True, True]])
matches = match_descriptors(descs1, descs2)
assert_equal(matches, [[0, 0], [1, 1]])
def test_binary_descriptors_rotation_crosscheck_false():
"""Verify matched keypoints and their corresponding masks results between
image and its rotated version with the expected keypoint pairs with
cross_check disabled."""
img = data.astronaut()
img = rgb2gray(img)
tform = transform.SimilarityTransform(scale=1, rotation=0.15, translation=(0, 0))
rotated_img = transform.warp(img, tform, clip=False)
extractor = BRIEF(descriptor_size=512)
keypoints1 = corner_peaks(corner_harris(img), min_distance=5,
threshold_abs=0, threshold_rel=0.1)
extractor.extract(img, keypoints1)
descriptors1 = extractor.descriptors
keypoints2 = corner_peaks(corner_harris(rotated_img), min_distance=5,
threshold_abs=0, threshold_rel=0.1)
extractor.extract(rotated_img, keypoints2)
descriptors2 = extractor.descriptors
matches = match_descriptors(descriptors1, descriptors2, cross_check=False)
exp_matches1 = np.arange(47)
exp_matches2 = np.array([0, 2, 1, 3, 4, 5, 7, 8, 14, 9, 11, 13,
23, 15, 16, 22, 17, 19, 34, 18, 24, 27,
30, 25, 26, 32, 28, 35, 37, 42, 29, 38,
33, 40, 36, 3, 10, 32, 43, 15, 29, 41,
1, 18, 32, 24, 11])
assert_equal(matches[:, 0], exp_matches1)
assert_equal(matches[:, 1], exp_matches2)
# minkowski takes a different code path, therefore we test it explicitly
matches = match_descriptors(descriptors1, descriptors2,
metric='minkowski', cross_check=False)
assert_equal(matches[:, 0], exp_matches1)
assert_equal(matches[:, 1], exp_matches2)
# it also has an extra parameter
matches = match_descriptors(descriptors1, descriptors2,
metric='minkowski', p=4, cross_check=False)
assert_equal(matches[:, 0], exp_matches1)
assert_equal(matches[:, 1], exp_matches2)
def test_binary_descriptors_rotation_crosscheck_true():
"""Verify matched keypoints and their corresponding masks results between
image and its rotated version with the expected keypoint pairs with
cross_check enabled."""
img = data.astronaut()
img = rgb2gray(img)
tform = transform.SimilarityTransform(scale=1, rotation=0.15, translation=(0, 0))
rotated_img = transform.warp(img, tform, clip=False)
extractor = BRIEF(descriptor_size=512)
keypoints1 = corner_peaks(corner_harris(img), min_distance=5,
threshold_abs=0, threshold_rel=0.1)
extractor.extract(img, keypoints1)
descriptors1 = extractor.descriptors
keypoints2 = corner_peaks(corner_harris(rotated_img), min_distance=5,
threshold_abs=0, threshold_rel=0.1)
extractor.extract(rotated_img, keypoints2)
descriptors2 = extractor.descriptors
matches = match_descriptors(descriptors1, descriptors2, cross_check=True)
exp_matches1 = np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
13, 14, 15, 16, 17, 19, 20, 21, 22, 23,
24, 25, 26, 27, 28, 29, 30, 31, 32, 33,
34, 38, 41])
exp_matches2 = np.array([0, 2, 1, 3, 4, 5, 7, 8, 14, 9, 11, 13,
23, 15, 16, 22, 17, 19, 18, 24, 27, 30,
25, 26, 32, 28, 35, 37, 42, 29, 38, 33,
40, 36, 43, 41])
assert_equal(matches[:, 0], exp_matches1)
assert_equal(matches[:, 1], exp_matches2)
def test_max_distance():
descs1 = np.zeros((10, 128))
descs2 = np.zeros((15, 128))
descs1[0, :] = 1
matches = match_descriptors(descs1, descs2, metric='euclidean',
max_distance=0.1, cross_check=False)
assert len(matches) == 9
matches = match_descriptors(descs1, descs2, metric='euclidean',
max_distance=np.sqrt(128.1),
cross_check=False)
assert len(matches) == 10
matches = match_descriptors(descs1, descs2, metric='euclidean',
max_distance=0.1,
cross_check=True)
assert_equal(matches, [[1, 0]])
matches = match_descriptors(descs1, descs2, metric='euclidean',
max_distance=np.sqrt(128.1),
cross_check=True)
assert_equal(matches, [[1, 0]])
def test_max_ratio():
descs1 = 10 * np.arange(10)[:, None].astype(np.float32)
descs2 = 10 * np.arange(15)[:, None].astype(np.float32)
descs2[0] = 5.0
matches = match_descriptors(descs1, descs2, metric='euclidean',
max_ratio=1.0, cross_check=False)
assert_equal(len(matches), 10)
matches = match_descriptors(descs1, descs2, metric='euclidean',
max_ratio=0.6, cross_check=False)
assert_equal(len(matches), 10)
matches = match_descriptors(descs1, descs2, metric='euclidean',
max_ratio=0.5, cross_check=False)
assert_equal(len(matches), 9)
descs1[0] = 7.5
matches = match_descriptors(descs1, descs2, metric='euclidean',
max_ratio=0.5, cross_check=False)
assert_equal(len(matches), 9)
descs2 = 10 * np.arange(1)[:, None].astype(np.float32)
matches = match_descriptors(descs1, descs2, metric='euclidean',
max_ratio=1.0, cross_check=False)
assert_equal(len(matches), 10)
matches = match_descriptors(descs1, descs2, metric='euclidean',
max_ratio=0.5, cross_check=False)
assert_equal(len(matches), 10)
descs1 = 10 * np.arange(1)[:, None].astype(np.float32)
matches = match_descriptors(descs1, descs2, metric='euclidean',
max_ratio=1.0, cross_check=False)
assert_equal(len(matches), 1)
matches = match_descriptors(descs1, descs2, metric='euclidean',
max_ratio=0.5, cross_check=False)
assert_equal(len(matches), 1)

View file

@ -0,0 +1,131 @@
import pytest
import numpy as np
from skimage._shared.testing import assert_equal, assert_almost_equal
from skimage.feature import ORB
from skimage._shared import testing
from skimage import data
from skimage._shared.testing import test_parallel, xfail, arch32
from skimage.util.dtype import _convert
img = data.coins()
@test_parallel()
@pytest.mark.parametrize('dtype', ['float32', 'float64', 'uint8',
'uint16', 'int64'])
def test_keypoints_orb_desired_no_of_keypoints(dtype):
_img = _convert(img, dtype)
detector_extractor = ORB(n_keypoints=10, fast_n=12, fast_threshold=0.20)
detector_extractor.detect(_img)
exp_rows = np.array([141., 108., 214.56, 131., 214.272, 67.,
206., 177., 108., 141.])
exp_cols = np.array([323., 328., 282.24, 292., 281.664, 85.,
260., 284., 328.8, 267.])
exp_scales = np.array([1, 1, 1.44, 1, 1.728, 1, 1, 1, 1.2, 1])
exp_orientations = np.array([-53.97446153, 59.5055285, -96.01885186,
-149.70789506, -94.70171899, -45.76429535,
-51.49752849, 113.57081195, 63.30428063,
-79.56091118])
exp_response = np.array([1.01168357, 0.82934145, 0.67784179, 0.57176438,
0.56637459, 0.52248355, 0.43696175, 0.42992376,
0.37700486, 0.36126832])
assert_almost_equal(exp_rows, detector_extractor.keypoints[:, 0])
assert_almost_equal(exp_cols, detector_extractor.keypoints[:, 1])
assert_almost_equal(exp_scales, detector_extractor.scales)
assert_almost_equal(exp_response, detector_extractor.responses, 5)
assert_almost_equal(exp_orientations,
np.rad2deg(detector_extractor.orientations), 4)
detector_extractor.detect_and_extract(img)
assert_almost_equal(exp_rows, detector_extractor.keypoints[:, 0])
assert_almost_equal(exp_cols, detector_extractor.keypoints[:, 1])
@pytest.mark.parametrize('dtype', ['float32', 'float64', 'uint8',
'uint16', 'int64'])
def test_keypoints_orb_less_than_desired_no_of_keypoints(dtype):
_img = _convert(img, dtype)
detector_extractor = ORB(n_keypoints=15, fast_n=12,
fast_threshold=0.33, downscale=2, n_scales=2)
detector_extractor.detect(_img)
exp_rows = np.array([108., 203., 140., 65., 58.])
exp_cols = np.array([293., 267., 202., 130., 291.])
exp_scales = np.array([1., 1., 1., 1., 1.])
exp_orientations = np.array([151.93906, -56.90052, -79.46341,
-59.42996, -158.26941])
exp_response = np.array([-0.1764169, 0.2652126, -0.0324343,
0.0400902, 0.2667641])
assert_almost_equal(exp_rows, detector_extractor.keypoints[:, 0])
assert_almost_equal(exp_cols, detector_extractor.keypoints[:, 1])
assert_almost_equal(exp_scales, detector_extractor.scales)
assert_almost_equal(exp_response, detector_extractor.responses)
assert_almost_equal(exp_orientations,
np.rad2deg(detector_extractor.orientations), 3)
detector_extractor.detect_and_extract(img)
assert_almost_equal(exp_rows, detector_extractor.keypoints[:, 0])
assert_almost_equal(exp_cols, detector_extractor.keypoints[:, 1])
@xfail(condition=arch32,
reason=('Known test failure on 32-bit platforms. See links for '
'details: '
'https://github.com/scikit-image/scikit-image/issues/3091 '
'https://github.com/scikit-image/scikit-image/issues/2529'))
def test_descriptor_orb():
detector_extractor = ORB(fast_n=12, fast_threshold=0.20)
exp_descriptors = np.array([[0, 0, 0, 1, 0, 0, 0, 1, 0, 1],
[1, 1, 0, 1, 0, 0, 0, 1, 0, 1],
[1, 1, 0, 0, 1, 0, 0, 0, 1, 1],
[1, 1, 1, 0, 0, 0, 1, 1, 1, 0],
[0, 0, 0, 1, 0, 1, 1, 1, 1, 1],
[1, 0, 0, 1, 1, 0, 0, 0, 1, 0],
[0, 1, 1, 1, 1, 1, 1, 1, 1, 0],
[1, 1, 1, 0, 1, 1, 1, 1, 0, 0],
[1, 1, 1, 1, 0, 0, 0, 1, 1, 1],
[0, 1, 1, 0, 0, 1, 1, 0, 1, 1],
[1, 1, 0, 0, 0, 0, 0, 0, 1, 1],
[1, 0, 0, 0, 0, 1, 0, 1, 1, 1],
[1, 0, 1, 1, 1, 0, 1, 0, 1, 0],
[0, 0, 1, 1, 0, 0, 0, 0, 1, 1],
[0, 1, 1, 0, 0, 0, 1, 0, 0, 1],
[0, 1, 1, 0, 0, 0, 1, 1, 1, 1],
[0, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[0, 0, 1, 1, 1, 1, 0, 1, 1, 0],
[0, 0, 1, 1, 1, 0, 1, 0, 0, 1],
[0, 1, 0, 0, 0, 0, 0, 0, 1, 0]], dtype=bool)
detector_extractor.detect(img)
detector_extractor.extract(img, detector_extractor.keypoints,
detector_extractor.scales,
detector_extractor.orientations)
assert_equal(exp_descriptors,
detector_extractor.descriptors[100:120, 10:20])
detector_extractor.detect_and_extract(img)
assert_equal(exp_descriptors,
detector_extractor.descriptors[100:120, 10:20])
keypoints_count = detector_extractor.keypoints.shape[0]
assert keypoints_count == detector_extractor.descriptors.shape[0]
assert keypoints_count == detector_extractor.orientations.shape[0]
assert keypoints_count == detector_extractor.responses.shape[0]
assert keypoints_count == detector_extractor.scales.shape[0]
def test_no_descriptors_extracted_orb():
img = np.ones((128, 128))
detector_extractor = ORB()
with testing.raises(RuntimeError):
detector_extractor.detect_and_extract(img)

View file

@ -0,0 +1,537 @@
import itertools
import numpy as np
import pytest
import unittest
from skimage._shared.testing import assert_array_almost_equal
from skimage._shared.testing import assert_equal
from scipy import ndimage as ndi
from skimage.feature import peak
np.random.seed(21)
class TestPeakLocalMax():
def test_trivial_case(self):
trivial = np.zeros((25, 25))
peak_indices = peak.peak_local_max(trivial, min_distance=1, indices=True)
assert type(peak_indices) is np.ndarray
assert peak_indices.size == 0
peaks = peak.peak_local_max(trivial, min_distance=1, indices=False)
assert (peaks.astype(np.bool) == trivial).all()
def test_noisy_peaks(self):
peak_locations = [(7, 7), (7, 13), (13, 7), (13, 13)]
# image with noise of amplitude 0.8 and peaks of amplitude 1
image = 0.8 * np.random.rand(20, 20)
for r, c in peak_locations:
image[r, c] = 1
peaks_detected = peak.peak_local_max(image, min_distance=5)
assert len(peaks_detected) == len(peak_locations)
for loc in peaks_detected:
assert tuple(loc) in peak_locations
def test_relative_threshold(self):
image = np.zeros((5, 5), dtype=np.uint8)
image[1, 1] = 10
image[3, 3] = 20
peaks = peak.peak_local_max(image, min_distance=1, threshold_rel=0.5)
assert len(peaks) == 1
assert_array_almost_equal(peaks, [(3, 3)])
def test_absolute_threshold(self):
image = np.zeros((5, 5), dtype=np.uint8)
image[1, 1] = 10
image[3, 3] = 20
peaks = peak.peak_local_max(image, min_distance=1, threshold_abs=10)
assert len(peaks) == 1
assert_array_almost_equal(peaks, [(3, 3)])
def test_constant_image(self):
image = np.full((20, 20), 128, dtype=np.uint8)
peaks = peak.peak_local_max(image, min_distance=1)
assert len(peaks) == 0
def test_flat_peak(self):
image = np.zeros((5, 5), dtype=np.uint8)
image[1:3, 1:3] = 10
peaks = peak.peak_local_max(image, min_distance=1)
assert len(peaks) == 4
def test_sorted_peaks(self):
image = np.zeros((5, 5), dtype=np.uint8)
image[1, 1] = 20
image[3, 3] = 10
peaks = peak.peak_local_max(image, min_distance=1)
assert peaks.tolist() == [[1, 1], [3, 3]]
image = np.zeros((3, 10))
image[1, (1, 3, 5, 7)] = (1, 2, 3, 4)
peaks = peak.peak_local_max(image, min_distance=1)
assert peaks.tolist() == [[1, 7], [1, 5], [1, 3], [1, 1]]
def test_num_peaks(self):
image = np.zeros((7, 7), dtype=np.uint8)
image[1, 1] = 10
image[1, 3] = 11
image[1, 5] = 12
image[3, 5] = 8
image[5, 3] = 7
assert len(peak.peak_local_max(image, min_distance=1, threshold_abs=0)) == 5
peaks_limited = peak.peak_local_max(
image, min_distance=1, threshold_abs=0, num_peaks=2)
assert len(peaks_limited) == 2
assert (1, 3) in peaks_limited
assert (1, 5) in peaks_limited
peaks_limited = peak.peak_local_max(
image, min_distance=1, threshold_abs=0, num_peaks=4)
assert len(peaks_limited) == 4
assert (1, 3) in peaks_limited
assert (1, 5) in peaks_limited
assert (1, 1) in peaks_limited
assert (3, 5) in peaks_limited
def test_num_peaks_and_labels(self):
image = np.zeros((7, 7), dtype=np.uint8)
labels = np.zeros((7, 7), dtype=np.uint8) + 20
image[1, 1] = 10
image[1, 3] = 11
image[1, 5] = 12
image[3, 5] = 8
image[5, 3] = 7
peaks_limited = peak.peak_local_max(
image, min_distance=1, threshold_abs=0, labels=labels)
assert len(peaks_limited) == 5
peaks_limited = peak.peak_local_max(
image, min_distance=1, threshold_abs=0, labels=labels, num_peaks=2)
assert len(peaks_limited) == 2
def test_num_peaks_tot_vs_labels_4quadrants(self):
np.random.seed(21)
image = np.random.uniform(size=(20, 30))
i, j = np.mgrid[0:20, 0:30]
labels = 1 + (i >= 10) + (j >= 15) * 2
result = peak.peak_local_max(image, labels=labels,
min_distance=1, threshold_rel=0,
indices=True,
num_peaks=np.inf,
num_peaks_per_label=2)
assert len(result) == 8
result = peak.peak_local_max(image, labels=labels,
min_distance=1, threshold_rel=0,
indices=True,
num_peaks=np.inf,
num_peaks_per_label=1)
assert len(result) == 4
result = peak.peak_local_max(image, labels=labels,
min_distance=1, threshold_rel=0,
indices=True,
num_peaks=2,
num_peaks_per_label=2)
assert len(result) == 2
def test_num_peaks3D(self):
# Issue 1354: the old code only hold for 2D arrays
# and this code would die with IndexError
image = np.zeros((10, 10, 100))
image[5,5,::5] = np.arange(20)
peaks_limited = peak.peak_local_max(image, min_distance=1, num_peaks=2)
assert len(peaks_limited) == 2
def test_reorder_labels(self):
image = np.random.uniform(size=(40, 60))
i, j = np.mgrid[0:40, 0:60]
labels = 1 + (i >= 20) + (j >= 30) * 2
labels[labels == 4] = 5
i, j = np.mgrid[-3:4, -3:4]
footprint = (i * i + j * j <= 9)
expected = np.zeros(image.shape, float)
for imin, imax in ((0, 20), (20, 40)):
for jmin, jmax in ((0, 30), (30, 60)):
expected[imin:imax, jmin:jmax] = ndi.maximum_filter(
image[imin:imax, jmin:jmax], footprint=footprint)
expected = (expected == image)
result = peak.peak_local_max(image, labels=labels, min_distance=1,
threshold_rel=0, footprint=footprint,
indices=False, exclude_border=False)
assert (result == expected).all()
def test_indices_with_labels(self):
image = np.random.uniform(size=(40, 60))
i, j = np.mgrid[0:40, 0:60]
labels = 1 + (i >= 20) + (j >= 30) * 2
i, j = np.mgrid[-3:4, -3:4]
footprint = (i * i + j * j <= 9)
expected = np.zeros(image.shape, float)
for imin, imax in ((0, 20), (20, 40)):
for jmin, jmax in ((0, 30), (30, 60)):
expected[imin:imax, jmin:jmax] = ndi.maximum_filter(
image[imin:imax, jmin:jmax], footprint=footprint)
expected = np.transpose(np.nonzero(expected == image))
expected = expected[np.argsort(image[tuple(expected.T)])[::-1]]
result = peak.peak_local_max(image, labels=labels, min_distance=1,
threshold_rel=0, footprint=footprint,
indices=True, exclude_border=False)
result = result[np.argsort(image[tuple(result.T)])[::-1]]
assert (result == expected).all()
def test_ndarray_indices_false(self):
nd_image = np.zeros((5, 5, 5))
nd_image[2, 2, 2] = 1
peaks = peak.peak_local_max(nd_image, min_distance=1, indices=False)
assert (peaks == nd_image.astype(np.bool)).all()
def test_ndarray_exclude_border(self):
nd_image = np.zeros((5, 5, 5))
nd_image[[1, 0, 0], [0, 1, 0], [0, 0, 1]] = 1
nd_image[3, 0, 0] = 1
nd_image[2, 2, 2] = 1
expected = np.zeros_like(nd_image, dtype=np.bool)
expected[2, 2, 2] = True
expectedNoBorder = nd_image > 0
result = peak.peak_local_max(nd_image, min_distance=2,
exclude_border=2, indices=False)
assert_equal(result, expected)
# Check that bools work as expected
assert_equal(
peak.peak_local_max(nd_image, min_distance=2,
exclude_border=2, indices=False),
peak.peak_local_max(nd_image, min_distance=2,
exclude_border=True, indices=False)
)
assert_equal(
peak.peak_local_max(nd_image, min_distance=2,
exclude_border=0, indices=False),
peak.peak_local_max(nd_image, min_distance=2,
exclude_border=False, indices=False)
)
# Check both versions with no border
assert_equal(
peak.peak_local_max(nd_image, min_distance=2,
exclude_border=0, indices=False),
expectedNoBorder,
)
assert_equal(
peak.peak_local_max(nd_image,
exclude_border=False, indices=False),
expectedNoBorder,
)
def test_empty(self):
image = np.zeros((10, 20))
labels = np.zeros((10, 20), int)
result = peak.peak_local_max(image, labels=labels,
footprint=np.ones((3, 3), bool),
min_distance=1, threshold_rel=0,
indices=False, exclude_border=False)
assert np.all(~ result)
def test_empty_non2d_indices(self):
image = np.zeros((10, 10, 10))
result = peak.peak_local_max(image,
footprint=np.ones((3, 3), bool),
min_distance=1, threshold_rel=0,
indices=True, exclude_border=False)
assert result.shape == (0, image.ndim)
def test_one_point(self):
image = np.zeros((10, 20))
labels = np.zeros((10, 20), int)
image[5, 5] = 1
labels[5, 5] = 1
result = peak.peak_local_max(image, labels=labels,
footprint=np.ones((3, 3), bool),
min_distance=1, threshold_rel=0,
indices=False, exclude_border=False)
assert np.all(result == (labels == 1))
def test_adjacent_and_same(self):
image = np.zeros((10, 20))
labels = np.zeros((10, 20), int)
image[5, 5:6] = 1
labels[5, 5:6] = 1
result = peak.peak_local_max(image, labels=labels,
footprint=np.ones((3, 3), bool),
min_distance=1, threshold_rel=0,
indices=False, exclude_border=False)
assert np.all(result == (labels == 1))
def test_adjacent_and_different(self):
image = np.zeros((10, 20))
labels = np.zeros((10, 20), int)
image[5, 5] = 1
image[5, 6] = .5
labels[5, 5:6] = 1
expected = (image == 1)
result = peak.peak_local_max(image, labels=labels,
footprint=np.ones((3, 3), bool),
min_distance=1, threshold_rel=0,
indices=False, exclude_border=False)
assert np.all(result == expected)
result = peak.peak_local_max(image, labels=labels,
min_distance=1, threshold_rel=0,
indices=False, exclude_border=False)
assert np.all(result == expected)
def test_not_adjacent_and_different(self):
image = np.zeros((10, 20))
labels = np.zeros((10, 20), int)
image[5, 5] = 1
image[5, 8] = .5
labels[image > 0] = 1
expected = (labels == 1)
result = peak.peak_local_max(image, labels=labels,
footprint=np.ones((3, 3), bool),
min_distance=1, threshold_rel=0,
indices=False, exclude_border=False)
assert np.all(result == expected)
def test_two_objects(self):
image = np.zeros((10, 20))
labels = np.zeros((10, 20), int)
image[5, 5] = 1
image[5, 15] = .5
labels[5, 5] = 1
labels[5, 15] = 2
expected = (labels > 0)
result = peak.peak_local_max(image, labels=labels,
footprint=np.ones((3, 3), bool),
min_distance=1, threshold_rel=0,
indices=False, exclude_border=False)
assert np.all(result == expected)
def test_adjacent_different_objects(self):
image = np.zeros((10, 20))
labels = np.zeros((10, 20), int)
image[5, 5] = 1
image[5, 6] = .5
labels[5, 5] = 1
labels[5, 6] = 2
expected = (labels > 0)
result = peak.peak_local_max(image, labels=labels,
footprint=np.ones((3, 3), bool),
min_distance=1, threshold_rel=0,
indices=False, exclude_border=False)
assert np.all(result == expected)
def test_four_quadrants(self):
image = np.random.uniform(size=(20, 30))
i, j = np.mgrid[0:20, 0:30]
labels = 1 + (i >= 10) + (j >= 15) * 2
i, j = np.mgrid[-3:4, -3:4]
footprint = (i * i + j * j <= 9)
expected = np.zeros(image.shape, float)
for imin, imax in ((0, 10), (10, 20)):
for jmin, jmax in ((0, 15), (15, 30)):
expected[imin:imax, jmin:jmax] = ndi.maximum_filter(
image[imin:imax, jmin:jmax], footprint=footprint)
expected = (expected == image)
result = peak.peak_local_max(image, labels=labels, footprint=footprint,
min_distance=1, threshold_rel=0,
indices=False, exclude_border=False)
assert np.all(result == expected)
def test_disk(self):
'''regression test of img-1194, footprint = [1]
Test peak.peak_local_max when every point is a local maximum
'''
image = np.random.uniform(size=(10, 20))
footprint = np.array([[1]])
result = peak.peak_local_max(image, labels=np.ones((10, 20)),
footprint=footprint,
min_distance=1, threshold_rel=0,
threshold_abs=-1, indices=False,
exclude_border=False)
assert np.all(result)
result = peak.peak_local_max(image, footprint=footprint, threshold_abs=-1,
indices=False, exclude_border=False)
assert np.all(result)
def test_3D(self):
image = np.zeros((30, 30, 30))
image[15, 15, 15] = 1
image[5, 5, 5] = 1
assert_equal(peak.peak_local_max(image, min_distance=10, threshold_rel=0),
[[15, 15, 15]])
assert_equal(peak.peak_local_max(image, min_distance=6, threshold_rel=0),
[[15, 15, 15]])
assert sorted(peak.peak_local_max(image, min_distance=10, threshold_rel=0,
exclude_border=False).tolist()) == \
[[5, 5, 5], [15, 15, 15]]
assert sorted(peak.peak_local_max(image, min_distance=5,
threshold_rel=0).tolist()) == \
[[5, 5, 5], [15, 15, 15]]
def test_4D(self):
image = np.zeros((30, 30, 30, 30))
image[15, 15, 15, 15] = 1
image[5, 5, 5, 5] = 1
assert_equal(peak.peak_local_max(image, min_distance=10, threshold_rel=0),
[[15, 15, 15, 15]])
assert_equal(peak.peak_local_max(image, min_distance=6, threshold_rel=0),
[[15, 15, 15, 15]])
assert sorted(peak.peak_local_max(image, min_distance=10, threshold_rel=0,
exclude_border=False).tolist()) == \
[[5, 5, 5, 5], [15, 15, 15, 15]]
assert sorted(peak.peak_local_max(image, min_distance=5,
threshold_rel=0).tolist()) == \
[[5, 5, 5, 5], [15, 15, 15, 15]]
def test_threshold_rel_default(self):
image = np.ones((5, 5))
image[2, 2] = 1
assert len(peak.peak_local_max(image)) == 0
image[2, 2] = 2
assert_equal(peak.peak_local_max(image), [[2, 2]])
image[2, 2] = 0
assert len(peak.peak_local_max(image, min_distance=0)) == image.size - 1
@pytest.mark.parametrize(
["indices"],
[[indices] for indices in itertools.product(range(5), range(5))],
)
def test_exclude_border(indices):
image = np.zeros((5, 5))
image[indices] = 1
# exclude_border = False, means it will always be found.
assert len(peak.peak_local_max(image, exclude_border=False)) == 1
# exclude_border = 0, means it will always be found.
assert len(peak.peak_local_max(image, exclude_border=0)) == 1
# exclude_border = True, min_distance=1 means it will be found unless it's
# on the edge.
if indices[0] in (0, 4) or indices[1] in (0, 4):
expected_peaks = 0
else:
expected_peaks = 1
assert len(peak.peak_local_max(
image, min_distance=1, exclude_border=True)) == expected_peaks
# exclude_border = (1, 0) means it will be found unless it's on the edge of
# the first dimension.
if indices[0] in (0, 4):
expected_peaks = 0
else:
expected_peaks = 1
assert len(peak.peak_local_max(
image, exclude_border=(1, 0))) == expected_peaks
# exclude_border = (0, 1) means it will be found unless it's on the edge of
# the second dimension.
if indices[1] in (0, 4):
expected_peaks = 0
else:
expected_peaks = 1
assert len(peak.peak_local_max(
image, exclude_border=(0, 1))) == expected_peaks
def test_exclude_border_errors():
image = np.zeros((5, 5))
# exclude_border doesn't have the right cardinality.
with pytest.raises(ValueError):
assert peak.peak_local_max(image, exclude_border=(1,))
# exclude_border doesn't have the right type
with pytest.raises(TypeError):
assert peak.peak_local_max(image, exclude_border=1.0)
# exclude_border is a tuple of the right cardinality but contains
# non-integer values.
with pytest.raises(ValueError):
assert peak.peak_local_max(image, exclude_border=(1, 'a'))
# exclude_border is a tuple of the right cardinality but contains a
# negative value.
with pytest.raises(ValueError):
assert peak.peak_local_max(image, exclude_border=(1, -1))
# exclude_border is a negative value.
with pytest.raises(ValueError):
assert peak.peak_local_max(image, exclude_border=-1)
class TestProminentPeaks(unittest.TestCase):
def test_isolated_peaks(self):
image = np.zeros((15, 15))
x0, y0, i0 = (12, 8, 1)
x1, y1, i1 = (2, 2, 1)
x2, y2, i2 = (5, 13, 1)
image[y0, x0] = i0
image[y1, x1] = i1
image[y2, x2] = i2
out = peak._prominent_peaks(image)
assert len(out[0]) == 3
for i, x, y in zip (out[0], out[1], out[2]):
self.assertTrue(i in (i0, i1, i2))
self.assertTrue(x in (x0, x1, x2))
self.assertTrue(y in (y0, y1, y2))
def test_threshold(self):
image = np.zeros((15, 15))
x0, y0, i0 = (12, 8, 10)
x1, y1, i1 = (2, 2, 8)
x2, y2, i2 = (5, 13, 10)
image[y0, x0] = i0
image[y1, x1] = i1
image[y2, x2] = i2
out = peak._prominent_peaks(image, threshold=None)
assert len(out[0]) == 3
for i, x, y in zip (out[0], out[1], out[2]):
self.assertTrue(i in (i0, i1, i2))
self.assertTrue(x in (x0, x1, x2))
out = peak._prominent_peaks(image, threshold=9)
assert len(out[0]) == 2
for i, x, y in zip (out[0], out[1], out[2]):
self.assertTrue(i in (i0, i2))
self.assertTrue(x in (x0, x2))
self.assertTrue(y in (y0, y2))
def test_peaks_in_contact(self):
image = np.zeros((15, 15))
x0, y0, i0 = (8, 8, 1)
x1, y1, i1 = (7, 7, 1) # prominent peak
x2, y2, i2 = (6, 6, 1)
image[y0, x0] = i0
image[y1, x1] = i1
image[y2, x2] = i2
out = peak._prominent_peaks(image, min_xdistance=3,
min_ydistance=3,)
assert_equal(out[0], np.array((i1,)))
assert_equal(out[1], np.array((x1,)))
assert_equal(out[2], np.array((y1,)))
def test_input_labels_unmodified(self):
image = np.zeros((10, 20))
labels = np.zeros((10, 20), int)
image[5, 5] = 1
labels[5, 5] = 1
labelsin = labels.copy()
result = peak.peak_local_max(image, labels=labels,
footprint=np.ones((3, 3), bool),
min_distance=1, threshold_rel=0,
indices=False, exclude_border=False)
assert np.all(labels == labelsin)
def test_many_objects(self):
mask = np.zeros([500, 500], dtype=bool)
x, y = np.indices((500, 500))
x_c = x // 20 * 20 + 10
y_c = y // 20 * 20 + 10
mask[(x - x_c) ** 2 + (y - y_c) ** 2 < 8 ** 2] = True
labels, num_objs = ndi.label(mask)
dist = ndi.distance_transform_edt(mask)
local_max = peak.peak_local_max(dist, min_distance=20, indices=True,
exclude_border=False, labels=labels)
assert len(local_max) == 625

View file

@ -0,0 +1,186 @@
import numpy as np
from skimage._shared.testing import assert_almost_equal, assert_equal
from skimage import data, img_as_float
from skimage.morphology import diamond
from skimage.feature import match_template, peak_local_max
from skimage._shared import testing
def test_template():
size = 100
# Float prefactors ensure that image range is between 0 and 1
image = np.full((400, 400), 0.5)
target = 0.1 * (np.tri(size) + np.tri(size)[::-1])
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 += 0.1 * np.random.uniform(size=(400, 400))
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):
assert_almost_equal(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.full((N, N), 0.5)
image[ipos:ipos + n, jpos:jpos + n] = 1
image[ineg:ineg + n, jneg:jneg + n] = 0
# 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 = 0.5 + 1e-9 * 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))
with testing.raises(ValueError):
match_template(template, image)
def test_pad_input():
"""Test `match_template` when `pad_input=True`.
This test places two full templates (one with values lower than the image
mean, the other higher) and two half templates, which are on the edges of
the image. The two full templates should score the top (positive and
negative) matches and the centers of the half templates should score 2nd.
"""
# Float prefactors ensure that image range is between 0 and 1
template = 0.5 * diamond(2)
image = 0.5 * np.ones((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,
constant_values=image.mean())
# get the max and min results.
sorted_result = np.argsort(result.flat)
i, j = np.unravel_index(sorted_result[:2], result.shape)
assert_equal(j, (12, 0))
i, j = np.unravel_index(sorted_result[-2:], result.shape)
assert_equal(j, (18, 6))
def test_3d():
np.random.seed(1)
template = np.random.rand(3, 3, 3)
image = np.zeros((12, 12, 12))
image[3:6, 5:8, 4:7] = template
result = match_template(image, template)
assert_equal(result.shape, (10, 10, 10))
assert_equal(np.unravel_index(result.argmax(), result.shape), (3, 5, 4))
def test_3d_pad_input():
np.random.seed(1)
template = np.random.rand(3, 3, 3)
image = np.zeros((12, 12, 12))
image[3:6, 5:8, 4:7] = template
result = match_template(image, template, pad_input=True)
assert_equal(result.shape, (12, 12, 12))
assert_equal(np.unravel_index(result.argmax(), result.shape), (4, 6, 5))
def test_padding_reflect():
template = diamond(2)
image = np.zeros((10, 10))
image[2:7, :3] = template[:, -3:]
result = match_template(image, template, pad_input=True,
mode='reflect')
assert_equal(np.unravel_index(result.argmax(), result.shape), (4, 0))
def test_wrong_input():
image = np.ones((5, 5, 1))
template = np.ones((3, 3))
with testing.raises(ValueError):
match_template(template, image)
image = np.ones((5, 5))
template = np.ones((3, 3, 2))
with testing.raises(ValueError):
match_template(template, image)
image = np.ones((5, 5, 3, 3))
template = np.ones((3, 3, 2))
with testing.raises(ValueError):
match_template(template, image)
def test_bounding_values():
image = img_as_float(data.page())
template = np.zeros((3, 3))
template[1, 1] = 1
result = match_template(img_as_float(data.page()), template)
print(result.max())
assert result.max() < 1 + 1e-7
assert result.min() > -1 - 1e-7

View file

@ -0,0 +1,294 @@
import numpy as np
from skimage.feature import (greycomatrix,
greycoprops,
local_binary_pattern,
multiblock_lbp)
from skimage._shared.testing import test_parallel
from skimage.transform import integral_image
from skimage._shared import testing
class TestGLCM():
def setup(self):
self.image = np.array([[0, 0, 1, 1],
[0, 0, 1, 1],
[0, 2, 2, 2],
[2, 2, 3, 3]], dtype=np.uint8)
@test_parallel()
def test_output_angles(self):
result = greycomatrix(self.image, [1], [0, np.pi / 4, np.pi / 2, 3 * np.pi / 4], 4)
assert result.shape == (4, 4, 1, 4)
expected1 = np.array([[2, 2, 1, 0],
[0, 2, 0, 0],
[0, 0, 3, 1],
[0, 0, 0, 1]], dtype=np.uint32)
np.testing.assert_array_equal(result[:, :, 0, 0], expected1)
expected2 = np.array([[1, 1, 3, 0],
[0, 1, 1, 0],
[0, 0, 0, 2],
[0, 0, 0, 0]], dtype=np.uint32)
np.testing.assert_array_equal(result[:, :, 0, 1], expected2)
expected3 = np.array([[3, 0, 2, 0],
[0, 2, 2, 0],
[0, 0, 1, 2],
[0, 0, 0, 0]], dtype=np.uint32)
np.testing.assert_array_equal(result[:, :, 0, 2], expected3)
expected4 = np.array([[2, 0, 0, 0],
[1, 1, 2, 0],
[0, 0, 2, 1],
[0, 0, 0, 0]], dtype=np.uint32)
np.testing.assert_array_equal(result[:, :, 0, 3], expected4)
def test_output_symmetric_1(self):
result = greycomatrix(self.image, [1], [np.pi / 2], 4,
symmetric=True)
assert result.shape == (4, 4, 1, 1)
expected = np.array([[6, 0, 2, 0],
[0, 4, 2, 0],
[2, 2, 2, 2],
[0, 0, 2, 0]], dtype=np.uint32)
np.testing.assert_array_equal(result[:, :, 0, 0], expected)
def test_error_raise_float(self):
for dtype in [np.float, np.double, np.float16, np.float32, np.float64]:
with testing.raises(ValueError):
greycomatrix(self.image.astype(dtype), [1], [np.pi], 4)
def test_error_raise_int_types(self):
for dtype in [np.int16, np.int32, np.int64, np.uint16, np.uint32, np.uint64]:
with testing.raises(ValueError):
greycomatrix(self.image.astype(dtype), [1], [np.pi])
def test_error_raise_negative(self):
with testing.raises(ValueError):
greycomatrix(self.image.astype(np.int16) - 1, [1], [np.pi], 4)
def test_error_raise_levels_smaller_max(self):
with testing.raises(ValueError):
greycomatrix(self.image - 1, [1], [np.pi], 3)
def test_image_data_types(self):
for dtype in [np.uint16, np.uint32, np.uint64, np.int16, np.int32, np.int64]:
img = self.image.astype(dtype)
result = greycomatrix(img, [1], [np.pi / 2], 4,
symmetric=True)
assert result.shape == (4, 4, 1, 1)
expected = np.array([[6, 0, 2, 0],
[0, 4, 2, 0],
[2, 2, 2, 2],
[0, 0, 2, 0]], dtype=np.uint32)
np.testing.assert_array_equal(result[:, :, 0, 0], expected)
return
def test_output_distance(self):
im = np.array([[0, 0, 0, 0],
[1, 0, 0, 1],
[2, 0, 0, 2],
[3, 0, 0, 3]], dtype=np.uint8)
result = greycomatrix(im, [3], [0], 4, symmetric=False)
expected = np.array([[1, 0, 0, 0],
[0, 1, 0, 0],
[0, 0, 1, 0],
[0, 0, 0, 1]], dtype=np.uint32)
np.testing.assert_array_equal(result[:, :, 0, 0], expected)
def test_output_combo(self):
im = np.array([[0],
[1],
[2],
[3]], dtype=np.uint8)
result = greycomatrix(im, [1, 2], [0, np.pi / 2], 4)
assert result.shape == (4, 4, 2, 2)
z = np.zeros((4, 4), dtype=np.uint32)
e1 = np.array([[0, 1, 0, 0],
[0, 0, 1, 0],
[0, 0, 0, 1],
[0, 0, 0, 0]], dtype=np.uint32)
e2 = np.array([[0, 0, 1, 0],
[0, 0, 0, 1],
[0, 0, 0, 0],
[0, 0, 0, 0]], dtype=np.uint32)
np.testing.assert_array_equal(result[:, :, 0, 0], z)
np.testing.assert_array_equal(result[:, :, 1, 0], z)
np.testing.assert_array_equal(result[:, :, 0, 1], e1)
np.testing.assert_array_equal(result[:, :, 1, 1], e2)
def test_output_empty(self):
result = greycomatrix(self.image, [10], [0], 4)
np.testing.assert_array_equal(result[:, :, 0, 0],
np.zeros((4, 4), dtype=np.uint32))
result = greycomatrix(self.image, [10], [0], 4, normed=True)
np.testing.assert_array_equal(result[:, :, 0, 0],
np.zeros((4, 4), dtype=np.uint32))
def test_normed_symmetric(self):
result = greycomatrix(self.image, [1, 2, 3],
[0, np.pi / 2, np.pi], 4,
normed=True, symmetric=True)
for d in range(result.shape[2]):
for a in range(result.shape[3]):
np.testing.assert_almost_equal(result[:, :, d, a].sum(),
1.0)
np.testing.assert_array_equal(result[:, :, d, a],
result[:, :, d, a].transpose())
def test_contrast(self):
result = greycomatrix(self.image, [1, 2], [0], 4,
normed=True, symmetric=True)
result = np.round(result, 3)
contrast = greycoprops(result, 'contrast')
np.testing.assert_almost_equal(contrast[0, 0], 0.585, decimal=3)
def test_dissimilarity(self):
result = greycomatrix(self.image, [1], [0, np.pi / 2], 4,
normed=True, symmetric=True)
result = np.round(result, 3)
dissimilarity = greycoprops(result, 'dissimilarity')
np.testing.assert_almost_equal(dissimilarity[0, 0], 0.418, decimal=3)
def test_dissimilarity_2(self):
result = greycomatrix(self.image, [1, 3], [np.pi / 2], 4,
normed=True, symmetric=True)
result = np.round(result, 3)
dissimilarity = greycoprops(result, 'dissimilarity')[0, 0]
np.testing.assert_almost_equal(dissimilarity, 0.665, decimal=3)
def test_non_normalized_glcm(self):
img = (np.random.random((100, 100)) * 8).astype(np.uint8)
p = greycomatrix(img, [1, 2, 4, 5], [0, 0.25, 1, 1.5], levels=8)
np.testing.assert_(np.max(greycoprops(p, 'correlation')) < 1.0)
def test_invalid_property(self):
result = greycomatrix(self.image, [1], [0], 4)
with testing.raises(ValueError):
greycoprops(result, 'ABC')
def test_homogeneity(self):
result = greycomatrix(self.image, [1], [0, 6], 4, normed=True,
symmetric=True)
homogeneity = greycoprops(result, 'homogeneity')[0, 0]
np.testing.assert_almost_equal(homogeneity, 0.80833333)
def test_energy(self):
result = greycomatrix(self.image, [1], [0, 4], 4, normed=True,
symmetric=True)
energy = greycoprops(result, 'energy')[0, 0]
np.testing.assert_almost_equal(energy, 0.38188131)
def test_correlation(self):
result = greycomatrix(self.image, [1, 2], [0], 4, normed=True,
symmetric=True)
energy = greycoprops(result, 'correlation')
np.testing.assert_almost_equal(energy[0, 0], 0.71953255)
np.testing.assert_almost_equal(energy[1, 0], 0.41176470)
def test_uniform_properties(self):
im = np.ones((4, 4), dtype=np.uint8)
result = greycomatrix(im, [1, 2, 8], [0, np.pi / 2], 4, normed=True,
symmetric=True)
for prop in ['contrast', 'dissimilarity', 'homogeneity',
'energy', 'correlation', 'ASM']:
greycoprops(result, prop)
class TestLBP():
def setup(self):
self.image = np.array([[255, 6, 255, 0, 141, 0],
[ 48, 250, 204, 166, 223, 63],
[ 8, 0, 159, 50, 255, 30],
[167, 255, 63, 40, 128, 255],
[ 0, 255, 30, 34, 255, 24],
[146, 241, 255, 0, 189, 126]], dtype='double')
@test_parallel()
def test_default(self):
lbp = local_binary_pattern(self.image, 8, 1, 'default')
ref = np.array([[ 0, 251, 0, 255, 96, 255],
[143, 0, 20, 153, 64, 56],
[238, 255, 12, 191, 0, 252],
[129, 64., 62, 159, 199, 0],
[255, 4, 255, 175, 0, 254],
[ 3, 5, 0, 255, 4, 24]])
np.testing.assert_array_equal(lbp, ref)
def test_ror(self):
lbp = local_binary_pattern(self.image, 8, 1, 'ror')
ref = np.array([[ 0, 127, 0, 255, 3, 255],
[ 31, 0, 5, 51, 1, 7],
[119, 255, 3, 127, 0, 63],
[ 3, 1, 31, 63, 31, 0],
[255, 1, 255, 95, 0, 127],
[ 3, 5, 0, 255, 1, 3]])
np.testing.assert_array_equal(lbp, ref)
def test_uniform(self):
lbp = local_binary_pattern(self.image, 8, 1, 'uniform')
ref = np.array([[0, 7, 0, 8, 2, 8],
[5, 0, 9, 9, 1, 3],
[9, 8, 2, 7, 0, 6],
[2, 1, 5, 6, 5, 0],
[8, 1, 8, 9, 0, 7],
[2, 9, 0, 8, 1, 2]])
np.testing.assert_array_equal(lbp, ref)
def test_var(self):
# Test idea: mean of variance is estimate of overall variance.
# Fix random seed for test stability.
np.random.seed(13141516)
# Create random image with known variance.
image = np.random.rand(500, 500)
target_std = 0.3
image = image / image.std() * target_std
# Use P=4 to avoid interpolation effects
P, R = 4, 1
lbp = local_binary_pattern(image, P, R, 'var')
# Take central part to avoid border effect.
lbp = lbp[5:-5, 5:-5]
# The LBP variance is biased (ddof=0), correct for that.
expected = target_std**2 * (P-1)/P
np.testing.assert_almost_equal(lbp.mean(), expected, 4)
def test_nri_uniform(self):
lbp = local_binary_pattern(self.image, 8, 1, 'nri_uniform')
ref = np.array([[ 0, 54, 0, 57, 12, 57],
[34, 0, 58, 58, 3, 22],
[58, 57, 15, 50, 0, 47],
[10, 3, 40, 42, 35, 0],
[57, 7, 57, 58, 0, 56],
[ 9, 58, 0, 57, 7, 14]])
np.testing.assert_array_almost_equal(lbp, ref)
class TestMBLBP():
def test_single_mblbp(self):
# Create dummy matrix where first and fifth rectangles have greater
# value than the central one. Therefore, the following bits
# should be 1.
test_img = np.zeros((9, 9), dtype='uint8')
test_img[3:6, 3:6] = 1
test_img[:3, :3] = 255
test_img[6:, 6:] = 255
# MB-LBP is filled in reverse order. So the first and fifth bits from
# the end should be filled.
correct_answer = 0b10001000
int_img = integral_image(test_img)
lbp_code = multiblock_lbp(int_img, 0, 0, 3, 3)
np.testing.assert_equal(lbp_code, correct_answer)

View file

@ -0,0 +1,81 @@
import numpy as np
try:
import matplotlib.pyplot as plt
except ImportError:
plt = None
from skimage._shared.testing import assert_equal
from skimage.feature.util import (FeatureDetector, DescriptorExtractor,
_prepare_grayscale_input_2D,
_mask_border_keypoints, plot_matches)
from skimage._shared import testing
def test_feature_detector():
with testing.raises(NotImplementedError):
FeatureDetector().detect(None)
def test_descriptor_extractor():
with testing.raises(NotImplementedError):
DescriptorExtractor().extract(None, None)
def test_prepare_grayscale_input_2D():
with testing.raises(ValueError):
_prepare_grayscale_input_2D(np.zeros((3, 3, 3)))
with testing.raises(ValueError):
_prepare_grayscale_input_2D(np.zeros((3, 1)))
with testing.raises(ValueError):
_prepare_grayscale_input_2D(np.zeros((3, 1, 1)))
img = _prepare_grayscale_input_2D(np.zeros((3, 3)))
img = _prepare_grayscale_input_2D(np.zeros((3, 3, 1)))
img = _prepare_grayscale_input_2D(np.zeros((1, 3, 3)))
def test_mask_border_keypoints():
keypoints = np.array([[0, 0], [1, 1], [2, 2], [3, 3], [4, 4]])
assert_equal(_mask_border_keypoints((10, 10), keypoints, 0),
[1, 1, 1, 1, 1])
assert_equal(_mask_border_keypoints((10, 10), keypoints, 2),
[0, 0, 1, 1, 1])
assert_equal(_mask_border_keypoints((4, 4), keypoints, 2),
[0, 0, 1, 0, 0])
assert_equal(_mask_border_keypoints((10, 10), keypoints, 5),
[0, 0, 0, 0, 0])
assert_equal(_mask_border_keypoints((10, 10), keypoints, 4),
[0, 0, 0, 0, 1])
@testing.skipif(plt is None, reason="Matplotlib not installed")
def test_plot_matches():
fig, ax = plt.subplots(nrows=1, ncols=1)
shapes = (((10, 10), (10, 10)),
((10, 10), (12, 10)),
((10, 10), (10, 12)),
((10, 10), (12, 12)),
((12, 10), (10, 10)),
((10, 12), (10, 10)),
((12, 12), (10, 10)))
keypoints1 = 10 * np.random.rand(10, 2)
keypoints2 = 10 * np.random.rand(10, 2)
idxs1 = np.random.randint(10, size=10)
idxs2 = np.random.randint(10, size=10)
matches = np.column_stack((idxs1, idxs2))
for shape1, shape2 in shapes:
img1 = np.zeros(shape1)
img2 = np.zeros(shape2)
plot_matches(ax, img1, img2, keypoints1, keypoints2, matches)
plot_matches(ax, img1, img2, keypoints1, keypoints2, matches,
only_matches=True)
plot_matches(ax, img1, img2, keypoints1, keypoints2, matches,
keypoints_color='r')
plot_matches(ax, img1, img2, keypoints1, keypoints2, matches,
matches_color='r')
plot_matches(ax, img1, img2, keypoints1, keypoints2, matches,
alignment='vertical')