[Python] What is the best way to find the exact edges and shapes in an image with python?

Discussão em 'Python' iniciado por Stack, Março 24, 2025.

  1. Stack

    Stack Membro Participativo

    For some time now I've been trying to create edge detection on images (mainly png/jpg graphics) so that they fully reproduce the edges that humans see.

    I tried the following workflow:

    1. Loading a png/jpg image
    2. Blurring with GaussianBlur
    3. Using Canny to detect edges (optimal thresholds are 25/80 - I tested all of them)
    4. cv2.findContours to find contours

    But I have a big problem with the fact that the contours are not "closed", I would like them all to be connected. And not all shapes are correctly mapped.

    Are there any solutions that will allow me to precisely capture shapes - such as in the sample images below?

    I thought about using color clustering using kmeans, but at lower "resolutions" there will be too much noise and with a small number of clusters I won't catch low contrasts. For example, in this image, clusters could work well for "large shapes" such as in examples 2 and 3, but not for edges - example 4 where we have broken edges because the edges during clustering do not become one color but several with a lot of noise.

    Would anyone have an idea how to achieve contouring of all the shapes we see as well as the outlines?

    Image. [​IMG] 1. [​IMG] 2. [​IMG] 3. [​IMG] 4. [​IMG]

    import cv2
    import numpy as np
    import matplotlib.pyplot as plt
    from matplotlib.widgets import Slider

    img = cv2.imread('image.png', cv2.IMREAD_GRAYSCALE)
    if img is None:
    print("Error")
    exit()

    def kmeans_clustering_blure(image, k):
    image_blur = cv2.GaussianBlur(image, (3,3), 0)
    pixels = image_blur.reshape(-1, 3).astype(np.float32)
    criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_COUNT, 100, 0.2)
    _, labels, centers = cv2.kmeans(pixels, k, None, criteria, 10, cv2.KMEANS_USE_INITIAL_LABELS)
    centers = np.uint8(centers)
    segmented_image = centers[labels.flatten()]
    return segmented_image.reshape(image.shape), labels, centers

    blur = cv2.GaussianBlur(img, (3, 3), 0)

    init_low = 25
    init_high = 80

    edges_init = cv2.Canny(blur, init_low, init_high)
    white_canvas_init = np.ones_like(edges_init, dtype=np.uint8) * 255
    white_canvas_init[edges_init > 0] = 0

    imgBin = cv2.bitwise_not(edges_init)
    kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE,(1,1))
    dilated = cv2.dilate(edges_init, kernel)

    contours, hierarchy = cv2.findContours(dilated.copy(), cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)


    contour_canvas = np.ones_like(img, dtype=np.uint8) * 255

    cv2.drawContours(contour_canvas, contours, -1, 0, 1)

    plt.figure(figsize=(20, 20))

    plt.subplot(1, 2, 1)
    plt.imshow(edges_init, cmap='gray')
    plt.title('1')
    plt.axis('off')

    plt.subplot(1, 2, 2)
    plt.imshow(contour_canvas, cmap='gray')
    plt.title('2')
    plt.axis('off')

    plt.show()


    I will add right away that I am not a Python specialist and I am using it for the first time for this project.

    Continue reading...

Compartilhe esta Página