В Tesseract всегда отсутствует текстовая строка на картинке - PullRequest
6 голосов
/ 26 мая 2020

Я пытаюсь извлечь данные из изображения с помощью OCR. Для этого я использую Tesseract API в C ++.

Исходное изображение таково:

enter image description here

Now the for me important data is this:

обработка изображений для повышения точности распознавания текста в тессеракте

Код для предварительной обработки:

cv::Mat image;
image = cv::imread(filename, cv::IMREAD_COLOR);
cv::resize(image, image, cv::Size{}, 1.2, 1.2, cv::INTER_CUBIC);

cv::cvtColor(image, image, cv::COLOR_BGR2GRAY);

auto kernel = cv::Mat(1, 1, CV_8UC1, cv::Scalar(1));
cv::dilate(image, image, kernel);
cv::erode(image, image, kernel);

cv::Mat filter;
cv::bilateralFilter(image, filter, 5, 75, 75);

cv::threshold(filter, image, 0, 255, cv::THRESH_BINARY + cv::THRESH_OTSU);

Я что-то упустил? Могу ли я настроить сам Tesseract или мне следует изменить предварительную обработку изображения?

Ответы [ 2 ]

3 голосов
/ 30 мая 2020

Моя ссылка здесь .

Примечание: Вам не нужно иметь дело с этапами предварительной обработки, потому что кажется, что у вас уже есть чистый образ. У него не так много шумов.

Информация о моем окружении:

Operating system: Ubuntu 16.04

Версия Tesseract по команде tesseract --version:

tesseract 4.1.1-rc2-21-gf4ef
 leptonica-1.78.0
  libgif 5.1.4 : libjpeg 8d (libjpeg-turbo 1.4.2) : libpng 1.2.54 : libtiff 4.0.6 : zlib 1.2.8 : libwebp 0.4.4 : libopenjp2 2.1.2
 Found AVX
 Found SSE
 Found libarchive 3.1.2

Версия OpenCV по команде pkg-config --modversion opencv:

3.4.3

Разница: Когда я проверил ваш код, я увидел только явную разницу с этим. Вы еще раз открываете изображение с помощью библиотеки leptonica вместо opencv.

Вот код и результат:

Вход:

enter image description here

Выходные тексты:

Al AQ A3 Ad AS A6 Al A8

| 2 3 4 5 6 7 8

WH GN YE GY PK Bu RD VT
K101 K102 K103 K104 K105 K107 K109 K110
Q30,0 Q30.1 Q30.2 Q30.3 Q30.4 Q30.5 Q30.6 Q30.7
=13/L.2 =13/2.2 =13/4.2 =13/6.2 =13/7.2 =13/10.2 FIBL.2 = 1312.2

AS AlO All Al2 AL3 Al4 ALS AL6

9 10 ll 12 13 14 15 16
GY /PK RD/BU WH/GN BN/GN WH/YE YE/BN WH/GY GY/BN
Kl1l K112 y114 K115 K117 K118 K124
Q31,0 Q31.1 Q31.2 Q31.3 Q31.4 Q31.5 Q31.6 Q31.7
=13/13.2 =13/14.2 =13/15.2 =13/16.2 =1B7.2 PIB. =13/21.2

Beckhoff KL 2809

Код:

#include <string>
#include <tesseract/baseapi.h>
#include <leptonica/allheaders.h>
#include <opencv2/opencv.hpp>

using namespace std;
using namespace cv;

int main(int argc, char* argv[])
{
    string outText;


    // Create Tesseract object
    tesseract::TessBaseAPI *ocr = new tesseract::TessBaseAPI();

    ocr->Init(NULL, "eng", tesseract::OEM_LSTM_ONLY);


    // Set Page segmentation mode to PSM_AUTO (3)
    ocr->SetPageSegMode(tesseract::PSM_AUTO);


    // Open input image using OpenCV
    Mat im = cv::imread("/ur/image/directory/tessatest.png", IMREAD_COLOR);


    // Set image data
    ocr->SetImage(im.data, im.cols, im.rows, 3, im.step);

    // Run Tesseract OCR on image
    outText = string(ocr->GetUTF8Text());

    // print recognized text
    cout << outText << endl;

    // Destroy used object and release memory
    ocr->End();

    return EXIT_SUCCESS;
}

Составление кода:

g++ -O3 -std=c++11 test.cpp -o output `pkg-config --cflags --libs tesseract opencv`
2 голосов
/ 28 мая 2020

