Skip to content

Commit 433b804

Browse files
authored
Added morphological operations, fixes: TheAlgorithms#5197 (TheAlgorithms#5199)
* Added morphological operations, fixes: TheAlgorithms#5197 * Added dilation tests and type hints * Added erosion tests and type hints * fixes: TheAlgorithms#5197 * fixes: TheAlgorithms#5197 * Update erosion_operation.py * made suggested changes in dilation * made suggested changes in erosion * made suggested changes in dilation * removed extra spaces in the tests * removed extra spaces in the tests
1 parent 3738588 commit 433b804

File tree

2 files changed

+148
-0
lines changed

2 files changed

+148
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
import numpy as np
2+
from PIL import Image
3+
4+
5+
def rgb2gray(rgb: np.array) -> np.array:
6+
"""
7+
Return gray image from rgb image
8+
>>> rgb2gray(np.array([[[127, 255, 0]]]))
9+
array([[187.6453]])
10+
>>> rgb2gray(np.array([[[0, 0, 0]]]))
11+
array([[0.]])
12+
>>> rgb2gray(np.array([[[2, 4, 1]]]))
13+
array([[3.0598]])
14+
>>> rgb2gray(np.array([[[26, 255, 14], [5, 147, 20], [1, 200, 0]]]))
15+
array([[159.0524, 90.0635, 117.6989]])
16+
"""
17+
r, g, b = rgb[:, :, 0], rgb[:, :, 1], rgb[:, :, 2]
18+
return 0.2989 * r + 0.5870 * g + 0.1140 * b
19+
20+
21+
def gray2binary(gray: np.array) -> np.array:
22+
"""
23+
Return binary image from gray image
24+
>>> gray2binary(np.array([[127, 255, 0]]))
25+
array([[False, True, False]])
26+
>>> gray2binary(np.array([[0]]))
27+
array([[False]])
28+
>>> gray2binary(np.array([[26.2409, 4.9315, 1.4729]]))
29+
array([[False, False, False]])
30+
>>> gray2binary(np.array([[26, 255, 14], [5, 147, 20], [1, 200, 0]]))
31+
array([[False, True, False],
32+
[False, True, False],
33+
[False, True, False]])
34+
"""
35+
return (127 < gray) & (gray <= 255)
36+
37+
38+
def dilation(image: np.array, kernel: np.array) -> np.array:
39+
"""
40+
Return dilated image
41+
>>> dilation(np.array([[True, False, True]]), np.array([[0, 1, 0]]))
42+
array([[False, False, False]])
43+
>>> dilation(np.array([[False, False, True]]), np.array([[1, 0, 1]]))
44+
array([[False, False, False]])
45+
"""
46+
output = np.zeros_like(image)
47+
image_padded = np.zeros(
48+
(image.shape[0] + kernel.shape[0] - 1, image.shape[1] + kernel.shape[1] - 1)
49+
)
50+
51+
# Copy image to padded image
52+
image_padded[kernel.shape[0] - 2 : -1 :, kernel.shape[1] - 2 : -1 :] = image
53+
54+
# Iterate over image & apply kernel
55+
for x in range(image.shape[1]):
56+
for y in range(image.shape[0]):
57+
summation = (
58+
kernel * image_padded[y : y + kernel.shape[0], x : x + kernel.shape[1]]
59+
).sum()
60+
output[y, x] = int(summation > 0)
61+
return output
62+
63+
64+
# kernel to be applied
65+
structuring_element = np.array([[0, 1, 0], [1, 1, 1], [0, 1, 0]])
66+
67+
68+
if __name__ == "__main__":
69+
# read original image
70+
image = np.array(Image.open(r"..\image_data\lena.jpg"))
71+
output = dilation(gray2binary(rgb2gray(image)), structuring_element)
72+
# Save the output image
73+
pil_img = Image.fromarray(output).convert("RGB")
74+
pil_img.save("result_dilation.png")
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
import numpy as np
2+
from PIL import Image
3+
4+
5+
def rgb2gray(rgb: np.array) -> np.array:
6+
"""
7+
Return gray image from rgb image
8+
>>> rgb2gray(np.array([[[127, 255, 0]]]))
9+
array([[187.6453]])
10+
>>> rgb2gray(np.array([[[0, 0, 0]]]))
11+
array([[0.]])
12+
>>> rgb2gray(np.array([[[2, 4, 1]]]))
13+
array([[3.0598]])
14+
>>> rgb2gray(np.array([[[26, 255, 14], [5, 147, 20], [1, 200, 0]]]))
15+
array([[159.0524, 90.0635, 117.6989]])
16+
"""
17+
r, g, b = rgb[:, :, 0], rgb[:, :, 1], rgb[:, :, 2]
18+
return 0.2989 * r + 0.5870 * g + 0.1140 * b
19+
20+
21+
def gray2binary(gray: np.array) -> np.array:
22+
"""
23+
Return binary image from gray image
24+
>>> gray2binary(np.array([[127, 255, 0]]))
25+
array([[False, True, False]])
26+
>>> gray2binary(np.array([[0]]))
27+
array([[False]])
28+
>>> gray2binary(np.array([[26.2409, 4.9315, 1.4729]]))
29+
array([[False, False, False]])
30+
>>> gray2binary(np.array([[26, 255, 14], [5, 147, 20], [1, 200, 0]]))
31+
array([[False, True, False],
32+
[False, True, False],
33+
[False, True, False]])
34+
"""
35+
return (127 < gray) & (gray <= 255)
36+
37+
38+
def erosion(image: np.array, kernel: np.array) -> np.array:
39+
"""
40+
Return eroded image
41+
>>> erosion(np.array([[True, True, False]]), np.array([[0, 1, 0]]))
42+
array([[False, False, False]])
43+
>>> erosion(np.array([[True, False, False]]), np.array([[1, 1, 0]]))
44+
array([[False, False, False]])
45+
"""
46+
output = np.zeros_like(image)
47+
image_padded = np.zeros(
48+
(image.shape[0] + kernel.shape[0] - 1, image.shape[1] + kernel.shape[1] - 1)
49+
)
50+
51+
# Copy image to padded image
52+
image_padded[kernel.shape[0] - 2 : -1 :, kernel.shape[1] - 2 : -1 :] = image
53+
54+
# Iterate over image & apply kernel
55+
for x in range(image.shape[1]):
56+
for y in range(image.shape[0]):
57+
summation = (
58+
kernel * image_padded[y : y + kernel.shape[0], x : x + kernel.shape[1]]
59+
).sum()
60+
output[y, x] = int(summation == 5)
61+
return output
62+
63+
64+
# kernel to be applied
65+
structuring_element = np.array([[0, 1, 0], [1, 1, 1], [0, 1, 0]])
66+
67+
if __name__ == "__main__":
68+
# read original image
69+
image = np.array(Image.open(r"..\image_data\lena.jpg"))
70+
# Apply erosion operation to a binary image
71+
output = erosion(gray2binary(rgb2gray(image)), structuring_element)
72+
# Save the output image
73+
pil_img = Image.fromarray(output).convert("RGB")
74+
pil_img.save("result_erosion.png")

0 commit comments

Comments
 (0)