#python #sorting #opencv #ocr
#python #сортировка #opencv #ocr
Вопрос:
Я пытаюсь отсортировать поля, которые являются результатом OCR engine. Ограничивающие рамки из движка являются случайными и не имеют какой-либо конкретной сортировки. Я хотел бы отсортировать поля слева направо, сверху вниз. Какие поля в одной строке (строке) должны быть отсортированы слева направо, а затем они должны перейти в нижнюю строку (строку) и отсортировать ее слева направо и так далее.
У меня есть все 4 точки каждого прямоугольника (прямоугольника)
Вот несколько примеров изображений.
Комментарии:
1. Предложение: 1) Вычислите координаты центра каждого поля; 2) Используйте кластеризацию по вертикальной координате, чтобы сгруппировать поля в строке; 3) Отсортируйте строки и отсортируйте поля в каждой строке.
2. Можете ли вы разделить перекрывающиеся блоки? Имеет ли значение сверху вниз верх или центр поля?
3. @Stef Да, я думал о том же подходе, но
clustering on vertical co-ordinate
это то, что я изо всех сил пытаюсь сделать. Как кластеризировать по оси y? Есть несколько подходов, которые я попробовал, которые берут самый верхний элемент и получают все точки, которые находятся ниже центра выбранной точки, и рассматривают эти точки в одной строке. Удалите выбранные поля и повторите. Но, похоже, это работает не очень хорошо.4. @SyedAbdul Вы пробовали использовать алгоритмы кластеризации из scikit-learn? Если вы знаете количество строк, то k-means должно быть идеальным для этого. Если вы не знаете количество строк, то иерархическая кластеризация должна работать довольно хорошо. См. scikit-learn.org/stable/modules/clustering.html
5. @SyedAbdul В частности, если вы знаете, что расстояние по вертикали между двумя разными блоками, которые не находятся на одной строке, всегда составляет хотя бы некоторую константу (скажем, 0,5 см), тогда любой из алгоритмов кластеризации из scikit-learn, который принимает
distance_threshold
параметр, может работать довольно хорошо.
Ответ №1:
Вы можете использовать функцию сортировки, которая является встроенной функцией Python, как показано ниже (этот код предполагает, что прямоугольники хранятся в виде кортежей (x, y, width, height) или (x1, y1, x2, y2):
from operator import itemgetter, attrgetter
rects = [(8, 10, 10, 10), (0, 5, 10, 10), (0, 0, 10, 10), (1, 10, 10, 10)]
rects = sorted(rects, key=itemgetter(1,0))
Результат:
[(0, 0, 10, 10), (0, 5, 10, 10), (1, 10, 10, 10), (8, 10, 10, 10)]
Комментарии:
1. Поля расположены не по прямой линии, как в примере, который вы взяли, все оси y расположены по прямой линии, а поля имеют одинаковый размер. Но в моем случае все ящики разного размера, а центральная точка ящиков также не находится на прямой линии. Таким образом, функция прямой сортировки не будет работать.
Ответ №2:
Вот предложение:
- Сортировка по вертикальной координате центра поля;
- Два соседних блока в отсортированном списке считаются «на одной строке», если их вертикальное перекрытие превышает 50% высоты первого блока.
Мы будем использовать python sorted
и more_itertools.split_when
для сортировки, а затем группировать в соответствии с этими критериями.
from more_itertools import split_when
def get_y_center(b):
up, down= b[0], b[2]
return (up down) / 2
def not_vertically_overlapping(b1, b2):
up1, down1 = b1[0], b1[2]
up2, down2 = b2[0], b2[2]
return down1 < up2 or (down1 - up2) < (up2 - up1)
def groupbyrow(boxes):
sorted_boxes = sorted(boxes, key=get_y_center)
return list(split_when(sorted_boxes, not_vertically_overlapping))
Тестирование:
import random
import matplotlib.pyplot as plt
import matplotlib.colors as mcolors
# GENERATE RANDOM BOXES
centers = [(random.gauss(i, 5),random.gauss(j,0.25)) for i in range(0,40,10) for j in range(0,40,2)]
random.shuffle(centers)
boxes = [(y-(h:=random.gauss(1,0.25)),x-(w:=random.gauss(5,2)),y h,x w) for x,y in centers]
# GROUP BOXES BY ROW
rows = groupbyrow(boxes)
# DRAW BOXES WITH ONE COLOUR PER ROW
def draw_box(box, colour):
u,l,d,r = box
xs = [l, r, r, l, l]
ys = [u, u, d, d, u]
plt.plot(xs, ys, colour)
colours = list(mcolors.CSS4_COLORS.keys())
for i,row in enumerate(rows):
for box in row:
draw_box(box, colours[i])
plt.gca().set_aspect('equal')
plt.show()
Ответ №3:
Не могли бы вы кратко изложить правила, которые вы рассматриваете для сортировки полей? Вы хотите сортировать поля в зигзагообразном порядке сканирования? В любом случае, если вы хотите применить определенное правило, вы можете передать свою настроенную функцию компаратора в отсортированную функцию.