Как мне найти центр контуров, но не геометрический, а визуальный?

В качестве домашнего проекта и обучения OpenCV я пишу читалку этого 2d-кода, но есть проблема при поиске визуального центра контуров, как вы можете видеть на фото, сейчас точки находятся в местах геометрического центра, и это не проблема для небольших участков, но для больших участков точки выходят за пределы контура, и это не подходит для моих целей. (Я ищу центральные точки, чтобы затем находить только те контуры, центральные точки которых образуют круг). Может быть, у кого-то есть идеи, как это сделать, или даже мысли о том, как читать код в целом) Сейчас код выглядит следующим образом

import cv2
import numpy as np

# Загрузка изображения
img = cv2.imread("t5.png")

# Преобразование изображения в оттенки серого
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# Размытие изображения для уменьшения шума
blur = cv2.GaussianBlur(gray, (5, 5), 0)

# Пороговое значение изображения для binarization
thresh = cv2.threshold(blur, 0, 255, cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU)[1]

# Нахождение контуров
contours, _ = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

# Вычисление площади всех контуров
areas = [cv2.contourArea(contour) for contour in contours]

# Нахождение контура с минимальной площадью
min_area = float("inf")
min_contour = None
for contour in contours:
    area = cv2.contourArea(contour)
    if area < min_area:
        min_area = area
        min_contour = contour

# Перебор всех контуров
for contour in contours:
    # Аппроксимируем контур
    epsilon = 0.01 * cv2.arcLength(contour, True)
    approx = cv2.approxPolyDP(contour, epsilon, True)

    # Преобразуем контур в полигон
    contour_poly = cv2.convexHull(contour)

    # Находим середины всех отрезков
    segments = []
    for i in range(len(contour_poly) - 1):
        x1, y1 = contour_poly[i][0]
        x2, y2 = contour_poly[i + 1][0]
        mid_x = (x1 + x2) // 2
        mid_y = (y1 + y2) // 2
        segments.append((mid_x, mid_y))

    # Находим точку по центру контура
    center_x = sum(point[0] for point in segments) // len(segments)
    center_y = sum(point[1] for point in segments) // len(segments)

    # Рисуем точку по центру контура
    cv2.circle(img, (center_x, center_y), 5, (0, 255, 0), -1)  # Зеленая точка размером 5

# Отображение изображения
cv2.imshow("Contours with Divided Parts", img)
cv2.waitKey(0)
cv2.destroyAllWindows()

2d код с точками в центрах контуров


Ответы (2 шт):

Автор решения: eri

Можно попробовать через центр массы.

Циклом с мелким шагом, например по пикселю

count=0
centerx,centery=(0,0)
for x in range(minx,maxx):
    for y in range(miny, maxy):
        if in_shape(x, y):
            count+=1
            centerx+=x
            century+=y
centerx/=count
century/=count

Но у изогнутых фигур центр может не лежать на фигуре. Смотреться будет достовернее чем радиус описанной.

Решать декодироние этого кода нужно через полярные координаты, а не через визуальный центр

→ Ссылка
Автор решения: Alex Alex

Тут надо использовать математическую морфологию, а именно операцию shrink.

В Matlab/Octave это делается одной командой im2=bwmorph(im, "shrink", Inf); Т.е. сначала вам нужно найти остов (скелет) объектов, а затем в цикле используя look up table делать подстановку по правилам для shrink.

→ Ссылка