Как отсортировать контуры сетки с помощью OpenCV python?

Я пытаюсь отсортировать следующие квадраты внутри сетки шахматной доски.

Как отсортировать контуры сетки с помощью OpenCV python?

У меня есть правильные контуры внутри массива NumPy.

Вот фрагмент кода, как я получаю правильные контуры квадратов.

  # Find contours and find squares with contour area filtering + shape approximation
            cnts = cv2.findContours(invert, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
            r = 0
            cnts = cnts[0] if len(cnts) == 2 else cnts[1]
            sort_contours(cnts, "bottom-to-top")
            sort_contours(cnts, "left-to-right")
            valid_cnts = []
            v = []
            areas = []
            for c in cnts:
                area = cv2.contourArea(c)
                peri = cv2.arcLength(c, True)
                approx = cv2.approxPolyDP(c, 0.02 * peri, True)
                if len(approx) == 4 and area > 150 and area < 15000:
                    areas.append(area)
                    x, y, w, h = cv2.boundingRect(c)
                    s = img[y:y + h, x:x + w]
                    imgStr = "squares/square" + str(r) + ".png"
                    v.insert(r, [x, y, w, h])
                    cv2.imwrite(imgStr, s)
                    cv2.drawContours(original, [c], -1, (36, 255, 12), 2)
                    cv2.drawContours(mask, [c], -1, (255, 255, 255), -1)
                    valid_cnts.insert(r, c)
                    r = r + 1

Моя цель также состоит в том, чтобы отсортировать их слева направо, а затем снизу вверх. Так что я могу узнать каждую часть на них. Это моя текущая функция сортировки:

def sort_contours(cnts, method = "left-to-right"):
    # initialize the reverse flag and sort index
    reverse = False
    i = 0
    # handle if we need to sort in reverse
    if method == "right-to-left" or method == "bottom-to-top":
        reverse = True
    # handle if we are sorting against the y-coordinate rather than
    # the x-coordinate of the bounding box
    if method == "top-to-bottom" or method == "bottom-to-top":
        i = 1
    # construct the list of bounding boxes and sort them from top to
    # bottom
    boundingBoxes = [cv2.boundingRect(c) for c in cnts]
    (cnts, boundingBoxes) = zip(*sorted(zip(cnts, boundingBoxes),
                                        key=lambda b: b[1][i], reverse=reverse))
    # return the list of sorted contours and bounding boxes
    return (cnts, boundingBoxes)

К сожалению не работает, думаю дело в ракурсе камеры. Потому что, когда я обрезаю фотографию до 64 квадратов, они не появляются в том порядке, в котором я хочу. Если бы кто-нибудь мог подсказать мне, как правильно и точно их сортировать, было бы здорово!

Взгляните на это от Энн Дзен: stackoverflow.com/questions/66946804/…, а также stackoverflow.com/questions/39403183/….

Jeru Luke 02.05.2022 19:00
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
3
1
97
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Идея состоит в том, что после нахождения контуров на изображении с пороговым значением мы используем imutils.contours.sort_contours() для сортировки контуров из bottom-to-top. Далее мы берем каждую строку из 8 квадратов и сортируем эту строку от left-to-right. Вот визуализация сортировки:

import cv2
from imutils import contours

# Load image, grayscale, gaussian blur, Otsu's threshold
image = cv2.imread("1.jpg")
original = image.copy()
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
blur = cv2.GaussianBlur(gray, (5,5), 0)
thresh = cv2.threshold(blur, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)[1]

# Find all contour and sort from top-to-bottom or bottom-to-top
cnts, _ = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)[-2:]
(cnts, _) = contours.sort_contours(cnts, method = "bottom-to-top")

# Take each row of 8 and sort from left-to-right
checkerboard_row = []
row = []
for (i, c) in enumerate(cnts, 1):
    row.append(c)
    if i % 8 == 0:  
        (cnts, _) = contours.sort_contours(row, method = "left-to-right")
        checkerboard_row.append(cnts)
        row = []

# Draw text
number = 0
for row in checkerboard_row:
    for c in row:
        M = cv2.moments(c)
        x = int(M['m10']/M['m00'])
        y = int(M['m01']/M['m00'])
        cv2.putText(original, "{}".format(number + 1), (x - 20,y), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255,50,10), 2)
        number += 1

cv2.imshow('original', original)
cv2.waitKey()

Примечание: Вы также можете изменить направление сортировки, например right-to-left или top-to-bottom и т. д.

отличная визуализация

Jeru Luke 03.05.2022 10:19

Другие вопросы по теме