Bezdepbonusu7Программирование: статьи и ответы

Вопрос

Как заказать контуры cv2 в сетке, которые могут иметь искажения?

Автор вопроса: user9940344Ответов: 1

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

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

Сетка1а>

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

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

Сетка2а>

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

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

  • Пожалуйста, добавьте код! Я не совсем понимаю, что ты хотел сделать. Saeed Masoomi 06.03.2020
  • Не могли бы вы объяснить, какую часть вы не понимаете, я попытаюсь объяснить? user9940344 06.03.2020

pythonopencvcomputer-vision

Ответы

Ответ 1 · Rotem

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

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

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

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

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

  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()

Результат:

Перевод вопроса и ответов сообщества Stack Overflow, лицензия CC BY-SA. Оригинал на Stack Overflow.

Похожие материалы