From 8a35b3f950c9f1cc0faf43bd420ade98e5682a99 Mon Sep 17 00:00:00 2001 From: Pieter Holtzhausen Date: Mon, 18 Apr 2011 00:17:48 +0200 Subject: [PATCH] Added CellProfiler sobel and prewitt functions. --- scikits/image/filter/__init__.py | 1 + scikits/image/filter/edges.py | 130 +++++++++++++++ scikits/image/filter/tests/test_edges.py | 201 +++++++++++++++++++++++ scikits/image/version.py | 3 +- 4 files changed, 334 insertions(+), 1 deletion(-) create mode 100644 scikits/image/filter/edges.py create mode 100644 scikits/image/filter/tests/test_edges.py diff --git a/scikits/image/filter/__init__.py b/scikits/image/filter/__init__.py index 29247baf..ef33468d 100644 --- a/scikits/image/filter/__init__.py +++ b/scikits/image/filter/__init__.py @@ -1,3 +1,4 @@ from lpi_filter import * from ctmf import median_filter from canny import canny +from edges import sobel, hsobel, vsobel, hprewitt, vprewitt, prewitt diff --git a/scikits/image/filter/edges.py b/scikits/image/filter/edges.py new file mode 100644 index 00000000..dae11cf9 --- /dev/null +++ b/scikits/image/filter/edges.py @@ -0,0 +1,130 @@ +'''edges.py - Sobel edge filter + +Originally part of CellProfiler, code licensed under both GPL and BSD licenses. +Website: http://www.cellprofiler.org +Copyright (c) 2003-2009 Massachusetts Institute of Technology +Copyright (c) 2009-2011 Broad Institute +All rights reserved. +Original author: Lee Kamentsky + +''' +import numpy as np +from scipy.ndimage import convolve, binary_erosion, generate_binary_structure + +def sobel(image, mask=None): + '''Calculate the absolute magnitude Sobel to find the edges + + image - image to process + mask - mask of relevant points + + Take the square root of the sum of the squares of the horizontal and + vertical Sobels to get a magnitude that's somewhat insensitive to + direction. + + Note that scipy's Sobel returns a directional Sobel which isn't + useful for edge detection in its raw form. + ''' + return np.sqrt(hsobel(image,mask)**2 + vsobel(image,mask)**2) + +def hsobel(image, mask=None): + '''Find the horizontal edges of an image using the Sobel transform + + image - image to process + mask - mask of relevant points + + We use the following kernel and return the absolute value of the + result at each point: + 1 2 1 + 0 0 0 + -1 -2 -1 + ''' + if mask == 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 + +def vsobel(image, mask=None): + '''Find the vertical edges of an image using the Sobel transform + + image - image to process + mask - mask of relevant points + + We use the following kernel and return the absolute value of the + result at each point: + 1 0 -1 + 2 0 -2 + 1 0 -1 + ''' + if mask == 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 + +def prewitt(image, mask=None): + '''Find the edge magnitude using the Prewitt transform + + image - image to process + mask - mask of relevant points + + Return the square root of the sum of squares of the horizontal + and vertical Prewitt transforms. + ''' + return np.sqrt(hprewitt(image,mask)**2 + vprewitt(image,mask)**2) + +def hprewitt(image, mask=None): + '''Find the horizontal edges of an image using the Prewitt transform + + image - image to process + mask - mask of relevant points + + We use the following kernel and return the absolute value of the + result at each point: + 1 1 1 + 0 0 0 + -1 -1 -1 + ''' + if mask == 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 + +def vprewitt(image, mask=None): + '''Find the vertical edges of an image using the Prewitt transform + + image - image to process + mask - mask of relevant points + + We use the following kernel and return the absolute value of the + result at each point: + 1 0 -1 + 1 0 -1 + 1 0 -1 + ''' + if mask == 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 diff --git a/scikits/image/filter/tests/test_edges.py b/scikits/image/filter/tests/test_edges.py new file mode 100644 index 00000000..015d0a7e --- /dev/null +++ b/scikits/image/filter/tests/test_edges.py @@ -0,0 +1,201 @@ +from numpy.testing import * +import numpy as np +from scipy.ndimage import binary_dilation, binary_erosion +import scikits.image.filter as F + +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_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_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_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)) + +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_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_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_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)) + +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_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_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_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)) + +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_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_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_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)) + +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_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_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_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)) + +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_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_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_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)) + + +if __name__ == "__main__": + run_module_suite() diff --git a/scikits/image/version.py b/scikits/image/version.py index 4fadcd3a..f30761c7 100644 --- a/scikits/image/version.py +++ b/scikits/image/version.py @@ -1 +1,2 @@ -version='unbuilt-dev' +# THIS FILE IS GENERATED FROM THE SCIKITS.IMAGE SETUP.PY +version='0.3dev'