Объединение регионов в 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-координатами. Следующий подход может быть неэффективным, и я постараюсь оптимизировать его, но он может дать вам представление о том, как решить проблему.

  1. Во-первых, давайте построим все 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)
    

    Это дает нам - MSER обнаружил bboxes

  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
    
  3. Теперь, чтобы сгруппировать ограничивающие прямоугольники, учитывая определенный интервал для 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
    
  4. Таким образом, перед группировкой ограничивающих рамок их необходимо отсортировать по координате 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)
    

    Конечный результирующий образ -

    Lines_combined

Опять же, я хотел бы еще раз повторить тот факт, что они могут быть способами дальнейшей оптимизации этого подхода. Цель состоит в том, чтобы дать вам представление о том, как можно решать такие проблемы.

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