mirror of
https://github.com/TheAlgorithms/Python.git
synced 2024-11-27 15:01:08 +00:00
Reduce the complexity of digital_image_processing/edge detection/canny.py (#8167)
* Reduce the complexity of digital_image_processing/edge_detection/canny.py * Fix * updating DIRECTORY.md * updating DIRECTORY.md * updating DIRECTORY.md * Fix review issues * Rename dst to destination --------- Co-authored-by: github-actions <${GITHUB_ACTOR}@users.noreply.github.com>
This commit is contained in:
parent
63710883c8
commit
59cae167e0
|
@ -18,60 +18,61 @@ def gen_gaussian_kernel(k_size, sigma):
|
||||||
return g
|
return g
|
||||||
|
|
||||||
|
|
||||||
def canny(image, threshold_low=15, threshold_high=30, weak=128, strong=255):
|
def suppress_non_maximum(image_shape, gradient_direction, sobel_grad):
|
||||||
image_row, image_col = image.shape[0], image.shape[1]
|
|
||||||
# gaussian_filter
|
|
||||||
gaussian_out = img_convolve(image, gen_gaussian_kernel(9, sigma=1.4))
|
|
||||||
# get the gradient and degree by sobel_filter
|
|
||||||
sobel_grad, sobel_theta = sobel_filter(gaussian_out)
|
|
||||||
gradient_direction = np.rad2deg(sobel_theta)
|
|
||||||
gradient_direction += PI
|
|
||||||
|
|
||||||
dst = np.zeros((image_row, image_col))
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Non-maximum suppression. If the edge strength of the current pixel is the largest
|
Non-maximum suppression. If the edge strength of the current pixel is the largest
|
||||||
compared to the other pixels in the mask with the same direction, the value will be
|
compared to the other pixels in the mask with the same direction, the value will be
|
||||||
preserved. Otherwise, the value will be suppressed.
|
preserved. Otherwise, the value will be suppressed.
|
||||||
"""
|
"""
|
||||||
for row in range(1, image_row - 1):
|
destination = np.zeros(image_shape)
|
||||||
for col in range(1, image_col - 1):
|
|
||||||
|
for row in range(1, image_shape[0] - 1):
|
||||||
|
for col in range(1, image_shape[1] - 1):
|
||||||
direction = gradient_direction[row, col]
|
direction = gradient_direction[row, col]
|
||||||
|
|
||||||
if (
|
if (
|
||||||
0 <= direction < 22.5
|
0 <= direction < PI / 8
|
||||||
or 15 * PI / 8 <= direction <= 2 * PI
|
or 15 * PI / 8 <= direction <= 2 * PI
|
||||||
or 7 * PI / 8 <= direction <= 9 * PI / 8
|
or 7 * PI / 8 <= direction <= 9 * PI / 8
|
||||||
):
|
):
|
||||||
w = sobel_grad[row, col - 1]
|
w = sobel_grad[row, col - 1]
|
||||||
e = sobel_grad[row, col + 1]
|
e = sobel_grad[row, col + 1]
|
||||||
if sobel_grad[row, col] >= w and sobel_grad[row, col] >= e:
|
if sobel_grad[row, col] >= w and sobel_grad[row, col] >= e:
|
||||||
dst[row, col] = sobel_grad[row, col]
|
destination[row, col] = sobel_grad[row, col]
|
||||||
|
|
||||||
elif (PI / 8 <= direction < 3 * PI / 8) or (
|
elif (
|
||||||
9 * PI / 8 <= direction < 11 * PI / 8
|
PI / 8 <= direction < 3 * PI / 8
|
||||||
|
or 9 * PI / 8 <= direction < 11 * PI / 8
|
||||||
):
|
):
|
||||||
sw = sobel_grad[row + 1, col - 1]
|
sw = sobel_grad[row + 1, col - 1]
|
||||||
ne = sobel_grad[row - 1, col + 1]
|
ne = sobel_grad[row - 1, col + 1]
|
||||||
if sobel_grad[row, col] >= sw and sobel_grad[row, col] >= ne:
|
if sobel_grad[row, col] >= sw and sobel_grad[row, col] >= ne:
|
||||||
dst[row, col] = sobel_grad[row, col]
|
destination[row, col] = sobel_grad[row, col]
|
||||||
|
|
||||||
elif (3 * PI / 8 <= direction < 5 * PI / 8) or (
|
elif (
|
||||||
11 * PI / 8 <= direction < 13 * PI / 8
|
3 * PI / 8 <= direction < 5 * PI / 8
|
||||||
|
or 11 * PI / 8 <= direction < 13 * PI / 8
|
||||||
):
|
):
|
||||||
n = sobel_grad[row - 1, col]
|
n = sobel_grad[row - 1, col]
|
||||||
s = sobel_grad[row + 1, col]
|
s = sobel_grad[row + 1, col]
|
||||||
if sobel_grad[row, col] >= n and sobel_grad[row, col] >= s:
|
if sobel_grad[row, col] >= n and sobel_grad[row, col] >= s:
|
||||||
dst[row, col] = sobel_grad[row, col]
|
destination[row, col] = sobel_grad[row, col]
|
||||||
|
|
||||||
elif (5 * PI / 8 <= direction < 7 * PI / 8) or (
|
elif (
|
||||||
13 * PI / 8 <= direction < 15 * PI / 8
|
5 * PI / 8 <= direction < 7 * PI / 8
|
||||||
|
or 13 * PI / 8 <= direction < 15 * PI / 8
|
||||||
):
|
):
|
||||||
nw = sobel_grad[row - 1, col - 1]
|
nw = sobel_grad[row - 1, col - 1]
|
||||||
se = sobel_grad[row + 1, col + 1]
|
se = sobel_grad[row + 1, col + 1]
|
||||||
if sobel_grad[row, col] >= nw and sobel_grad[row, col] >= se:
|
if sobel_grad[row, col] >= nw and sobel_grad[row, col] >= se:
|
||||||
dst[row, col] = sobel_grad[row, col]
|
destination[row, col] = sobel_grad[row, col]
|
||||||
|
|
||||||
|
return destination
|
||||||
|
|
||||||
|
|
||||||
|
def detect_high_low_threshold(
|
||||||
|
image_shape, destination, threshold_low, threshold_high, weak, strong
|
||||||
|
):
|
||||||
"""
|
"""
|
||||||
High-Low threshold detection. If an edge pixel’s gradient value is higher
|
High-Low threshold detection. If an edge pixel’s gradient value is higher
|
||||||
than the high threshold value, it is marked as a strong edge pixel. If an
|
than the high threshold value, it is marked as a strong edge pixel. If an
|
||||||
|
@ -80,43 +81,63 @@ def canny(image, threshold_low=15, threshold_high=30, weak=128, strong=255):
|
||||||
an edge pixel's value is smaller than the low threshold value, it will be
|
an edge pixel's value is smaller than the low threshold value, it will be
|
||||||
suppressed.
|
suppressed.
|
||||||
"""
|
"""
|
||||||
if dst[row, col] >= threshold_high:
|
for row in range(1, image_shape[0] - 1):
|
||||||
dst[row, col] = strong
|
for col in range(1, image_shape[1] - 1):
|
||||||
elif dst[row, col] <= threshold_low:
|
if destination[row, col] >= threshold_high:
|
||||||
dst[row, col] = 0
|
destination[row, col] = strong
|
||||||
|
elif destination[row, col] <= threshold_low:
|
||||||
|
destination[row, col] = 0
|
||||||
else:
|
else:
|
||||||
dst[row, col] = weak
|
destination[row, col] = weak
|
||||||
|
|
||||||
|
|
||||||
|
def track_edge(image_shape, destination, weak, strong):
|
||||||
"""
|
"""
|
||||||
Edge tracking. Usually a weak edge pixel caused from true edges will be connected
|
Edge tracking. Usually a weak edge pixel caused from true edges will be connected
|
||||||
to a strong edge pixel while noise responses are unconnected. As long as there is
|
to a strong edge pixel while noise responses are unconnected. As long as there is
|
||||||
one strong edge pixel that is involved in its 8-connected neighborhood, that weak
|
one strong edge pixel that is involved in its 8-connected neighborhood, that weak
|
||||||
edge point can be identified as one that should be preserved.
|
edge point can be identified as one that should be preserved.
|
||||||
"""
|
"""
|
||||||
for row in range(1, image_row):
|
for row in range(1, image_shape[0]):
|
||||||
for col in range(1, image_col):
|
for col in range(1, image_shape[1]):
|
||||||
if dst[row, col] == weak:
|
if destination[row, col] == weak:
|
||||||
if 255 in (
|
if 255 in (
|
||||||
dst[row, col + 1],
|
destination[row, col + 1],
|
||||||
dst[row, col - 1],
|
destination[row, col - 1],
|
||||||
dst[row - 1, col],
|
destination[row - 1, col],
|
||||||
dst[row + 1, col],
|
destination[row + 1, col],
|
||||||
dst[row - 1, col - 1],
|
destination[row - 1, col - 1],
|
||||||
dst[row + 1, col - 1],
|
destination[row + 1, col - 1],
|
||||||
dst[row - 1, col + 1],
|
destination[row - 1, col + 1],
|
||||||
dst[row + 1, col + 1],
|
destination[row + 1, col + 1],
|
||||||
):
|
):
|
||||||
dst[row, col] = strong
|
destination[row, col] = strong
|
||||||
else:
|
else:
|
||||||
dst[row, col] = 0
|
destination[row, col] = 0
|
||||||
|
|
||||||
return dst
|
|
||||||
|
def canny(image, threshold_low=15, threshold_high=30, weak=128, strong=255):
|
||||||
|
# gaussian_filter
|
||||||
|
gaussian_out = img_convolve(image, gen_gaussian_kernel(9, sigma=1.4))
|
||||||
|
# get the gradient and degree by sobel_filter
|
||||||
|
sobel_grad, sobel_theta = sobel_filter(gaussian_out)
|
||||||
|
gradient_direction = PI + np.rad2deg(sobel_theta)
|
||||||
|
|
||||||
|
destination = suppress_non_maximum(image.shape, gradient_direction, sobel_grad)
|
||||||
|
|
||||||
|
detect_high_low_threshold(
|
||||||
|
image.shape, destination, threshold_low, threshold_high, weak, strong
|
||||||
|
)
|
||||||
|
|
||||||
|
track_edge(image.shape, destination, weak, strong)
|
||||||
|
|
||||||
|
return destination
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
# read original image in gray mode
|
# read original image in gray mode
|
||||||
lena = cv2.imread(r"../image_data/lena.jpg", 0)
|
lena = cv2.imread(r"../image_data/lena.jpg", 0)
|
||||||
# canny edge detection
|
# canny edge detection
|
||||||
canny_dst = canny(lena)
|
canny_destination = canny(lena)
|
||||||
cv2.imshow("canny", canny_dst)
|
cv2.imshow("canny", canny_destination)
|
||||||
cv2.waitKey(0)
|
cv2.waitKey(0)
|
||||||
|
|
Loading…
Reference in New Issue
Block a user