Разделить изображение текста на составные изображения символов

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

Я собираюсь использовать текст только в одной строке, поэтому высота по оси y не имеет значения — мне нужно найти начало и конец каждой буквы и обрезать по этим координатам. Таким образом, я бы также избежал проблем с «i», «j» и т. д.

Я новичок в обработке изображений, и я не уверен, как это сделать. Какая-то форма обнаружения края? Есть ли способ определить смежные области сплошного цвета? Любая помощь прекрасна.

Пытаясь улучшить свои навыки работы с Python и познакомиться с некоторыми из множества доступных библиотек, я использую Python Imaging. Library (PIL), но я также просмотрел OpenCV.


Образец изображения:

Это какой-то текст


person blork    schedule 29.12.2009    source источник


Ответы (6)


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

Вы можете начать применять пороговый алгоритм, если ваше изображение не бинарное (хорошо работает адаптивный порог Otsu)

После этого вы можете использовать алгоритм маркировки, чтобы идентифицировать каждый «остров» пикселей, который формирует ваши фигуры (в данном случае каждый символ).

Проблема возникает, когда у вас есть шум. Фигуры, которые были помечены, но не представляют интереса. В этом случае вы можете использовать некоторую эвристику, чтобы определить, является ли фигура символом или нет (вы можете использовать нормализованную область, положение объекта, если ваш текст находится в четко определенном месте и т. д.). Если этого недостаточно, вам придется иметь дело с более сложным персоналом, таким как алгоритмы извлечения признаков формы и какой-то алгоритм распознавания образов, например, многослойные персептроны.

Чтобы закончить, это кажется простой задачей, но в зависимости от качества вашего изображения это может стать сложнее. Приведенные здесь алгоритмы можно легко найти в Интернете или реализовать в некоторых библиотеках, таких как OpenCv.

Любая дополнительная помощь, просто спросите, если я могу помочь, конечно;)

person Andres    schedule 29.12.2009
comment
Спасибо за ваш ответ! На данный момент меня интересует только обработка простых изображений, таких как предоставленный мной образец, черный текст на сплошном белом фоне. Другие соображения я могу добавить позже, так что спасибо за советы. Алгоритм маркировки, значит? Быстрый google дает мне cvBlobsLib из библиотеки OpenCV, которая, кажется, может справиться с поиском фигур. Я не знаю, как тогда их спасти, но я попробую. - person blork; 29.12.2009

Я знаю, что опоздал на несколько лет :-), но теперь вы можете довольно легко делать такие вещи с ImageMagick, прямо в командной строке, ничего не компилируя, поскольку в него встроен анализ подключенных компонентов:

Вот один из способов сделать это так:

