Как заказать порядок контуров cv2 в сетке, которая может иметь некоторые искажения? - PullRequest
0 голосов
/ 06 марта 2020

Я написал файл python для обнаружения контуров в сетке cv2 и упорядочения их, спускаясь по столбцам слева направо. (См. Изображение grid1 ниже).

Это довольно тривиально для сортировки. Я потянул верхний левый угол контура и отсортировал его по x, затем по его y координате, а затем использовал отсортированные углы для сортировки. контурный список. Это прекрасно работает, когда сетка совершенно прямая.

Grid1

Теперь, если сетка имеет искажения, это больше не работает, глядя на grid2, мы можем видеть, что x координата верхнего левого угла куска, обозначенного 2, меньше, чем x координата верхнего угла куска, обозначенного 1 (как показано зеленой линией).

Отсюда когда я применяю свою функцию сортировки, которая работала для grid1, она сортирует по x, а затем y, и, следовательно, фрагмент, помеченный 2, неверно упорядочивается как первый элемент отсортированных контуров, а не второй, каким он должен быть.

Grid2

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

У кого-нибудь есть предложения?

1 Ответ

0 голосов
/ 06 марта 2020

Вы можете основывать свой выбор заказа, основываясь как на расстоянии угла для начала координат, так и на относительной позиции угла.

  • Поиск контуров и иерархии.
    Сохранение контуров без дочерних элементов (на основе иерархии).
  • Поиск углов ограничивающих прямоугольников.

Анализ углы основаны на следующих условиях (или найдите более простые условия):

  • Верхний левый контур - это тот, у которого минимальное расстояние от верхнего левого угла.
  • Нижний правый контур - это контур с максимальным расстоянием от верхнего левого угла.
  • Другие два контура могут быть разделены максимальным x и максимальным y (после исключения верхнего левого и нижнего правого).

Решение ниже, др aws ограничивающие прямоугольники в цветах для тестирования:

  1. Красный
  2. Зеленый
  3. Синий
  4. Желтый

Вот пример рабочего кода (пожалуйста, прочитайте комментарии):

import numpy as np
import cv2

# Read input image as Grayscale
img = cv2.imread('img.png', cv2.IMREAD_GRAYSCALE)

# Convert img to uint8 binary image with values 0 and 255
# All black pixels goes to 0, and other pixels goes to 255
ret, thresh_gray = cv2.threshold(img, 1, 255, cv2.THRESH_BINARY)

# Find contours in thresh_gray.
cnts, hiers = cv2.findContours(thresh_gray, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)[-2:]  # [-2:] indexing takes return value before last (due to OpenCV compatibility issues).

corners = [] # List of corners
dist = np.array([]) # Array of distance from axes origin

# Iterate cnts and hiers, find bounding rectangles, and add corners to a list
for c, h in zip(cnts, hiers[0]):
    # If contours has no child
    if h[2] == -1:
        # Get bounding rectangle
        x, y, w, h = cv2.boundingRect(c)

        # Append corner to list of corners - format is corners[i] holds a tuple: ((x0, y0), (x1, y1))
        p0 = (x, y)
        p1 = (x+w, y+h)
        corners.append((p0, p1))

        # Distance of corners from origin
        d = np.array([np.linalg.norm(p0), np.linalg.norm(p1)])

        if dist.size == 0:
            dist = d
        else:
            dist = np.vstack((dist, d))


top_left = np.argmin(dist[:,0]) # Index of top left corner (assume minimum distance from origin)
bottom_right = np.argmax(dist[:,1]) # Index of top bottom right corner (assume maximum distance from origin)

tmp_corners = np.array(corners)
tmp_corners[top_left, :, :] = np.array(((0,0), (0,0))) #Ignore top_left corners
tmp_corners[bottom_right, :, :] = np.array(((0,0), (0,0))) #Ignore bottom_right corners
bottom_left = np.argmax(tmp_corners[:,1,1]) #Maximum y is bottom left
tmp_corners[bottom_left, :, :] = np.array(((0,0), (0,0))) #Ignore bottom_left corners
top_right = np.argmax(tmp_corners[:,1,0])  #Maximum x is top right

# Convert Grayscale to BGR (just for testing - for drawing rectangles in green color).
out = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)

# Draw rectangles (for testing)
# 1. Red
# 2. Green
# 3. Blue
# 4. Yellow
cv2.rectangle(out, corners[top_left][0], corners[top_left][1], (0, 0, 255), thickness = 2)
cv2.rectangle(out, corners[bottom_left][0], corners[bottom_left][1], (0, 255, 0), thickness = 2)
cv2.rectangle(out, corners[top_right][0], corners[top_right][1], (255, 0, 0), thickness = 2)
cv2.rectangle(out, corners[bottom_right][0], corners[bottom_right][1], (0, 255, 255), thickness = 2)

cv2.imwrite('out.png', out)  #Save out to file (for testing).


# Show result (for testing).
cv2.imshow('thresh_gray', thresh_gray)
cv2.imshow('out', out)
cv2.waitKey(0)
cv2.destroyAllWindows()

Результат:
enter image description here

...