Объединение областей в 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. Любая помощь будет оценена по достоинству.

Прикрепите образец изображения введите здесь описание изображения

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

Другая строка введите здесь описание изображения

Другая строка введите здесь описание изображения


person Amrith Krishna    schedule 05.02.2018    source источник
comment
Каков ваш ожидаемый результат?   -  person ZdaR    schedule 05.02.2018
comment
@ZdaR - Обновлено описание. Я хочу объединить регионы так, чтобы регионы, принадлежащие строке текста, объединялись как одно изображение.   -  person Amrith Krishna    schedule 05.02.2018
comment
Подсчитайте количество белых пикселей для каждой строки бинарного изображения и сегмента, где обнаружены пики в распределении белого цвета.   -  person ZdaR    schedule 05.02.2018
comment
Проверьте это   -  person Miki    schedule 05.02.2018
comment
@AmrithKrishna Не могли бы вы указать, почему ответ с эрозией / расширением был выбран в качестве принятого ответа?   -  person GaneshTata    schedule 08.02.2018
comment
@GaneshTata- Большое спасибо за ваш ответ. Во-первых, средняя высота вообще не работала из-за разной высоты капель. Капли разной длины в первую очередь появлялись из-за специфических для языка свойств, таких как лигатуры, метки и т. д. Теперь идея принятого ответа не зависела от них. Путем расширения и эрозии с небольшими корректировками я получал желаемые результаты. Предположим, что оба подхода более или менее дают один и тот же результат, по бритве Оккама следует предпочесть тот, который проще. Следовательно, предпочтение отдается текущему принятому ответу.   -  person Amrith Krishna    schedule 09.02.2018


Ответы (2)


Может быть, даже что-то столь примитивное, как расширение-разрушение, может работать в вашем случае? Например, если я использую операцию erode, за которой следует операция dilate на исходном изображении, и в основном в горизонтальном направлении, т.е. грамм.:

img = cv2.erode(img, np.ones((1, 20)))
img = cv2.dilate(img, np.ones((1, 22)))

результат примерно такой:

введите здесь описание изображения

Итак, если мы нарисуем это поверх исходного изображения, оно станет:

введите здесь описание изображения

Я не изменил размер исходного изображения, как вы (вероятно, чтобы обнаружить эти маленькие отдельные точки и прочее). Не идеально (я не знаю, как работает MSER), но с достаточной настройкой, возможно, вы могли бы даже использовать простое обнаружение подключенных компонентов с этим?

person Headcrab    schedule 05.02.2018

Если вы особенно заинтересованы в использовании MSER, то, как вы упомянули, можно использовать эвристику для объединения областей с близлежащими координатами y. Следующий подход может оказаться неэффективным, и я попытаюсь его оптимизировать, но он может дать вам представление о том, как решить проблему.

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

    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 (Здесь средняя высота), я изменяю фрагмент, который я когда-то нашел в stackoverflow (я добавлю исходный код, как только найду его). Эта функция принимает список вместе с определенным интервалом в качестве входных данных и возвращает список групп, где каждая группа содержит ограничивающие прямоугольники, абсолютная разница в координатах 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. После группировки мы перебираем каждую группу и определяем минимальную координату x, минимальную координату y, максимальную координату x и максимальную координату 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)
    

    Окончательное результирующее изображение -

    Линии_объединенные

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

person GaneshTata    schedule 05.02.2018