From 7414096c0947664c8f9a47627c577278961e93a1 Mon Sep 17 00:00:00 2001 From: MaximSmolskiy Date: Thu, 3 Nov 2022 23:03:11 +0300 Subject: [PATCH 1/7] Reduce the complexity of digital_image_processing/edge_detection/canny.py --- .../edge_detection/canny.py | 65 ++++++++++++------- 1 file changed, 43 insertions(+), 22 deletions(-) diff --git a/digital_image_processing/edge_detection/canny.py b/digital_image_processing/edge_detection/canny.py index a830355267c4..d1b2359d3f38 100644 --- a/digital_image_processing/edge_detection/canny.py +++ b/digital_image_processing/edge_detection/canny.py @@ -18,28 +18,20 @@ def gen_gaussian_kernel(k_size, sigma): return g -def canny(image, threshold_low=15, threshold_high=30, weak=128, strong=255): - 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)) - +def suppress_non_maximum(image_row, image_col, gradient_direction, sobel_grad): """ 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 preserved. Otherwise, the value will be suppressed. """ + dst = np.zeros((image_row, image_col)) + for row in range(1, image_row - 1): for col in range(1, image_col - 1): direction = gradient_direction[row, col] if ( - 0 <= direction < 22.5 + 0 <= direction < PI / 8 or 15 * PI / 8 <= direction <= 2 * PI or 7 * PI / 8 <= direction <= 9 * PI / 8 ): @@ -48,8 +40,9 @@ def canny(image, threshold_low=15, threshold_high=30, weak=128, strong=255): if sobel_grad[row, col] >= w and sobel_grad[row, col] >= e: dst[row, col] = sobel_grad[row, col] - elif (PI / 8 <= direction < 3 * PI / 8) or ( - 9 * PI / 8 <= direction < 11 * PI / 8 + elif ( + PI / 8 <= direction < 3 * PI / 8 + or 9 * PI / 8 <= direction < 11 * PI / 8 ): sw = sobel_grad[row + 1, col - 1] ne = sobel_grad[row - 1, col + 1] @@ -72,14 +65,22 @@ def canny(image, threshold_low=15, threshold_high=30, weak=128, strong=255): if sobel_grad[row, col] >= nw and sobel_grad[row, col] >= se: dst[row, col] = sobel_grad[row, col] - """ - 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 - edge pixel’s gradient value is smaller than the high threshold value and - larger than the low threshold value, it is marked as a weak edge pixel. If - an edge pixel's value is smaller than the low threshold value, it will be - suppressed. - """ + return dst + + +def detect_high_low_threshold( + image_row, image_col, dst, threshold_low, threshold_high, weak, strong +): + """ + 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 + edge pixel’s gradient value is smaller than the high threshold value and + larger than the low threshold value, it is marked as a weak edge pixel. If + an edge pixel's value is smaller than the low threshold value, it will be + suppressed. + """ + for row in range(1, image_row - 1): + for col in range(1, image_col - 1): if dst[row, col] >= threshold_high: dst[row, col] = strong elif dst[row, col] <= threshold_low: @@ -87,6 +88,8 @@ def canny(image, threshold_low=15, threshold_high=30, weak=128, strong=255): else: dst[row, col] = weak + +def track_edge(image_row, image_col, dst, weak, strong): """ 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 @@ -110,6 +113,24 @@ def canny(image, threshold_low=15, threshold_high=30, weak=128, strong=255): else: dst[row, col] = 0 + +def canny(image, threshold_low=15, threshold_high=30, weak=128, strong=255): + 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 = suppress_non_maximum(image_row, image_col, gradient_direction, sobel_grad) + + detect_high_low_threshold( + image_row, image_col, dst, threshold_low, threshold_high, weak, strong + ) + + track_edge(image_row, image_col, dst, weak, strong) + return dst From 1193f67ea4f9ae600d2f32b8b00fc287ad266c95 Mon Sep 17 00:00:00 2001 From: MaximSmolskiy Date: Thu, 3 Nov 2022 23:05:21 +0300 Subject: [PATCH 2/7] Fix --- digital_image_processing/edge_detection/canny.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/digital_image_processing/edge_detection/canny.py b/digital_image_processing/edge_detection/canny.py index d1b2359d3f38..2564574bc400 100644 --- a/digital_image_processing/edge_detection/canny.py +++ b/digital_image_processing/edge_detection/canny.py @@ -49,16 +49,18 @@ def suppress_non_maximum(image_row, image_col, gradient_direction, sobel_grad): if sobel_grad[row, col] >= sw and sobel_grad[row, col] >= ne: dst[row, col] = sobel_grad[row, col] - elif (3 * PI / 8 <= direction < 5 * PI / 8) or ( - 11 * PI / 8 <= direction < 13 * PI / 8 + elif ( + 3 * PI / 8 <= direction < 5 * PI / 8 + or 11 * PI / 8 <= direction < 13 * PI / 8 ): n = sobel_grad[row - 1, col] s = sobel_grad[row + 1, col] if sobel_grad[row, col] >= n and sobel_grad[row, col] >= s: dst[row, col] = sobel_grad[row, col] - elif (5 * PI / 8 <= direction < 7 * PI / 8) or ( - 13 * PI / 8 <= direction < 15 * PI / 8 + elif ( + 5 * PI / 8 <= direction < 7 * PI / 8 + or 13 * PI / 8 <= direction < 15 * PI / 8 ): nw = sobel_grad[row - 1, col - 1] se = sobel_grad[row + 1, col + 1] From 6b60eaacc3e381524f128e016c3a35c14670b2ff Mon Sep 17 00:00:00 2001 From: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Date: Fri, 10 Mar 2023 20:07:21 +0000 Subject: [PATCH 3/7] updating DIRECTORY.md --- DIRECTORY.md | 1 + 1 file changed, 1 insertion(+) diff --git a/DIRECTORY.md b/DIRECTORY.md index f25b0c6ff4e3..b2daaaa9c47d 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -334,6 +334,7 @@ ## Electronics * [Builtin Voltage](electronics/builtin_voltage.py) * [Carrier Concentration](electronics/carrier_concentration.py) + * [Circular Convolution](electronics/circular_convolution.py) * [Coulombs Law](electronics/coulombs_law.py) * [Electric Conductivity](electronics/electric_conductivity.py) * [Electric Power](electronics/electric_power.py) From 581ca58884785cf1dc1a900d9e943e04be6e56b5 Mon Sep 17 00:00:00 2001 From: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Date: Tue, 14 Mar 2023 07:03:39 +0000 Subject: [PATCH 4/7] updating DIRECTORY.md --- DIRECTORY.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/DIRECTORY.md b/DIRECTORY.md index e1ce44eedce1..e932a1e0522a 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -196,11 +196,14 @@ * [Disjoint Set](data_structures/disjoint_set/disjoint_set.py) * Hashing * [Double Hash](data_structures/hashing/double_hash.py) + * [Hash Map](data_structures/hashing/hash_map.py) * [Hash Table](data_structures/hashing/hash_table.py) * [Hash Table With Linked List](data_structures/hashing/hash_table_with_linked_list.py) * Number Theory * [Prime Numbers](data_structures/hashing/number_theory/prime_numbers.py) * [Quadratic Probing](data_structures/hashing/quadratic_probing.py) + * Tests + * [Test Hash Map](data_structures/hashing/tests/test_hash_map.py) * Heap * [Binomial Heap](data_structures/heap/binomial_heap.py) * [Heap](data_structures/heap/heap.py) From 7c5f091ae31a953867789735659748936845730b Mon Sep 17 00:00:00 2001 From: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Date: Sat, 1 Apr 2023 11:01:36 +0000 Subject: [PATCH 5/7] updating DIRECTORY.md --- DIRECTORY.md | 1 + 1 file changed, 1 insertion(+) diff --git a/DIRECTORY.md b/DIRECTORY.md index 1a641d8ecb59..33c816fc4add 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -317,6 +317,7 @@ * [Longest Sub Array](dynamic_programming/longest_sub_array.py) * [Matrix Chain Order](dynamic_programming/matrix_chain_order.py) * [Max Non Adjacent Sum](dynamic_programming/max_non_adjacent_sum.py) + * [Max Product Subarray](dynamic_programming/max_product_subarray.py) * [Max Sub Array](dynamic_programming/max_sub_array.py) * [Max Sum Contiguous Subsequence](dynamic_programming/max_sum_contiguous_subsequence.py) * [Min Distance Up Bottom](dynamic_programming/min_distance_up_bottom.py) From a806c0d14d0bdb82566b5d643c1cf098abdea574 Mon Sep 17 00:00:00 2001 From: MaximSmolskiy Date: Sat, 1 Apr 2023 18:57:42 +0300 Subject: [PATCH 6/7] Fix review issues --- .../edge_detection/canny.py | 30 +++++++++---------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/digital_image_processing/edge_detection/canny.py b/digital_image_processing/edge_detection/canny.py index 2564574bc400..b92566272ca0 100644 --- a/digital_image_processing/edge_detection/canny.py +++ b/digital_image_processing/edge_detection/canny.py @@ -18,16 +18,16 @@ def gen_gaussian_kernel(k_size, sigma): return g -def suppress_non_maximum(image_row, image_col, gradient_direction, sobel_grad): +def suppress_non_maximum(image_shape, gradient_direction, sobel_grad): """ 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 preserved. Otherwise, the value will be suppressed. """ - dst = np.zeros((image_row, image_col)) + dst = np.zeros(image_shape) - for row in range(1, image_row - 1): - 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] if ( @@ -71,7 +71,7 @@ def suppress_non_maximum(image_row, image_col, gradient_direction, sobel_grad): def detect_high_low_threshold( - image_row, image_col, dst, threshold_low, threshold_high, weak, strong + image_shape, dst, threshold_low, threshold_high, weak, strong ): """ High-Low threshold detection. If an edge pixel’s gradient value is higher @@ -81,8 +81,8 @@ def detect_high_low_threshold( an edge pixel's value is smaller than the low threshold value, it will be suppressed. """ - for row in range(1, image_row - 1): - 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): if dst[row, col] >= threshold_high: dst[row, col] = strong elif dst[row, col] <= threshold_low: @@ -91,15 +91,15 @@ def detect_high_low_threshold( dst[row, col] = weak -def track_edge(image_row, image_col, dst, weak, strong): +def track_edge(image_shape, dst, weak, strong): """ 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 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. """ - for row in range(1, image_row): - for col in range(1, image_col): + for row in range(1, image_shape[0]): + for col in range(1, image_shape[1]): if dst[row, col] == weak: if 255 in ( dst[row, col + 1], @@ -117,21 +117,19 @@ def track_edge(image_row, image_col, dst, weak, strong): def canny(image, threshold_low=15, threshold_high=30, weak=128, strong=255): - 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 + gradient_direction = PI + np.rad2deg(sobel_theta) - dst = suppress_non_maximum(image_row, image_col, gradient_direction, sobel_grad) + dst = suppress_non_maximum(image.shape, gradient_direction, sobel_grad) detect_high_low_threshold( - image_row, image_col, dst, threshold_low, threshold_high, weak, strong + image.shape, dst, threshold_low, threshold_high, weak, strong ) - track_edge(image_row, image_col, dst, weak, strong) + track_edge(image.shape, dst, weak, strong) return dst From 8884fcbce843f67f738edaa7b5471b5404517d8f Mon Sep 17 00:00:00 2001 From: MaximSmolskiy Date: Sat, 1 Apr 2023 19:17:40 +0300 Subject: [PATCH 7/7] Rename dst to destination --- .../edge_detection/canny.py | 60 +++++++++---------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/digital_image_processing/edge_detection/canny.py b/digital_image_processing/edge_detection/canny.py index b92566272ca0..f8cbeedb3874 100644 --- a/digital_image_processing/edge_detection/canny.py +++ b/digital_image_processing/edge_detection/canny.py @@ -24,7 +24,7 @@ def suppress_non_maximum(image_shape, gradient_direction, sobel_grad): compared to the other pixels in the mask with the same direction, the value will be preserved. Otherwise, the value will be suppressed. """ - dst = np.zeros(image_shape) + destination = np.zeros(image_shape) for row in range(1, image_shape[0] - 1): for col in range(1, image_shape[1] - 1): @@ -38,7 +38,7 @@ def suppress_non_maximum(image_shape, gradient_direction, sobel_grad): w = sobel_grad[row, col - 1] e = sobel_grad[row, col + 1] 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 @@ -47,7 +47,7 @@ def suppress_non_maximum(image_shape, gradient_direction, sobel_grad): sw = 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: - dst[row, col] = sobel_grad[row, col] + destination[row, col] = sobel_grad[row, col] elif ( 3 * PI / 8 <= direction < 5 * PI / 8 @@ -56,7 +56,7 @@ def suppress_non_maximum(image_shape, gradient_direction, sobel_grad): n = sobel_grad[row - 1, col] s = sobel_grad[row + 1, col] 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 @@ -65,13 +65,13 @@ def suppress_non_maximum(image_shape, gradient_direction, sobel_grad): nw = 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: - dst[row, col] = sobel_grad[row, col] + destination[row, col] = sobel_grad[row, col] - return dst + return destination def detect_high_low_threshold( - image_shape, dst, threshold_low, threshold_high, weak, strong + image_shape, destination, threshold_low, threshold_high, weak, strong ): """ High-Low threshold detection. If an edge pixel’s gradient value is higher @@ -83,15 +83,15 @@ def detect_high_low_threshold( """ for row in range(1, image_shape[0] - 1): for col in range(1, image_shape[1] - 1): - if dst[row, col] >= threshold_high: - dst[row, col] = strong - elif dst[row, col] <= threshold_low: - dst[row, col] = 0 + if destination[row, col] >= threshold_high: + destination[row, col] = strong + elif destination[row, col] <= threshold_low: + destination[row, col] = 0 else: - dst[row, col] = weak + destination[row, col] = weak -def track_edge(image_shape, dst, weak, strong): +def track_edge(image_shape, destination, weak, strong): """ 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 @@ -100,20 +100,20 @@ def track_edge(image_shape, dst, weak, strong): """ for row in range(1, image_shape[0]): for col in range(1, image_shape[1]): - if dst[row, col] == weak: + if destination[row, col] == weak: if 255 in ( - dst[row, col + 1], - dst[row, col - 1], - dst[row - 1, col], - dst[row + 1, col], - dst[row - 1, col - 1], - dst[row + 1, col - 1], - dst[row - 1, col + 1], - dst[row + 1, col + 1], + destination[row, col + 1], + destination[row, col - 1], + destination[row - 1, col], + destination[row + 1, col], + destination[row - 1, col - 1], + destination[row + 1, col - 1], + destination[row - 1, col + 1], + destination[row + 1, col + 1], ): - dst[row, col] = strong + destination[row, col] = strong else: - dst[row, col] = 0 + destination[row, col] = 0 def canny(image, threshold_low=15, threshold_high=30, weak=128, strong=255): @@ -123,21 +123,21 @@ def canny(image, threshold_low=15, threshold_high=30, weak=128, strong=255): sobel_grad, sobel_theta = sobel_filter(gaussian_out) gradient_direction = PI + np.rad2deg(sobel_theta) - dst = suppress_non_maximum(image.shape, gradient_direction, sobel_grad) + destination = suppress_non_maximum(image.shape, gradient_direction, sobel_grad) detect_high_low_threshold( - image.shape, dst, threshold_low, threshold_high, weak, strong + image.shape, destination, threshold_low, threshold_high, weak, strong ) - track_edge(image.shape, dst, weak, strong) + track_edge(image.shape, destination, weak, strong) - return dst + return destination if __name__ == "__main__": # read original image in gray mode lena = cv2.imread(r"../image_data/lena.jpg", 0) # canny edge detection - canny_dst = canny(lena) - cv2.imshow("canny", canny_dst) + canny_destination = canny(lena) + cv2.imshow("canny", canny_destination) cv2.waitKey(0)