From 9a339027d5f19643089d560a76ae909157c9795b Mon Sep 17 00:00:00 2001 From: Sujoy Kumar Goswami Date: Thu, 23 Apr 2020 21:08:31 +0530 Subject: [PATCH 1/8] Update edge.py added edge detector based on Sujoy's algorithm --- mahotas/edge.py | 59 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/mahotas/edge.py b/mahotas/edge.py index e954407a..e5539850 100644 --- a/mahotas/edge.py +++ b/mahotas/edge.py @@ -21,6 +21,7 @@ __all__ = [ 'sobel', + 'sujoy', 'dog', ] @@ -69,6 +70,64 @@ def sobel(img, just_filter=False): thresh = 2*np.sqrt(filtered.mean()) return mh.regmax(filtered) * (np.sqrt(filtered) > thresh) +def sujoy(img, kernel_nhood=0, just_filter=False): + + ''' + edges = sujoy(img, kernel_nhood=0, just_filter=False) + + Compute edges using Sujoy's algorithm + + `edges` is a binary image of edges computed according to Sujoy's algorithm. + https://www.ijert.org/research/a-better-first-derivative-approach-for-edge-detection-IJERTV2IS110616.pdf + + Parameters + ---------- + img : Any 2D-ndarray + kernel_nhood : 0(default) or 1 + if 0, kernel is based on 4-neighborhood + else , kernel is based on 8-neighborhood + just_filter : boolean, optional + If true, then return the result of filtering the image with the Sujoy's + filters, but do not threshold (default is False). + + Returns + ------- + edges : ndarray + Binary image of edges, unless `just_filter`, in which case it will be + an array of floating point values. + ''' + # This is similar to 'sobel" implementation above + img = np.array(img, dtype=np.float) + if img.ndim != 2: + raise ValueError('mahotas.sujoy: Only available for 2-dimensional images') + img -= img.min() + ptp = img.ptp() + if ptp == 0: + return img + img /= ptp + + if kernel_nhood: + krnl_h = np.array([[0,-1,-1,-1,0],[0,-1,-1,-1,0],[0,0,0,0,0],[0,1,1,1,0],[0,1,1,1,0]])/12. + krnl_v = np.array([[0,0,0,0,0],[-1,-1,0,1,1],[-1,-1,0,1,1],[-1,-1,0,1,1],[0,0,0,0,0]])/12. + else: + krnl_h = np.array([[0,0,-1,0,0],[0,-1,-1,-1,0],[0,0,0,0,0],[0,1,1,1,0],[0,0,1,0,0]])/8. + krnl_v = np.array([[0,0,0,0,0],[0,-1,0,1,0],[-1,-1,0,1,1],[0,-1,0,1,0],[0,0,0,0,0]])/8. + + grad_h = convolve(img, krnl_h, mode='nearest') + grad_v = convolve(img, krnl_v, mode='nearest') + + grad_h **=2 + grad_v **=2 + + grad = grad_h + grad += grad_v + if just_filter: + return grad + t = 2*np.sqrt(grad.mean()) + + return mh.regmax(grad)*(np.sqrt(grad)>t) + + def dog(img, sigma1 = 2, multiplier = 1.001, just_filter = False): ''' edges = dog(img, sigma1 = 2, thresh= None, just_filter = False) From 8f6d638de3d46a6740e9f9f1ebf7ef8a3a3c5e63 Mon Sep 17 00:00:00 2001 From: Sujoy Kumar Goswami Date: Fri, 12 Jun 2020 15:53:42 +0530 Subject: [PATCH 2/8] Update edge.py corrected space/tab errors... all indentation are now tabs... --- mahotas/edge.py | 98 ++++++++++++++++++++++++------------------------- 1 file changed, 49 insertions(+), 49 deletions(-) diff --git a/mahotas/edge.py b/mahotas/edge.py index e5539850..dd547409 100644 --- a/mahotas/edge.py +++ b/mahotas/edge.py @@ -20,10 +20,10 @@ [ 1, 2, 1]])/8. __all__ = [ - 'sobel', - 'sujoy', - 'dog', - ] + 'sobel', + 'sujoy', + 'dog', + ] def sobel(img, just_filter=False): ''' @@ -76,56 +76,56 @@ def sujoy(img, kernel_nhood=0, just_filter=False): edges = sujoy(img, kernel_nhood=0, just_filter=False) Compute edges using Sujoy's algorithm - - `edges` is a binary image of edges computed according to Sujoy's algorithm. - https://www.ijert.org/research/a-better-first-derivative-approach-for-edge-detection-IJERTV2IS110616.pdf - Parameters - ---------- - img : Any 2D-ndarray + `edges` is a binary image of edges computed according to Sujoy's algorithm. + Paper link: https://www.ijert.org/research/a-better-first-derivative-approach-for-edge-detection-IJERTV2IS110616.pdf + + Parameters + ---------- + img : Any 2D-ndarray kernel_nhood : 0(default) or 1 if 0, kernel is based on 4-neighborhood else , kernel is based on 8-neighborhood - just_filter : boolean, optional - If true, then return the result of filtering the image with the Sujoy's - filters, but do not threshold (default is False). - - Returns - ------- - edges : ndarray - Binary image of edges, unless `just_filter`, in which case it will be - an array of floating point values. - ''' + just_filter : boolean, optional + If true, then return the result of filtering the image with the Sujoy's + filters, but do not threshold (default is False). + + Returns + ------- + edges : ndarray + Binary image of edges, unless `just_filter`, in which case it will be + an array of floating point values. + ''' # This is similar to 'sobel" implementation above - img = np.array(img, dtype=np.float) - if img.ndim != 2: - raise ValueError('mahotas.sujoy: Only available for 2-dimensional images') - img -= img.min() - ptp = img.ptp() - if ptp == 0: - return img - img /= ptp - - if kernel_nhood: - krnl_h = np.array([[0,-1,-1,-1,0],[0,-1,-1,-1,0],[0,0,0,0,0],[0,1,1,1,0],[0,1,1,1,0]])/12. - krnl_v = np.array([[0,0,0,0,0],[-1,-1,0,1,1],[-1,-1,0,1,1],[-1,-1,0,1,1],[0,0,0,0,0]])/12. - else: - krnl_h = np.array([[0,0,-1,0,0],[0,-1,-1,-1,0],[0,0,0,0,0],[0,1,1,1,0],[0,0,1,0,0]])/8. - krnl_v = np.array([[0,0,0,0,0],[0,-1,0,1,0],[-1,-1,0,1,1],[0,-1,0,1,0],[0,0,0,0,0]])/8. - - grad_h = convolve(img, krnl_h, mode='nearest') - grad_v = convolve(img, krnl_v, mode='nearest') - - grad_h **=2 - grad_v **=2 - - grad = grad_h - grad += grad_v - if just_filter: - return grad - t = 2*np.sqrt(grad.mean()) - - return mh.regmax(grad)*(np.sqrt(grad)>t) + img = np.array(img, dtype=np.float) + if img.ndim != 2: + raise ValueError('mahotas.sujoy: Only available for 2-dimensional images') + img -= img.min() + ptp = img.ptp() + if ptp == 0: + return img + img /= ptp + + if kernel_nhood: + krnl_h = np.array([[0,-1,-1,-1,0],[0,-1,-1,-1,0],[0,0,0,0,0],[0,1,1,1,0],[0,1,1,1,0]])/12. + krnl_v = np.array([[0,0,0,0,0],[-1,-1,0,1,1],[-1,-1,0,1,1],[-1,-1,0,1,1],[0,0,0,0,0]])/12. + else: + krnl_h = np.array([[0,0,-1,0,0],[0,-1,-1,-1,0],[0,0,0,0,0],[0,1,1,1,0],[0,0,1,0,0]])/8. + krnl_v = np.array([[0,0,0,0,0],[0,-1,0,1,0],[-1,-1,0,1,1],[0,-1,0,1,0],[0,0,0,0,0]])/8. + + grad_h = convolve(img, krnl_h, mode='nearest') + grad_v = convolve(img, krnl_v, mode='nearest') + + grad_h **=2 + grad_v **=2 + + grad = grad_h + grad += grad_v + if just_filter: + return grad + t = 2*np.sqrt(grad.mean()) + + return mh.regmax(grad)*(np.sqrt(grad)>t) def dog(img, sigma1 = 2, multiplier = 1.001, just_filter = False): From 0017fc16b9aa51a082e251cc3cabe3f732785c2c Mon Sep 17 00:00:00 2001 From: Sujoy Kumar Goswami Date: Sat, 13 Jun 2020 00:30:10 +0530 Subject: [PATCH 3/8] Update edge.py update threshold 't' --- mahotas/edge.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mahotas/edge.py b/mahotas/edge.py index dd547409..4d943c28 100644 --- a/mahotas/edge.py +++ b/mahotas/edge.py @@ -123,7 +123,7 @@ def sujoy(img, kernel_nhood=0, just_filter=False): grad += grad_v if just_filter: return grad - t = 2*np.sqrt(grad.mean()) + t = np.sqrt(grad.mean()) return mh.regmax(grad)*(np.sqrt(grad)>t) From c7af17f55158de52ef2ce946fc37c367a05e03a0 Mon Sep 17 00:00:00 2001 From: Sujoy Kumar Goswami Date: Sat, 13 Jun 2020 12:26:36 +0530 Subject: [PATCH 4/8] Update test_edge.py test_edge.py updated with sujoy-edge-detector test cases --- mahotas/tests/test_edge.py | 45 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/mahotas/tests/test_edge.py b/mahotas/tests/test_edge.py index 26ce49d0..659dd4d9 100644 --- a/mahotas/tests/test_edge.py +++ b/mahotas/tests/test_edge.py @@ -1,4 +1,5 @@ from mahotas.edge import sobel +from mahotas.edge import sujoy from nose.tools import raises import mahotas as mh import numpy as np @@ -50,6 +51,50 @@ def test_3d_error(): f = np.zeros((32,16,3)) sobel(f) +def test_sujoy_shape(): + A = np.arange(100*100) + A = (A % 15) + A = A.reshape((100,100)) + assert sujoy(A).shape == A.shape + assert sujoy(A, just_filter=True).shape == A.shape + +def test_sujoy_zeros(): + A = np.zeros((15,100)) + assert sujoy(A).shape == A.shape + assert sujoy(A).sum() == 0 + +def test_sujoy(): + I = np.array([ + [0,0,0,0,0,0], + [0,0,0,1,0,0], + [0,0,0,1,0,0], + [0,0,0,1,0,0], + [0,0,0,1,0,0], + [0,0,0,0,0,0]]) + E = sujoy(I) + r,c = I.shape + for y,x in zip(*np.where(E)): + N = [I[y,x]] + if y > 0: N.append(I[y-1,x]) + if x > 0: N.append(I[y,x-1]) + if y < (r-1): N.append(I[y+1,x]) + if x < (c-1): N.append(I[y,x+1]) + assert len(set(N)) > 1 + +def test_zero_images1(): + assert np.isnan(sujoy(np.zeros((16,16)))).sum() == 0 + assert sujoy(np.zeros((16,16)), just_filter=True).sum() == 0 + +def test_sujoy_pure(): + f = np.random.random((64, 128)) + f2 = f.copy() + _ = mh.sujoy(f) + assert np.all(f == f2) + +@raises(ValueError) +def test_3d_error1(): + f = np.zeros((32,16,3)) + sujoy(f) def test_dog(): im = mh.demos.load('lena') From d9283fef876a7e3d6c8764e3c48d98590828cb93 Mon Sep 17 00:00:00 2001 From: Sujoy Kumar Goswami Date: Sat, 13 Jun 2020 21:55:55 +0530 Subject: [PATCH 5/8] all indentation are now spaces --- mahotas/tests/test_edge.py | 64 +++++++++++++++++++------------------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/mahotas/tests/test_edge.py b/mahotas/tests/test_edge.py index 659dd4d9..f9275753 100644 --- a/mahotas/tests/test_edge.py +++ b/mahotas/tests/test_edge.py @@ -52,49 +52,49 @@ def test_3d_error(): sobel(f) def test_sujoy_shape(): - A = np.arange(100*100) - A = (A % 15) - A = A.reshape((100,100)) - assert sujoy(A).shape == A.shape - assert sujoy(A, just_filter=True).shape == A.shape + A = np.arange(100*100) + A = (A % 15) + A = A.reshape((100,100)) + assert sujoy(A).shape == A.shape + assert sujoy(A, just_filter=True).shape == A.shape def test_sujoy_zeros(): - A = np.zeros((15,100)) - assert sujoy(A).shape == A.shape - assert sujoy(A).sum() == 0 + A = np.zeros((15,100)) + assert sujoy(A).shape == A.shape + assert sujoy(A).sum() == 0 def test_sujoy(): - I = np.array([ - [0,0,0,0,0,0], - [0,0,0,1,0,0], - [0,0,0,1,0,0], - [0,0,0,1,0,0], - [0,0,0,1,0,0], - [0,0,0,0,0,0]]) - E = sujoy(I) - r,c = I.shape - for y,x in zip(*np.where(E)): - N = [I[y,x]] - if y > 0: N.append(I[y-1,x]) - if x > 0: N.append(I[y,x-1]) - if y < (r-1): N.append(I[y+1,x]) - if x < (c-1): N.append(I[y,x+1]) - assert len(set(N)) > 1 + I = np.array([ + [0,0,0,0,0,0], + [0,0,0,1,0,0], + [0,0,0,1,0,0], + [0,0,0,1,0,0], + [0,0,0,1,0,0], + [0,0,0,0,0,0]]) + E = sujoy(I) + r,c = I.shape + for y,x in zip(*np.where(E)): + N = [I[y,x]] + if y > 0: N.append(I[y-1,x]) + if x > 0: N.append(I[y,x-1]) + if y < (r-1): N.append(I[y+1,x]) + if x < (c-1): N.append(I[y,x+1]) + assert len(set(N)) > 1 def test_zero_images1(): - assert np.isnan(sujoy(np.zeros((16,16)))).sum() == 0 - assert sujoy(np.zeros((16,16)), just_filter=True).sum() == 0 + assert np.isnan(sujoy(np.zeros((16,16)))).sum() == 0 + assert sujoy(np.zeros((16,16)), just_filter=True).sum() == 0 def test_sujoy_pure(): - f = np.random.random((64, 128)) - f2 = f.copy() - _ = mh.sujoy(f) - assert np.all(f == f2) + f = np.random.random((64, 128)) + f2 = f.copy() + _ = mh.sujoy(f) + assert np.all(f == f2) @raises(ValueError) def test_3d_error1(): - f = np.zeros((32,16,3)) - sujoy(f) + f = np.zeros((32,16,3)) + sujoy(f) def test_dog(): im = mh.demos.load('lena') From 4f6e9e4838ec2773869e3387b24e20ba940b1ca7 Mon Sep 17 00:00:00 2001 From: Sujoy Kumar Goswami Date: Sat, 13 Jun 2020 23:31:14 +0530 Subject: [PATCH 6/8] Update test_edge.py updated test cases with parameter "kernel_nhood=1" --- mahotas/tests/test_edge.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/mahotas/tests/test_edge.py b/mahotas/tests/test_edge.py index f9275753..042004b9 100644 --- a/mahotas/tests/test_edge.py +++ b/mahotas/tests/test_edge.py @@ -56,12 +56,14 @@ def test_sujoy_shape(): A = (A % 15) A = A.reshape((100,100)) assert sujoy(A).shape == A.shape + assert sujoy(A, kernel_nhood=1).shape == A.shape assert sujoy(A, just_filter=True).shape == A.shape def test_sujoy_zeros(): A = np.zeros((15,100)) assert sujoy(A).shape == A.shape assert sujoy(A).sum() == 0 + assert sujoy(A, kernel_nhood=1).sum() == 0 def test_sujoy(): I = np.array([ @@ -80,9 +82,19 @@ def test_sujoy(): if y < (r-1): N.append(I[y+1,x]) if x < (c-1): N.append(I[y,x+1]) assert len(set(N)) > 1 + E = sujoy(I, kernel_nhood=1) + r,c = I.shape + for y,x in zip(*np.where(E)): + N = [I[y,x]] + if y > 0: N.append(I[y-1,x]) + if x > 0: N.append(I[y,x-1]) + if y < (r-1): N.append(I[y+1,x]) + if x < (c-1): N.append(I[y,x+1]) + assert len(set(N)) > 1 def test_zero_images1(): assert np.isnan(sujoy(np.zeros((16,16)))).sum() == 0 + assert np.isnan(sujoy(np.zeros((16,16)), kernel_nhood=1)).sum() == 0 assert sujoy(np.zeros((16,16)), just_filter=True).sum() == 0 def test_sujoy_pure(): From 185c7946e992594cca4ab1f18936278aef95a513 Mon Sep 17 00:00:00 2001 From: Sujoy Kumar Goswami Date: Sun, 14 Jun 2020 14:13:05 +0530 Subject: [PATCH 7/8] Update test_edge.py line 103 from"mh.sujoy" to "sujoy" --- mahotas/tests/test_edge.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mahotas/tests/test_edge.py b/mahotas/tests/test_edge.py index 042004b9..03195c31 100644 --- a/mahotas/tests/test_edge.py +++ b/mahotas/tests/test_edge.py @@ -96,11 +96,12 @@ def test_zero_images1(): assert np.isnan(sujoy(np.zeros((16,16)))).sum() == 0 assert np.isnan(sujoy(np.zeros((16,16)), kernel_nhood=1)).sum() == 0 assert sujoy(np.zeros((16,16)), just_filter=True).sum() == 0 + assert sujoy(np.zeros((16,16)), just_filter=True, kernel_nhood=1).sum() == 0 def test_sujoy_pure(): f = np.random.random((64, 128)) f2 = f.copy() - _ = mh.sujoy(f) + _ = sujoy(f) assert np.all(f == f2) @raises(ValueError) From 57e5245fa479d8ce6ecfb2dece69079e1c5b60fe Mon Sep 17 00:00:00 2001 From: Sujoy Kumar Goswami Date: Sun, 20 Sep 2020 19:27:36 +0530 Subject: [PATCH 8/8] Update test_edge.py update test_3d_error1() function --- mahotas/tests/test_edge.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/mahotas/tests/test_edge.py b/mahotas/tests/test_edge.py index 29464be2..59970a21 100644 --- a/mahotas/tests/test_edge.py +++ b/mahotas/tests/test_edge.py @@ -1,6 +1,5 @@ from mahotas.edge import sobel from mahotas.edge import sujoy -from nose.tools import raises import pytest import mahotas as mh import numpy as np @@ -105,10 +104,10 @@ def test_sujoy_pure(): _ = sujoy(f) assert np.all(f == f2) -@raises(ValueError) def test_3d_error1(): f = np.zeros((32,16,3)) - sujoy(f) + with pytest.raises(ValueError): + sujoy(f) def test_dog(): im = mh.demos.load('lena')