В этой части OCR расшифровывается как оптическое распознавание символов. Этот метод широко используется для чтения текстов из кодексов, которые можно найти в части 1.

Итак, начинаем с изображения:

Большинство мемов имеют этот отчетливый белый шрифт, и мы хотим это исправить. Применяя инверсию цветов, мы получаем текст, близкий к удобочитаемому для человека, но ценой наличия поверхностей. Наличие поверхностей не имело бы большого значения до тех пор, пока не появился тессеракт — мой выбор OCR не стал бы на него ругаться, в результате извергая мусор.

Сначала я хотел исправить символы мусора, для изображения в градациях серого я получил:

MM Bou, YOU WROTE AN ARTICLE ||\n5 ABOUT MEMES? k\n. i\n\nay Bos\n\n2\n\nPLEASE, TELL ME MORE ABOUT HOW\nORIGINAL YOU ARE\n\n \n\x0c

Цифры и новые строки неуместны. К счастью, Tesseract позволяет пользователям устанавливать собственные настройки, такие как символы из белого списка. Это текущая настройка, которую я использую. Флаг OEM означает использование устаревшего или LSTM (Long-Short Term Memory — тип алгоритма машинного обучения) механизма распознавания символов, если LSTM будет доступен. PSM приказывает tesseract найти как можно больше текста, потому что нельзя делать безопасных предположений о том, где будет текст в мемах и в каком формате они будут.

"--oem 3 --psm 11 -c tessedit_char_whitelist='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"

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

Когда я увидел белый текст и яркий фон, моей первой мыслью было: просто инвертируйте цвета с порогом, и все готово. Этот метод не сработал, как планировалось, и текст был слишком фрагментирован, чтобы собрать из них значимые теги. Естественно, я искал алгоритмы обработки изображений. Первое, что я нашел, это морфологические преобразования: они используются для поиска форм в изображениях.

Преобразование состоит из ядра и образа. Ядро представляет собой движущуюся сетку, которая перебирает изображение во время преобразования, обычно определяя пороговое значение пикселей, таким образом реализуя решение динамического порогового значения. Есть много преобразований: в первую очередь эрозия, расширение и их перестановки, такие как открытие и закрытие. Вы можете узнать больше о преобразованиях на этой справочной странице OpenCV.

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

Адаптивная пороговая обработка по Гауссу — судя по названию — работает с изображением с заранее определенным ядром. Этот метод вычисляет взвешенную сумму ядра, которая взаимно коррелируется с гауссовой оконной функцией, и вычитает стандартное отклонение.

Гауссовский порог был многообещающим, но прорыв произошел, когда он был объединен с методом Оцу.

Немного поискав, я нашел еще один метод, который дает отличные результаты. К сожалению, это преобразование, преобразование ширины обводки, лучше всего подходит для изображений с черным текстом и белым фоном, см. предыдущую ссылку для получения потрясающих результатов. При этом у меня было 3 метода для яркого фона и белого текста и один для белого фона и черного текста.

Объединение найденных текстов.

После замены символов новой строки пробелами и удаления строк мы получаем слова и слова, написанные вместе из предварительно обработанных изображений. Я использовал воронку, так как каждое преобразованное/предварительно обработанное изображение проходило через OCR. Собрав все строки из процесса, были выполнены основные этапы обработки текста: чередование пробелов, разделение слов и разделение слов, написанных вместе.

Разделение слов, написанных вместе

До сих пор это была одна из самых сложных задач. Я пробовал искать настоящие английские слова в корпусах, я использовал nltk’s brown и слова corpi, использовал wordninja и, наконец, enchant.

Первая попытка: моя гипотеза заключалась в том, что если у вас есть миллион слов в корпусе, вы можете выбрать 10 000 самых распространенных, которые не являются стоп-словами (самые распространенные английские слова, которые бесполезны при поиске, например: a, an, он она). Эта гипотеза вскоре потерпела неудачу, поскольку поиск допустимых слов вскоре вернул отдельные буквы и короткие непонятные строки, которые БЫЛИ частью корпуса, но не квалифицируются как допустимое слово. Например, притяжательное ‹’s› считается словом в корпусе и встречалось много раз для каждого изображения.

Второй запуск: wordninja — это статистический инструмент для нарезки слов, он поставляется с корпусом, который можно редактировать/расширять, но слова в его словаре должны быть пропорциональны вероятности появления слов. Это было самое быстрое решение, но словарь предпочел слишком глубокий язык для мемов, и поэтому такие слова, как просветление, которые могут быть ключевыми словами, не были найдены.

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

def _split_long_string(long: str, dictionary) -> list[str]:
    length = len(long)
    words = set()
    longest = 0
    for i in range(0, length - 2):
        if i < longest:
            continue
        for j in range(length, i + 1, -1):
            if dictionary.check(long[i:j]):
                words.add(long[i:j])
                longest = j
                break
    return words

В конце модуля я собираю каждое слово в один HashSet и ищу для него синоним, чтобы расширить теги. Синонимы находятся в WordNet.

В следующей части я опишу обнаружение объектов и обнаружение лиц/эмоций в процессе маркировки.