#!/bin/bash
image="$1"
draw=$(convert $image                              \
   -threshold 50%                                  \
   -define connected-components:verbose=true       \
   -define connected-components:area-threshold=10  \
   -connected-components 8                         \
   -auto-level objects.png | \
   awk 'BEGIN{command=""}
        /\+0\+0/||/id:/{next}
        {
          geom=$2
          gsub(/x/," ",geom)
          gsub(/+/," ",geom)
          split(geom,a," ")
          d=sprintf("-draw \x27rectangle %d,%d %d,%d\x27 ",a[3],a[4],a[3]+a[1],a[4]+a[2])
          command = command d
          #printf "%d,%d %d,%d\n",a[3],a[4],a[3]+a[1],a[4]+a[2]
        }
        END{print command}')

eval convert "$image" -fill none -strokewidth 2 -stroke red $draw result.png

Результат выглядит следующим образом:

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

Во-первых, я порогую ваше изображение на 50%, чтобы в нем были только чистые черные и белые цвета, без тональных градаций. Затем я говорю ImageMagick, чтобы он выводил информацию о найденных ограничивающих прямоугольниках, и что меня не интересуют объекты общей площадью менее 10 пикселей. Затем я разрешаю пикселям быть 8-связными, то есть с их соседями по диагонали (СВ, ЮВ, СЗ, ЮЗ), а также с их соседями слева-справа и сверху-снизу. Наконец, я анализирую выходные данные ограничивающей рамки с помощью awk, чтобы нарисовать красные линии вокруг ограничивающих рамок.

Вывод исходной команды, которую я анализирую с помощью awk, выглядит следующим образом:

Objects (id: bounding-box centroid area mean-color):
  0: 539x53+0+0 263.7,24.3 20030 srgba(255,255,255,1)
  11: 51x38+308+14 333.1,30.2 869 srgba(0,0,0,1)
  13: 35x39+445+14 461.7,32.8 670 srgba(0,0,0,1)
  12: 35x39+365+14 381.7,32.8 670 srgba(0,0,0,1)
  2: 30x52+48+0 60.4,27.0 634 srgba(0,0,0,1)
  1: 41x52+1+0 20.9,16.6 600 srgba(0,0,0,1)
  8: 30x39+174+14 188.3,33.1 595 srgba(0,0,0,1)
  7: 30x39+102+14 116.3,33.1 595 srgba(0,0,0,1)
  9: 30x39+230+14 244.3,33.1 595 srgba(0,0,0,1)
  10: 35x39+265+14 282.2,33.0 594 srgba(0,0,0,1)
  16: 33x37+484+15 500.2,33.0 520 srgba(0,0,0,1)
  17: 22x28+272+19 282.3,32.8 503 srgba(255,255,255,1)
  5: 18x51+424+2 432.5,27.9 389 srgba(0,0,0,1)
  6: 18x51+520+2 528.5,27.9 389 srgba(0,0,0,1)
  15: 6x37+160+15 162.5,33.0 222 srgba(0,0,0,1)
  14: 6x37+88+15 90.5,33.0 222 srgba(0,0,0,1)
  18: 22x11+372+19 382.6,24.9 187 srgba(255,255,255,1)
  19: 22x11+452+19 462.6,24.9 187 srgba(255,255,255,1)
  3: 6x8+88+0 90.5,3.5 48 srgba(0,0,0,1)
  4: 6x8+160+0 162.5,3.5 48 srgba(0,0,0,1)

и awk превращает это в это

convert http://imgur.com/AVW7A.png -fill none -strokewidth 2 -stroke red \
-draw 'rectangle 308,14 359,52'        \
-draw 'rectangle 445,14 480,53'        \
-draw 'rectangle 365,14 400,53'        \
-draw 'rectangle 48,0 78,52'           \
-draw 'rectangle 1,0 42,52'            \
-draw 'rectangle 174,14 204,53'        \
-draw 'rectangle 102,14 132,53'        \
-draw 'rectangle 230,14 260,53'        \
-draw 'rectangle 265,14 300,53'        \
-draw 'rectangle 484,15 517,52'        \
-draw 'rectangle 272,19 294,47'        \
-draw 'rectangle 424,2 442,53'         \
-draw 'rectangle 520,2 538,53'         \
-draw 'rectangle 160,15 166,52'        \
-draw 'rectangle 88,15 94,52'          \
-draw 'rectangle 372,19 394,30'        \
-draw 'rectangle 452,19 474,30'        \
-draw 'rectangle 88,0 94,8'            \
-draw 'rectangle 160,0 166,8' result.png
person Mark Setchell    schedule 19.01.2015
comment
@Setchell, я получаю эту ошибку при запуске вашего скрипта. convert: изображения не определены 'word.png' @ error/convert.c/ConvertImageCommand/3275. Вы можете помочь? - person Shreesha N; 12.06.2018
comment
@ShreeshaN Как ты это запустил? Какой образ вы использовали? Какую версию ImageMagick вы используете? Вы на какой ОС? Попробуйте добавить `-xv` в конец первой строки. - person Mark Setchell; 12.06.2018
comment
Версия ImageMagick - 7.0.7-38, изображение - jpg/png, ОС - MacOS. Добавление -xv не помогло. ошибка определения изображений не сохраняется - person Shreesha N; 12.06.2018
comment
Как вы его запускали? - person Mark Setchell; 12.06.2018
comment
Сохранил его в файле .sh и запустил sh filename.sh - person Shreesha N; 12.06.2018
comment
Вы должны передать ему имя вашего изображения в качестве первого параметра. Вы также не должны запускать сценарии bash с sh, потому что sh не является bash. - person Mark Setchell; 12.06.2018

Вы можете начать с простого алгоритма анализа связанных компонентов (CCA), который можно довольно эффективно реализовать с помощью алгоритма растровой строки (вы просто отслеживаете объединенные регионы и переименовываете их в конце). Это даст вам отдельно пронумерованные «капли» для каждой непрерывной области, что будет работать для большинства (но не для всех) букв. Затем вы можете просто взять ограничивающую рамку каждого связанного блоба, и это даст вам контур для каждого. Вы даже можете сохранить ограничивающую рамку, применяя CCA для повышения эффективности.

Итак, в вашем примере первое слово слева после CCA приведет к чему-то вроде:

1111111  2         3
   1     2
   1     2 4444    5  666
   1     22    4   5 6
   1     2     4   5  666
   1     2     4   5     6
   1     2     4   5  666

с классами эквивалентности 4=2.

Затем ограничивающие рамки каждой капли дают вам область вокруг буквы. Вы столкнетесь с проблемами с такими буквами, как i и j, но они могут быть в особом регистре. Вы можете искать область меньше определенного размера, которая находится над другой областью определенной ширины (как грубая эвристика).

Библиотека cvBlobsLib в OpenCV должна сделать большую часть этого за вас.

person gavinb    schedule 29.12.2009

Гм, это на самом деле очень просто для образца, который вы предоставили:

start at left edge
  go right 1 column at a time until the current column contains black (a letter)
  this is the start of the character
  go right again till no black at all in current column
  end of character
repeat till end of image

(Между прочим, это также работает для разделения абзаца на строки.)
Если буквы перекрываются или имеют общие столбцы, это становится немного трудным интересным.

Редактировать:

@Андрес, нет, для 'U' все работает нормально, нужно смотреть все в каждом столбце

 U   U
 U   U
 U   U
 U   U
  UUU
 01234

0,4:everything but bottom row
1-3:only bottom row
person David X    schedule 29.12.2009
comment
С этим подходом есть проблема. Шаги «снова идите вправо, пока не станет черным, конец символа» неверны. Если вы обрабатываете символ «U» или даже символ «h», конец черного не означает конец символа, поскольку они образуют два столбца пикселей с пробелом между ними. - person Andres; 29.12.2009

Недавно я экспериментировал с ocropus, анализом текста с открытым исходным кодом и распознаванием текста. инструмент предварительной обработки. В рамках своего рабочего процесса он также создает нужные вам изображения. Возможно, это поможет вам, хотя магия python не задействована.

person moritz    schedule 29.12.2009

Проблема, которую вы поставили, действительно сложна, ее решение заняло некоторое время у лучших мировых исследователей в области обработки изображений. Решение — основная часть набора инструментов Djvu для сжатия изображений и отображения: их первый шаг в сжатии документа — определить передний план и разделить его на символы. Затем они используют эту информацию для облегчения сжатия, поскольку изображение одной буквы «е» в нижнем регистре очень похоже на другую — сжатый документ должен содержать только различия. Вы найдете ссылки на множество технических документов по адресу http://djvu.org/resources/; лучше всего начать с Высококачественное сжатие изображения документа с помощью Djvu.

Многие инструменты пакета Djvu находятся в открытом доступе под названием djvulibre; к сожалению, мне не удалось выяснить, как вытащить передний план (или отдельные символы) с помощью существующих инструментов командной строки. Мне было бы очень интересно посмотреть, как это будет сделано.

person Norman Ramsey    schedule 29.12.2009