Объединение регионов в MSER для идентификации текстовых строк в OCR
Я использую MSER для определения текстовых областей в MSER. Я использую следующий код для извлечения регионов и сохранения их в виде изображения. В настоящее время каждый указанный регион сохраняется как отдельное изображение. Но я хочу объединить области, принадлежащие одной строке текста, как одно изображение.
import cv2
img = cv2.imread('newF.png')
mser = cv2.MSER_create()
img = cv2.resize(img, (img.shape[1]*2, img.shape[0]*2))
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
vis = img.copy()
regions = mser.detectRegions(gray)
hulls = [cv2.convexHull(p.reshape(-1, 1, 2)) for p in regions[0]]
cv2.polylines(vis, hulls, 1, (0,255,0))
Как я могу сшить изображения, которые принадлежат одной строке вместе? Я получаю логику, которая будет в основном основываться на некоторой эвристике для определения областей с близлежащими y-координатами.
Но как именно регионы можно объединить в OpenCV. Я пропускаю это, поскольку я новичок в openCV. Любая помощь будет оценена.
Прикрепление образца изображения
2 ответа
Может быть, даже что-то столь примитивное, как Дилат-эрод, может быть сделано в вашем случае? Например, если я использую erode
операция с последующим dilate
работа с исходным изображением, в основном в горизонтальном направлении, например:
img = cv2.erode(img, np.ones((1, 20)))
img = cv2.dilate(img, np.ones((1, 22)))
результат примерно такой:
Поэтому, если мы рисуем это поверх исходного изображения, оно становится:
Я не изменил размер исходного изображения, как вы (вероятно, чтобы обнаружить эти маленькие отдельные точки и прочее). Не идеально (я не знаю, как работает MSER), но с достаточной настройкой, возможно, вы могли бы даже использовать простое обнаружение подключенных компонентов с этим?
Если вы неравнодушны к использованию MSER, то, как вы упомянули, можно использовать эвристику для объединения областей с близлежащими y-координатами. Следующий подход может быть неэффективным, и я постараюсь оптимизировать его, но он может дать вам представление о том, как решить проблему.
Во-первых, давайте построим все bbox, определенные MSER:
coordinates, bboxes = mser.detectRegions(gray) for bbox in bboxes: x, y, w, h = bbox cv2.rectangle(img, (x, y), (x + w, y + h), (0, 255, 0), 2)
Теперь из bbox видно, что высоты меняются довольно сильно, даже в одной строке. Таким образом, для кластеризации ограничивающих bbox-ов в одну строку мы должны были бы найти интервал. Я не смог придумать что-то надежное, поэтому я выбрал половину медианы всех высот данных ящиков, что хорошо работает в данном случае.
bboxes_list = list() heights = list() for bbox in bboxes: x, y, w, h = bbox bboxes_list.append([x, y, x + w, y + h]) # Create list of bounding boxes, with each bbox containing the left-top and right-bottom coordinates heights.append(h) heights = sorted(heights) # Sort heights median_height = heights[len(heights) / 2] / 2 # Find half of the median height
Теперь, чтобы сгруппировать ограничивающие прямоугольники, учитывая определенный интервал для y-координат (Здесь, средняя высота), я изменяю фрагмент, который я когда-то нашел в stackru (я добавлю источник, как только найду его). Эта функция принимает список вместе с определенным интервалом в качестве входных данных и возвращает список групп, где каждая группа содержит ограничивающие прямоугольники, абсолютная разница в y-координатах которых меньше или равна интервалу. Обратите внимание, что итерируемый / список должен быть отсортирован по y-координате.
def grouper(iterable, interval=2): prev = None group = [] for item in iterable: if not prev or abs(item[1] - prev[1]) <= interval: group.append(item) else: yield group group = [item] prev = item if group: yield group
Таким образом, перед группировкой ограничивающих рамок их необходимо отсортировать по координате y. После группировки мы выполняем итерацию по каждой группе и определяем min x-координату, min y-координату, max x-координату и max y-координату, необходимые для рисования ограничивающего прямоугольника, который охватывает все ограничивающие прямоугольники в данной группе.
bboxes_list = sorted(bbox_mod, key=lambda k: k[1]) # Sort the bounding boxes based on y1 coordinate ( y of the left-top coordinate ) combined_bboxes = grouper(bboxes_list, median_height) # Group the bounding boxes for group in combined_bboxes: x_min = min(group, key=lambda k: k[0])[0] # Find min of x1 x_max = max(group, key=lambda k: k[2])[2] # Find max of x2 y_min = min(group, key=lambda k: k[1])[1] # Find min of y1 y_max = max(group, key=lambda k: k[3])[3] # Find max of y2 cv2.rectangle(img, (x_min, y_min), (x_max, y_max), (0, 255, 0), 2)
Конечный результирующий образ -
Опять же, я хотел бы еще раз повторить тот факт, что они могут быть способами дальнейшей оптимизации этого подхода. Цель состоит в том, чтобы дать вам представление о том, как можно решать такие проблемы.