Tesseract имеет тенденцию отбрасывать строки или фрагменты текста в нескольких случаях:

  • Есть некоторые нетекстовые вещи, которые мешают (линии, артефакты, градиенты освещения)
  • Там слишком много вещей, которые не распознаются как символы с достаточной уверенностью
  • Линия неровная (неровности) / плохо выровнена, а также искажения, такие как перспектива
  • Внутри линии слишком большие пробелы
  • Текст расположен слишком близко к другому тексту, особенно если размер шрифта также неравномерный

Я не буду публиковать готовое решение или код, но могу написать, что бы я попробовал, основываясь на моем опыте работы с Tesseract:

  1. Не устанавливайте пороговые значения для сканированных изображений, это часто ухудшает эффект, поскольку информация теряется, это имеет больше смысла, когда сканируется не текст, а фотография с градиентами света / тени и т. Д. c. (в таких сценах относительно хорошо работает адаптивный порог или другие фильтры + порог). В противном случае - нет причин для этого, Tesseract выполняет внутреннюю бинаризацию (которая довольно плохо работает для градиентов молний / теней, поскольку она не адаптивна, но довольно хорошо подходит для отсканированных изображений).

  2. Попробуйте проверить как это происходит с разными DPI / размерами изображений. Может работать лучше, если вы найдете оптимальный вариант (это больше о более старой версии Tesseract, в настоящее время это имеет меньшее значение).

РЕДАКТИРОВАТЬ: Для изменения размера в opencv можно использовать:

cv::resize(inImg, outImg, cv::Size(), 0.7, 0.7);

Удаление прямоугольников вокруг текста может помочь.

  • Это может быть сделано путем обнаружения линий, прямоугольников или контуров, фильтрации по длине / размеру относительно ширины изображения (или абсолютной, если он всегда один и тот же) и рисует на нем белым, поэтому он удаляется.

EDIT: на inte rnet есть несколько руководств по обнаружению прямоугольников. Большинство из них обнаруживают и рисуют. Например, alyssaq / opencv / squares. cpp на Github . Вы можете обнаружить квадраты, затем отфильтровать их по размеру в C ++, а затем нарисовать их белым, чтобы он рисовал белым поверх черного и эффективно удалял их.

  • В качестве альтернативы это можно сделать путем копирования с маскированием, но это может быть труднее писать и хуже по производительности

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

EDIT: для гистограммы по Y и поиска пробелов между строками см. Этот вопрос Найти все пики для Mat () в OpenCV C ++ - это должно быть сделано аналогично, но на другой оси.

для обрезки см. этот вопрос и ответы Как обрезать CvMat в OpenCV?

для добавления отступов есть метод copyMakeBorder (), см. Добавление границ к изображениям в документации.

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

  • может размывать изображение с пороговым значением, чтобы сгруппировать буквы, найти контуры, отфильтровать их, взять их определенных c размеров для обработки, вырезать их с помощью маски, дополнить их белым, обработать каждый

РЕДАКТИРОВАТЬ: для этого вы можете найти вопросы и ответы по этой полезной ссылке: Извлечение текста OpenCV

  • может использовать те прямоугольники, которые у вас есть - найти их положение с обнаружением формы, вырезать содержимое, обработать индивидуально

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

РЕДАКТИРОВАТЬ: Чтобы узнать слова или символы, можно использовать этот код:

tesseract::ResultIterator *iter = tess.GetIterator();
tesseract::PageIteratorLevel level = tesseract::RIL_WORD; // may use RIL_SYMBOL

if (iter != 0) {
  do {
    const char *word = iter->GetUTF8Text(level);
    float conf = iter->Confidence(level);
    int x1, y1, x2, y2;
    iter->BoundingBox(level, &x1, &y1, &x2, &y2);

    if (word) {
      printf("word: '%s';  \tconfidence: %.2f\t bounding box: [%d,%d,%d,%d]\n", word, conf, x1, y1, x2, y2);

      // ... use that info

      delete[] word;
    }
  } while (iter->Next(level));
}

Код не тестировался, правильный код может отличаться для разных версий Tesseract, это для 3.0.

И последнее, но не менее важное: если не все изображения хорошо выровнены при сканировании, то, конечно, необходимо провести некоторую обработку, чтобы сделать его хорошо выровненным и выровненным, также вам нужно будет удалить градиенты / тени, если изображения создаются по фотографии, а не со сканера. . Тем не менее на примере я вижу, что это относительно хорошие отсканированные изображения, поэтому здесь нет необходимости (я вижу проблему с некоторыми символами, которые плохо напечатаны / ксерокопированы, с этим будет сложно что-либо сделать).

РЕДАКТИРОВАТЬ: не буду помещать примеры или ссылки для этого пункта, так как это очень широкая тема c и зависит от качества изображений, от того, как это делается, как выглядит текст, какой фон и c.

...