Merge pull request #298 from tonysyu/edge-masking-tweak

Edge filter refactor
This commit is contained in:
Johannes Schönberger
2012-09-04 07:13:39 -07:00
2 changed files with 236 additions and 203 deletions
+36 -28
View File
@@ -13,6 +13,26 @@ from skimage import img_as_float
from scipy.ndimage import convolve, binary_erosion, generate_binary_structure
EROSION_SELEM = generate_binary_structure(2, 2)
def _mask_filter_result(result, mask):
"""Return result after masking.
Input masks are eroded so that mask areas in the original image don't
affect values in the result.
"""
if mask is None:
result[0, :] = 0
result[-1, :] = 0
result[:, 0] = 0
result[:, -1] = 0
return result
else:
mask = binary_erosion(mask, EROSION_SELEM, border_value=0)
return result * mask
def sobel(image, mask=None):
"""Calculate the absolute magnitude Sobel to find edges.
@@ -22,6 +42,8 @@ def sobel(image, mask=None):
Image to process.
mask : array_like, dtype=bool, optional
An optional mask to limit the application to a certain area.
Note that pixels surrounding masked regions are also masked to
prevent masked regions from affecting the result.
Returns
-------
@@ -49,6 +71,8 @@ def hsobel(image, mask=None):
Image to process.
mask : array_like, dtype=bool, optional
An optional mask to limit the application to a certain area.
Note that pixels surrounding masked regions are also masked to
prevent masked regions from affecting the result.
Returns
-------
@@ -66,17 +90,11 @@ def hsobel(image, mask=None):
"""
image = img_as_float(image)
if mask is None:
mask = np.ones(image.shape, bool)
big_mask = binary_erosion(mask,
generate_binary_structure(2, 2),
border_value=0)
result = np.abs(convolve(image,
np.array([[ 1, 2, 1],
[ 0, 0, 0],
[-1,-2,-1]]).astype(float) / 4.0))
result[big_mask == False] = 0
return result
return _mask_filter_result(result, mask)
def vsobel(image, mask=None):
@@ -88,6 +106,8 @@ def vsobel(image, mask=None):
Image to process
mask : array_like, dtype=bool, optional
An optional mask to limit the application to a certain area
Note that pixels surrounding masked regions are also masked to
prevent masked regions from affecting the result.
Returns
-------
@@ -105,17 +125,11 @@ def vsobel(image, mask=None):
"""
image = img_as_float(image)
if mask is None:
mask = np.ones(image.shape, bool)
big_mask = binary_erosion(mask,
generate_binary_structure(2, 2),
border_value=0)
result = np.abs(convolve(image,
np.array([[1, 0, -1],
[2, 0, -2],
[1, 0, -1]]).astype(float) / 4.0))
result[big_mask == False] = 0
return result
return _mask_filter_result(result, mask)
def prewitt(image, mask=None):
@@ -127,6 +141,8 @@ def prewitt(image, mask=None):
Image to process.
mask : array_like, dtype=bool, optional
An optional mask to limit the application to a certain area.
Note that pixels surrounding masked regions are also masked to
prevent masked regions from affecting the result.
Returns
-------
@@ -150,6 +166,8 @@ def hprewitt(image, mask=None):
Image to process.
mask : array_like, dtype=bool, optional
An optional mask to limit the application to a certain area.
Note that pixels surrounding masked regions are also masked to
prevent masked regions from affecting the result.
Returns
-------
@@ -167,17 +185,11 @@ def hprewitt(image, mask=None):
"""
image = img_as_float(image)
if mask is None:
mask = np.ones(image.shape, bool)
big_mask = binary_erosion(mask,
generate_binary_structure(2, 2),
border_value=0)
result = np.abs(convolve(image,
np.array([[ 1, 1, 1],
[ 0, 0, 0],
[-1,-1,-1]]).astype(float) / 3.0))
result[big_mask == False] = 0
return result
return _mask_filter_result(result, mask)
def vprewitt(image, mask=None):
@@ -189,6 +201,8 @@ def vprewitt(image, mask=None):
Image to process.
mask : array_like, dtype=bool, optional
An optional mask to limit the application to a certain area.
Note that pixels surrounding masked regions are also masked to
prevent masked regions from affecting the result.
Returns
-------
@@ -206,14 +220,8 @@ def vprewitt(image, mask=None):
"""
image = img_as_float(image)
if mask is None:
mask = np.ones(image.shape, bool)
big_mask = binary_erosion(mask,
generate_binary_structure(2, 2),
border_value=0)
result = np.abs(convolve(image,
np.array([[1, 0, -1],
[1, 0, -1],
[1, 0, -1]]).astype(float) / 3.0))
result[big_mask == False] = 0
return result
return _mask_filter_result(result, mask)
+200 -175
View File
@@ -1,211 +1,236 @@
import os
from numpy.testing import *
import numpy as np
from scipy.ndimage import binary_dilation, binary_erosion
from numpy.testing import assert_array_almost_equal as assert_close
import skimage.filter as F
from skimage import data_dir, img_as_float
class TestSobel():
def test_00_00_zeros(self):
"""Sobel on an array of all zeros"""
result = F.sobel(np.zeros((10, 10)), np.ones((10, 10), bool))
assert (np.all(result == 0))
def test_sobel_zeros():
"""Sobel on an array of all zeros"""
result = F.sobel(np.zeros((10, 10)), np.ones((10, 10), bool))
assert (np.all(result == 0))
def test_00_01_mask(self):
"""Sobel on a masked array should be zero"""
np.random.seed(0)
result = F.sobel(np.random.uniform(size=(10, 10)),
np.zeros((10, 10), bool))
assert (np.all(result == 0))
def test_sobel_mask():
"""Sobel on a masked array should be zero"""
np.random.seed(0)
result = F.sobel(np.random.uniform(size=(10, 10)),
np.zeros((10, 10), bool))
assert (np.all(result == 0))
def test_01_01_horizontal(self):
"""Sobel on an edge should be a horizontal line"""
i, j = np.mgrid[-5:6, -5:6]
image = (i >= 0).astype(float)
result = F.sobel(image)
# Fudge the eroded points
i[np.abs(j) == 5] = 10000
assert (np.all(result[i == 0] == 1))
assert (np.all(result[np.abs(i) > 1] == 0))
def test_sobel_horizontal():
"""Sobel on an edge should be a horizontal line"""
i, j = np.mgrid[-5:6, -5:6]
image = (i >= 0).astype(float)
result = F.sobel(image)
# Fudge the eroded points
i[np.abs(j) == 5] = 10000
assert (np.all(result[i == 0] == 1))
assert (np.all(result[np.abs(i) > 1] == 0))
def test_01_02_vertical(self):
"""Sobel on a vertical edge should be a vertical line"""
i, j = np.mgrid[-5:6, -5:6]
image = (j >= 0).astype(float)
result = F.sobel(image)
j[np.abs(i) == 5] = 10000
assert (np.all(result[j == 0] == 1))
assert (np.all(result[np.abs(j) > 1] == 0))
def test_sobel_vertical():
"""Sobel on a vertical edge should be a vertical line"""
i, j = np.mgrid[-5:6, -5:6]
image = (j >= 0).astype(float)
result = F.sobel(image)
j[np.abs(i) == 5] = 10000
assert (np.all(result[j == 0] == 1))
assert (np.all(result[np.abs(j) > 1] == 0))
class TestHSobel():
def test_00_00_zeros(self):
"""Horizontal sobel on an array of all zeros"""
result = F.hsobel(np.zeros((10, 10)), np.ones((10, 10), bool))
assert (np.all(result == 0))
def test_hsobel_zeros():
"""Horizontal sobel on an array of all zeros"""
result = F.hsobel(np.zeros((10, 10)), np.ones((10, 10), bool))
assert (np.all(result == 0))
def test_00_01_mask(self):
"""Horizontal Sobel on a masked array should be zero"""
np.random.seed(0)
result = F.hsobel(np.random.uniform(size=(10, 10)),
np.zeros((10, 10), bool))
assert (np.all(result == 0))
def test_hsobel_mask():
"""Horizontal Sobel on a masked array should be zero"""
np.random.seed(0)
result = F.hsobel(np.random.uniform(size=(10, 10)),
np.zeros((10, 10), bool))
assert (np.all(result == 0))
def test_01_01_horizontal(self):
"""Horizontal Sobel on an edge should be a horizontal line"""
i, j = np.mgrid[-5:6, -5:6]
image = (i >= 0).astype(float)
result = F.hsobel(image)
# Fudge the eroded points
i[np.abs(j) == 5] = 10000
assert (np.all(result[i == 0] == 1))
assert (np.all(result[np.abs(i) > 1] == 0))
def test_hsobel_horizontal():
"""Horizontal Sobel on an edge should be a horizontal line"""
i, j = np.mgrid[-5:6, -5:6]
image = (i >= 0).astype(float)
result = F.hsobel(image)
# Fudge the eroded points
i[np.abs(j) == 5] = 10000
assert (np.all(result[i == 0] == 1))
assert (np.all(result[np.abs(i) > 1] == 0))
def test_01_02_vertical(self):
"""Horizontal Sobel on a vertical edge should be zero"""
i, j = np.mgrid[-5:6, -5:6]
image = (j >= 0).astype(float)
result = F.hsobel(image)
assert (np.all(result == 0))
def test_hsobel_vertical():
"""Horizontal Sobel on a vertical edge should be zero"""
i, j = np.mgrid[-5:6, -5:6]
image = (j >= 0).astype(float)
result = F.hsobel(image)
assert (np.all(result == 0))
class TestVSobel():
def test_00_00_zeros(self):
"""Vertical sobel on an array of all zeros"""
result = F.vsobel(np.zeros((10, 10)), np.ones((10, 10), bool))
assert (np.all(result == 0))
def test_vsobel_zeros():
"""Vertical sobel on an array of all zeros"""
result = F.vsobel(np.zeros((10, 10)), np.ones((10, 10), bool))
assert (np.all(result == 0))
def test_00_01_mask(self):
"""Vertical Sobel on a masked array should be zero"""
np.random.seed(0)
result = F.vsobel(np.random.uniform(size=(10, 10)),
np.zeros((10, 10), bool))
assert (np.all(result == 0))
def test_vsobel_mask():
"""Vertical Sobel on a masked array should be zero"""
np.random.seed(0)
result = F.vsobel(np.random.uniform(size=(10, 10)),
np.zeros((10, 10), bool))
assert (np.all(result == 0))
def test_01_01_vertical(self):
"""Vertical Sobel on an edge should be a vertical line"""
i, j = np.mgrid[-5:6, -5:6]
image = (j >= 0).astype(float)
result = F.vsobel(image)
# Fudge the eroded points
j[np.abs(i) == 5] = 10000
assert (np.all(result[j == 0] == 1))
assert (np.all(result[np.abs(j) > 1] == 0))
def test_vsobel_vertical():
"""Vertical Sobel on an edge should be a vertical line"""
i, j = np.mgrid[-5:6, -5:6]
image = (j >= 0).astype(float)
result = F.vsobel(image)
# Fudge the eroded points
j[np.abs(i) == 5] = 10000
assert (np.all(result[j == 0] == 1))
assert (np.all(result[np.abs(j) > 1] == 0))
def test_01_02_horizontal(self):
"""vertical Sobel on a horizontal edge should be zero"""
i, j = np.mgrid[-5:6, -5:6]
image = (i >= 0).astype(float)
result = F.vsobel(image)
eps = .000001
assert (np.all(np.abs(result) < eps))
def test_vsobel_horizontal():
"""vertical Sobel on a horizontal edge should be zero"""
i, j = np.mgrid[-5:6, -5:6]
image = (i >= 0).astype(float)
result = F.vsobel(image)
eps = .000001
assert (np.all(np.abs(result) < eps))
class TestPrewitt():
def test_00_00_zeros(self):
"""Prewitt on an array of all zeros"""
result = F.prewitt(np.zeros((10, 10)), np.ones((10, 10), bool))
assert (np.all(result == 0))
def test_prewitt_zeros():
"""Prewitt on an array of all zeros"""
result = F.prewitt(np.zeros((10, 10)), np.ones((10, 10), bool))
assert (np.all(result == 0))
def test_00_01_mask(self):
"""Prewitt on a masked array should be zero"""
np.random.seed(0)
result = F.prewitt(np.random.uniform(size=(10, 10)),
np.zeros((10, 10), bool))
eps = .000001
assert (np.all(np.abs(result) < eps))
def test_prewitt_mask():
"""Prewitt on a masked array should be zero"""
np.random.seed(0)
result = F.prewitt(np.random.uniform(size=(10, 10)),
np.zeros((10, 10), bool))
eps = .000001
assert (np.all(np.abs(result) < eps))
def test_01_01_horizontal(self):
"""Prewitt on an edge should be a horizontal line"""
i, j = np.mgrid[-5:6, -5:6]
image = (i >= 0).astype(float)
result = F.prewitt(image)
# Fudge the eroded points
i[np.abs(j) == 5] = 10000
eps = .000001
assert (np.all(result[i == 0] == 1))
assert (np.all(np.abs(result[np.abs(i) > 1]) < eps))
def test_prewitt_horizontal():
"""Prewitt on an edge should be a horizontal line"""
i, j = np.mgrid[-5:6, -5:6]
image = (i >= 0).astype(float)
result = F.prewitt(image)
# Fudge the eroded points
i[np.abs(j) == 5] = 10000
eps = .000001
assert (np.all(result[i == 0] == 1))
assert (np.all(np.abs(result[np.abs(i) > 1]) < eps))
def test_01_02_vertical(self):
"""Prewitt on a vertical edge should be a vertical line"""
i, j = np.mgrid[-5:6, -5:6]
image = (j >= 0).astype(float)
result = F.prewitt(image)
eps = .000001
j[np.abs(i) == 5] = 10000
assert (np.all(result[j == 0] == 1))
assert (np.all(np.abs(result[np.abs(j) > 1]) < eps))
def test_prewitt_vertical():
"""Prewitt on a vertical edge should be a vertical line"""
i, j = np.mgrid[-5:6, -5:6]
image = (j >= 0).astype(float)
result = F.prewitt(image)
eps = .000001
j[np.abs(i) == 5] = 10000
assert (np.all(result[j == 0] == 1))
assert (np.all(np.abs(result[np.abs(j) > 1]) < eps))
class TestHPrewitt():
def test_00_00_zeros(self):
"""Horizontal sobel on an array of all zeros"""
result = F.hprewitt(np.zeros((10, 10)), np.ones((10, 10), bool))
assert (np.all(result == 0))
def test_hprewitt_zeros():
"""Horizontal prewitt on an array of all zeros"""
result = F.hprewitt(np.zeros((10, 10)), np.ones((10, 10), bool))
assert (np.all(result == 0))
def test_00_01_mask(self):
"""Horizontal prewitt on a masked array should be zero"""
np.random.seed(0)
result = F.hprewitt(np.random.uniform(size=(10, 10)),
np.zeros((10, 10), bool))
eps = .000001
assert (np.all(np.abs(result) < eps))
def test_hprewitt_mask():
"""Horizontal prewitt on a masked array should be zero"""
np.random.seed(0)
result = F.hprewitt(np.random.uniform(size=(10, 10)),
np.zeros((10, 10), bool))
eps = .000001
assert (np.all(np.abs(result) < eps))
def test_01_01_horizontal(self):
"""Horizontal prewitt on an edge should be a horizontal line"""
i, j = np.mgrid[-5:6, -5:6]
image = (i >= 0).astype(float)
result = F.hprewitt(image)
# Fudge the eroded points
i[np.abs(j) == 5] = 10000
eps = .000001
assert (np.all(result[i == 0] == 1))
assert (np.all(np.abs(result[np.abs(i) > 1]) < eps))
def test_hprewitt_horizontal():
"""Horizontal prewitt on an edge should be a horizontal line"""
i, j = np.mgrid[-5:6, -5:6]
image = (i >= 0).astype(float)
result = F.hprewitt(image)
# Fudge the eroded points
i[np.abs(j) == 5] = 10000
eps = .000001
assert (np.all(result[i == 0] == 1))
assert (np.all(np.abs(result[np.abs(i) > 1]) < eps))
def test_01_02_vertical(self):
"""Horizontal prewitt on a vertical edge should be zero"""
i, j = np.mgrid[-5:6, -5:6]
image = (j >= 0).astype(float)
result = F.hprewitt(image)
eps = .000001
assert (np.all(np.abs(result) < eps))
def test_hprewitt_vertical():
"""Horizontal prewitt on a vertical edge should be zero"""
i, j = np.mgrid[-5:6, -5:6]
image = (j >= 0).astype(float)
result = F.hprewitt(image)
eps = .000001
assert (np.all(np.abs(result) < eps))
class TestVPrewitt():
def test_00_00_zeros(self):
"""Vertical prewitt on an array of all zeros"""
result = F.vprewitt(np.zeros((10, 10)), np.ones((10, 10), bool))
assert (np.all(result == 0))
def test_vprewitt_zeros():
"""Vertical prewitt on an array of all zeros"""
result = F.vprewitt(np.zeros((10, 10)), np.ones((10, 10), bool))
assert (np.all(result == 0))
def test_00_01_mask(self):
"""Vertical prewitt on a masked array should be zero"""
np.random.seed(0)
result = F.vprewitt(np.random.uniform(size=(10, 10)),
np.zeros((10, 10), bool))
assert (np.all(result == 0))
def test_vprewitt_mask():
"""Vertical prewitt on a masked array should be zero"""
np.random.seed(0)
result = F.vprewitt(np.random.uniform(size=(10, 10)),
np.zeros((10, 10), bool))
assert (np.all(result == 0))
def test_01_01_vertical(self):
"""Vertical prewitt on an edge should be a vertical line"""
i, j = np.mgrid[-5:6, -5:6]
image = (j >= 0).astype(float)
result = F.vprewitt(image)
# Fudge the eroded points
j[np.abs(i) == 5] = 10000
assert (np.all(result[j == 0] == 1))
eps = .000001
assert (np.all(np.abs(result[np.abs(j) > 1]) < eps))
def test_vprewitt_vertical():
"""Vertical prewitt on an edge should be a vertical line"""
i, j = np.mgrid[-5:6, -5:6]
image = (j >= 0).astype(float)
result = F.vprewitt(image)
# Fudge the eroded points
j[np.abs(i) == 5] = 10000
assert (np.all(result[j == 0] == 1))
eps = .000001
assert (np.all(np.abs(result[np.abs(j) > 1]) < eps))
def test_01_02_horizontal(self):
"""Vertical prewitt on a horizontal edge should be zero"""
i, j = np.mgrid[-5:6, -5:6]
image = (i >= 0).astype(float)
result = F.vprewitt(image)
eps = .000001
assert (np.all(np.abs(result) < eps))
def test_vprewitt_horizontal():
"""Vertical prewitt on a horizontal edge should be zero"""
i, j = np.mgrid[-5:6, -5:6]
image = (i >= 0).astype(float)
result = F.vprewitt(image)
eps = .000001
assert (np.all(np.abs(result) < eps))
def test_horizontal_mask_line():
"""Horizontal edge filters mask pixels surrounding input mask."""
vgrad, _ = np.mgrid[:1:11j, :1:11j] # vertical gradient with spacing 0.1
vgrad[5, :] = 1 # bad horizontal line
mask = np.ones_like(vgrad)
mask[5, :] = 0 # mask bad line
expected = np.zeros_like(vgrad)
expected[1:-1, 1:-1] = 0.2 # constant gradient for most of image,
expected[4:7, 1:-1] = 0 # but line and neighbors masked
for grad_func in (F.hprewitt, F.hsobel):
result = grad_func(vgrad, mask)
yield assert_close, result, expected
def test_vertical_mask_line():
"""Vertical edge filters mask pixels surrounding input mask."""
_, hgrad = np.mgrid[:1:11j, :1:11j] # horizontal gradient with spacing 0.1
hgrad[:, 5] = 1 # bad vertical line
mask = np.ones_like(hgrad)
mask[:, 5] = 0 # mask bad line
expected = np.zeros_like(hgrad)
expected[1:-1, 1:-1] = 0.2 # constant gradient for most of image,
expected[1:-1, 4:7] = 0 # but line and neighbors masked
for grad_func in (F.vprewitt, F.vsobel):
result = grad_func(hgrad, mask)
yield assert_close, result, expected
if __name__ == "__main__":
run_module_suite()
from numpy import testing
testing.run_module_suite()