diff --git a/.github/workflows/codespell.yml b/.github/workflows/codespell.yml index 3479b0218a69..02de2b6e89f2 100644 --- a/.github/workflows/codespell.yml +++ b/.github/workflows/codespell.yml @@ -11,7 +11,7 @@ jobs: - run: pip install codespell flake8 - run: | SKIP="./.*,./other/dictionary.txt,./other/words,./project_euler/problem_22/p022_names.txt" - codespell -L ans,fo,hist,iff,secant,tim --skip=$SKIP --quiet-level=2 + codespell --ignore-words-list=ans,fo,hist,iff,secant,som,tim --skip=$SKIP --quiet-level=2 - name: Codespell comment if: ${{ failure() }} uses: plettich/python_codespell_action@master diff --git a/DIRECTORY.md b/DIRECTORY.md index f08c31794b1e..3227711c7853 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -646,6 +646,8 @@ * [Sol1](https://github.com/TheAlgorithms/Python/blob/master/project_euler/problem_67/sol1.py) * Problem 76 * [Sol1](https://github.com/TheAlgorithms/Python/blob/master/project_euler/problem_76/sol1.py) + * Problem 97 + * [Sol1](https://github.com/TheAlgorithms/Python/blob/master/project_euler/problem_97/sol1.py) * Problem 99 * [Sol1](https://github.com/TheAlgorithms/Python/blob/master/project_euler/problem_99/sol1.py) diff --git a/bit_border.py b/bit_border.py new file mode 100644 index 000000000000..295b4d825c12 --- /dev/null +++ b/bit_border.py @@ -0,0 +1,122 @@ +import cv2 +import numpy as np + +from digital_image_processing.filters.convolve import img_convolve +from digital_image_processing.filters.sobel_filter import sobel_filter + +PI = 180 + + +def gen_gaussian_kernel(k_size, sigma): + center = k_size // 2 + x, y = np.mgrid[0 - center : k_size - center, 0 - center : k_size - center] + g = ( + 1 + / (2 * np.pi * sigma) + * np.exp(-(np.square(x) + np.square(y)) / (2 * np.square(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)) + + """ + 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. + """ + 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 + or 15 * PI / 8 <= direction <= 2 * PI + or 7 * PI / 8 <= direction <= 9 * PI / 8 + ): + 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] + + 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] + 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 + ): + 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 + ): + 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] + + """ + 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. + """ + if dst[row, col] >= threshold_high: + dst[row, col] = strong + elif dst[row, col] <= threshold_low: + dst[row, col] = 0 + else: + dst[row, col] = weak + + """ + 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): + if dst[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], + ): + dst[row, col] = strong + else: + dst[row, col] = 0 + + return dst + + +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) + cv2.waitKey(0)