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

147

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

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

Какие-нибудь общие советы для тех, кто является новичком в обработке изображений?

user364902
источник

Ответы:

106
  1. исправить DPI (при необходимости) минимум 300 DPI
  2. исправить размер текста (например, 12 пунктов должно быть в порядке)
  3. попытаться исправить текстовые строки (выравнивание и удаление текста)
  4. попытаться исправить освещенность изображения (например, нет темной части изображения)
  5. бинаризация и устранение шума изображения

Не существует универсальной командной строки, которая бы подходила для всех случаев (иногда вам нужно размыть и повысить резкость изображения). Но вы можете попробовать TEXTCLEANER из скриптов ImageMagick Фреда .

Если вы не фанат командной строки, возможно, вы можете попробовать использовать opensource scantailor.sourceforge.net или коммерческий бухгалтер .

user898678
источник
6
И есть иллюстрированное руководство о том, как это сделать: code.google.com/p/tesseract-ocr/wiki/ImproveQuality
iljau
2
Обратите внимание, что связанный скрипт выглядит только для Linux.
Зоран Павлович
1
Это не так - это скрипт bash. Если вы установили bash и ImageMagick, он будет работать и на Windows. Bash может быть установлен как часть другого полезного программного обеспечения, например, git или msys2 ...
user898678
6
@iljau С тех пор как перешел на github. Вики-страница находится по адресу: github.com/tesseract-ocr/tesseract/wiki/ImproveQuality
hometoast
2
Документы Тессеракта переехали снова, tesseract-ocr.github.io/tessdoc/ImproveQuality
Nobody
73

Я ни в коем случае не эксперт OCR. Но мне на этой неделе пришлось конвертировать текст из jpg.

Я начал с цветного, RGB 445x747 пикселей jpg. Я сразу попробовал тессеракт на этом, и программа почти ничего не конвертировала. Затем я вошел в GIMP и сделал следующее. image> mode> grayscale image> scale image> 1191x2000 пикселей фильтры> улучшение> нерезкая маска со значениями радиуса = 6,8, количество = 2,69, порог = 0 Затем я сохраняю как новый jpg с качеством 100%.

Затем Tesseract смог извлечь весь текст в файл .txt

Гимп твой друг.

Джон
источник
11
+1 Я следовал твоим шагам и получил большое улучшение. Спасибо
от
1
У меня также сложилось впечатление, что Tesseract работает лучше, если вы преобразуете входные данные в файл TIFF и даете Tesseract TIFF (вместо того, чтобы просить Tesseract выполнить преобразование для вас). ImageMagick может сделать преобразование для вас. Это мое неподтвержденное впечатление, но я не проверил его тщательно, так что это может быть неправильно.
DW
+1 Фильтр «нерезкая маска» действительно сделал мой день. Еще один шаг, который мне помог: с помощью инструмента «Нечеткое выделение» выберите фон, затем нажмите Del, чтобы украсить его
Davide
Я застрял в этой проблеме с обработкой изображений перед распознаванием tesseract stackoverflow.com/questions/32473095/… Можете ли вы помочь мне здесь?
Хуссейн
Нет. я попытался сделать его больше, и установить его в оттенках серого, кажется, ничего не дает мне положительного результата. Вздох :( Проверьте эту цель: freesms4us.com/…
gumuruh
30

Три пункта для улучшения читабельности изображения: 1) Измените размер изображения с переменной высотой и шириной (умножьте 0,5 и 1 и 2 на высоту и ширину изображения). 2) Преобразуйте изображение в формат оттенков серого (черно-белый). 3) Уберите пиксели шума и сделайте их более четкими (Фильтруйте изображение).

Смотрите ниже код:

//Resize
  public Bitmap Resize(Bitmap bmp, int newWidth, int newHeight)
        {

                Bitmap temp = (Bitmap)bmp;

                Bitmap bmap = new Bitmap(newWidth, newHeight, temp.PixelFormat);

                double nWidthFactor = (double)temp.Width / (double)newWidth;
                double nHeightFactor = (double)temp.Height / (double)newHeight;

                double fx, fy, nx, ny;
                int cx, cy, fr_x, fr_y;
                Color color1 = new Color();
                Color color2 = new Color();
                Color color3 = new Color();
                Color color4 = new Color();
                byte nRed, nGreen, nBlue;

                byte bp1, bp2;

                for (int x = 0; x < bmap.Width; ++x)
                {
                    for (int y = 0; y < bmap.Height; ++y)
                    {

                        fr_x = (int)Math.Floor(x * nWidthFactor);
                        fr_y = (int)Math.Floor(y * nHeightFactor);
                        cx = fr_x + 1;
                        if (cx >= temp.Width) cx = fr_x;
                        cy = fr_y + 1;
                        if (cy >= temp.Height) cy = fr_y;
                        fx = x * nWidthFactor - fr_x;
                        fy = y * nHeightFactor - fr_y;
                        nx = 1.0 - fx;
                        ny = 1.0 - fy;

                        color1 = temp.GetPixel(fr_x, fr_y);
                        color2 = temp.GetPixel(cx, fr_y);
                        color3 = temp.GetPixel(fr_x, cy);
                        color4 = temp.GetPixel(cx, cy);

                        // Blue
                        bp1 = (byte)(nx * color1.B + fx * color2.B);

                        bp2 = (byte)(nx * color3.B + fx * color4.B);

                        nBlue = (byte)(ny * (double)(bp1) + fy * (double)(bp2));

                        // Green
                        bp1 = (byte)(nx * color1.G + fx * color2.G);

                        bp2 = (byte)(nx * color3.G + fx * color4.G);

                        nGreen = (byte)(ny * (double)(bp1) + fy * (double)(bp2));

                        // Red
                        bp1 = (byte)(nx * color1.R + fx * color2.R);

                        bp2 = (byte)(nx * color3.R + fx * color4.R);

                        nRed = (byte)(ny * (double)(bp1) + fy * (double)(bp2));

                        bmap.SetPixel(x, y, System.Drawing.Color.FromArgb
                (255, nRed, nGreen, nBlue));
                    }
                }



                bmap = SetGrayscale(bmap);
                bmap = RemoveNoise(bmap);

                return bmap;

        }


//SetGrayscale
  public Bitmap SetGrayscale(Bitmap img)
        {

            Bitmap temp = (Bitmap)img;
            Bitmap bmap = (Bitmap)temp.Clone();
            Color c;
            for (int i = 0; i < bmap.Width; i++)
            {
                for (int j = 0; j < bmap.Height; j++)
                {
                    c = bmap.GetPixel(i, j);
                    byte gray = (byte)(.299 * c.R + .587 * c.G + .114 * c.B);

                    bmap.SetPixel(i, j, Color.FromArgb(gray, gray, gray));
                }
            }
            return (Bitmap)bmap.Clone();

        }
//RemoveNoise
   public Bitmap RemoveNoise(Bitmap bmap)
        {

            for (var x = 0; x < bmap.Width; x++)
            {
                for (var y = 0; y < bmap.Height; y++)
                {
                    var pixel = bmap.GetPixel(x, y);
                    if (pixel.R < 162 && pixel.G < 162 && pixel.B < 162)
                        bmap.SetPixel(x, y, Color.Black);
                    else if (pixel.R > 162 && pixel.G > 162 && pixel.B > 162)
                        bmap.SetPixel(x, y, Color.White);
                }
            }

            return bmap;
        }

ВХОДНОЕ ИЗОБРАЖЕНИЕ
ВХОДНОЕ ИЗОБРАЖЕНИЕ

ВЫХОДНОЕ ИЗОБРАЖЕНИЕ ВЫХОДНОЕ ИЗОБРАЖЕНИЕ

Сатьярадж Паланисами
источник
Да. Мы должны передать требуемый параметр в метод Resize, он будет обрабатывать операции preize, resG, SetGrayscale и RemoveNoise, а затем вернуть выходное изображение с лучшей читаемостью.
Сатьярадж Паланисами
Опробовал этот подход на множестве файлов и сравнил с первоначальным результатом. В некоторых ограниченных случаях это дает лучший результат, в основном было небольшое снижение качества выходного текста. Таким образом, это не выглядит универсальным решением.
Брин
Это действительно сработало для меня. Конечно, это дает отправную точку для предварительной обработки изображений, которая устраняет количество тарабарщины, которую вы получаете от Tesseract.
SES
22

Как правило, я использую следующие методы предварительной обработки изображений с использованием библиотеки OpenCV:

  1. Изменение масштаба изображения (рекомендуется, если вы работаете с изображениями с разрешением менее 300 dpi):

    img = cv2.resize(img, None, fx=1.2, fy=1.2, interpolation=cv2.INTER_CUBIC)
    
  2. Преобразование изображения в оттенки серого:

    img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    
  3. Применение расширения и эрозии для устранения шума (вы можете поиграть с размером ядра в зависимости от набора данных):

    kernel = np.ones((1, 1), np.uint8)
    img = cv2.dilate(img, kernel, iterations=1)
    img = cv2.erode(img, kernel, iterations=1)
    
  4. Применение размытия, которое можно выполнить с помощью одной из следующих строк (однако каждая из них имеет свои плюсы и минусы, однако медианное размытие и двусторонний фильтр обычно работают лучше, чем размытие по Гауссу.):

    cv2.threshold(cv2.GaussianBlur(img, (5, 5), 0), 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)[1]
    
    cv2.threshold(cv2.bilateralFilter(img, 5, 75, 75), 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)[1]
    
    cv2.threshold(cv2.medianBlur(img, 3), 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)[1]
    
    cv2.adaptiveThreshold(cv2.GaussianBlur(img, (5, 5), 0), 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 31, 2)
    
    cv2.adaptiveThreshold(cv2.bilateralFilter(img, 9, 75, 75), 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 31, 2)
    
    cv2.adaptiveThreshold(cv2.medianBlur(img, 3), 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 31, 2)
    

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

Если вы хотите проверить их, я делюсь ссылками с вами:

bkaankuguoglu
источник
почему мы конвертируем изображение в оттенки серого? Чтобы быть более конкретным, я видел в процессе обнаружения изображения, изображение сначала преобразуется в оттенки серого, а затем sobel-> MSER -> SWT. не могли бы вы уточнить это? Я новичок в области IP.
OnePunchMan
Насколько я понимаю, это зависит от алгоритма, некоторые могут не нуждаться в конвертации вообще. Думайте о пикселях как о нескольких цветовых значениях, хранящихся в цифровом виде - в случае RGB, красного, зеленого и синего. Когда пиксель преобразуется в черно-белую шкалу, тогда ваш алгоритм должен работать только с 2 измерениями вместо 3. Это дает очевидные преимущества в скорости при запуске вашего алгоритма на пикселях один за другим. Кроме того, некоторые могут также сказать, что легче устранить шум и обнаружить края на изображении, когда оно преобразуется в оттенки серого.
bkaankuguoglu
Спасибо за ответ. А что касается вашего блога, не могли бы вы написать один из них, КАК СОЗДАТЬ OCR ИЗ SCRATCH, ИСПОЛЬЗУЯ TESSERACT для нелатинского шрифта. Я ищу везде, все, что доступно правильно, не ясно.
OnePunchMan
16

Это несколько лет назад, но все еще может быть полезным.

Мой опыт показывает, что иногда помогает изменение размера изображения в памяти перед передачей его в tesseract.

Попробуйте разные режимы интерполяции. Пост https://stackoverflow.com/a/4756906/146003 мне очень помог.

Atmocreations
источник
15

На этом пути мне ОЧЕНЬ ПОЛЕЗНО помогли исходные коды проекта Capture2Text. http://sourceforge.net/projects/capture2text/files/Capture2Text/ .

Кстати: спасибо автору за то, что он поделился таким кропотливым алгоритмом.

Обратите особое внимание на файл Capture2Text \ SourceCode \ leptonica_util \ leptonica_util.c - в этом суть предварительной обработки изображения для этой утилиты.

Если вы запустите двоичные файлы, вы можете проверить преобразование изображения до / после процесса в папке Capture2Text \ Output \.

PS упомянутое решение использует Tesseract для OCR и Leptonica для предварительной обработки.

Мудрец
источник
1
Спасибо за инструмент Capture2Text. Он отлично решает все проблемы с распознаванием текста в моем проекте!
Ле Куанг Дуй
12

Java-версия для кода Сатьяраджа выше:

// Resize
public Bitmap resize(Bitmap img, int newWidth, int newHeight) {
    Bitmap bmap = img.copy(img.getConfig(), true);

    double nWidthFactor = (double) img.getWidth() / (double) newWidth;
    double nHeightFactor = (double) img.getHeight() / (double) newHeight;

    double fx, fy, nx, ny;
    int cx, cy, fr_x, fr_y;
    int color1;
    int color2;
    int color3;
    int color4;
    byte nRed, nGreen, nBlue;

    byte bp1, bp2;

    for (int x = 0; x < bmap.getWidth(); ++x) {
        for (int y = 0; y < bmap.getHeight(); ++y) {

            fr_x = (int) Math.floor(x * nWidthFactor);
            fr_y = (int) Math.floor(y * nHeightFactor);
            cx = fr_x + 1;
            if (cx >= img.getWidth())
                cx = fr_x;
            cy = fr_y + 1;
            if (cy >= img.getHeight())
                cy = fr_y;
            fx = x * nWidthFactor - fr_x;
            fy = y * nHeightFactor - fr_y;
            nx = 1.0 - fx;
            ny = 1.0 - fy;

            color1 = img.getPixel(fr_x, fr_y);
            color2 = img.getPixel(cx, fr_y);
            color3 = img.getPixel(fr_x, cy);
            color4 = img.getPixel(cx, cy);

            // Blue
            bp1 = (byte) (nx * Color.blue(color1) + fx * Color.blue(color2));
            bp2 = (byte) (nx * Color.blue(color3) + fx * Color.blue(color4));
            nBlue = (byte) (ny * (double) (bp1) + fy * (double) (bp2));

            // Green
            bp1 = (byte) (nx * Color.green(color1) + fx * Color.green(color2));
            bp2 = (byte) (nx * Color.green(color3) + fx * Color.green(color4));
            nGreen = (byte) (ny * (double) (bp1) + fy * (double) (bp2));

            // Red
            bp1 = (byte) (nx * Color.red(color1) + fx * Color.red(color2));
            bp2 = (byte) (nx * Color.red(color3) + fx * Color.red(color4));
            nRed = (byte) (ny * (double) (bp1) + fy * (double) (bp2));

            bmap.setPixel(x, y, Color.argb(255, nRed, nGreen, nBlue));
        }
    }

    bmap = setGrayscale(bmap);
    bmap = removeNoise(bmap);

    return bmap;
}

// SetGrayscale
private Bitmap setGrayscale(Bitmap img) {
    Bitmap bmap = img.copy(img.getConfig(), true);
    int c;
    for (int i = 0; i < bmap.getWidth(); i++) {
        for (int j = 0; j < bmap.getHeight(); j++) {
            c = bmap.getPixel(i, j);
            byte gray = (byte) (.299 * Color.red(c) + .587 * Color.green(c)
                    + .114 * Color.blue(c));

            bmap.setPixel(i, j, Color.argb(255, gray, gray, gray));
        }
    }
    return bmap;
}

// RemoveNoise
private Bitmap removeNoise(Bitmap bmap) {
    for (int x = 0; x < bmap.getWidth(); x++) {
        for (int y = 0; y < bmap.getHeight(); y++) {
            int pixel = bmap.getPixel(x, y);
            if (Color.red(pixel) < 162 && Color.green(pixel) < 162 && Color.blue(pixel) < 162) {
                bmap.setPixel(x, y, Color.BLACK);
            }
        }
    }
    for (int x = 0; x < bmap.getWidth(); x++) {
        for (int y = 0; y < bmap.getHeight(); y++) {
            int pixel = bmap.getPixel(x, y);
            if (Color.red(pixel) > 162 && Color.green(pixel) > 162 && Color.blue(pixel) > 162) {
                bmap.setPixel(x, y, Color.WHITE);
            }
        }
    }
    return bmap;
}
Фабиу Силва
источник
Какой у вас класс для Bitmap? Растровое изображение не найдено в Java (изначально в Android).
Мы Борг
Этот метод проходит исключение: вызвано: java.lang.IllegalArgumentException: y должно быть <bitmap.height ()
Натив
9

Документация Tesseract содержит некоторые подробные сведения о том, как улучшить качество распознавания текста с помощью этапов обработки изображений.

В некоторой степени Тессеракт автоматически применяет их. Также можно сказать Тессеракту написать промежуточное изображение для проверки, то есть проверить, насколько хорошо работает внутренняя обработка изображения (ищите tessedit_write_imagesв приведенной выше ссылке).

Что еще более важно, новая нейросетевая система в Tesseract 4 дает намного лучшие результаты распознавания текста - в целом и особенно для изображений с некоторым шумом. Это включено с помощью --oem 1, например, в:

$ tesseract --oem 1 -l deu page.png result pdf

(этот пример выбирает немецкий язык)

Таким образом, имеет смысл сначала проверить, насколько далеко вы продвинулись с новым режимом Tesseract LSTM, прежде чем применять некоторые пользовательские этапы предварительной обработки изображений.

maxschlepzig
источник
6

Адаптивный порог имеет важное значение, если освещение неравномерно по всему изображению. Моя предварительная обработка с использованием GraphicsMagic упоминается в этом посте: https://groups.google.com/forum/#!topic/tesseract-ocr/jONGSChLRv4

В GraphicsMagic также есть функция -lat для линейного адаптивного порога, которую я скоро опробую.

Другой метод порогового использования с использованием OpenCV описан здесь: http://docs.opencv.org/trunk/doc/py_tutorials/py_imgproc/py_thresholding/py_thresholding.html

rleir
источник
2
Ссылка OpenCV изменена. В документации OpenCV это Учебные
Установка
2

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

  1. Примените размытие к исходному изображению.
  2. Применить адаптивный порог.
  3. Применить эффект заточки.

И если все еще не получаются хорошие результаты, масштабируйте изображение до 150% или 200%.

Хамза Икбал
источник
2

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

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

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

3) Наличие строк: при выполнении сегментации слов или строк механизм OCR иногда также пытается объединить слова и строки вместе, обрабатывая, таким образом, неверный контент и, следовательно, давая неправильные результаты. Есть и другие проблемы, но это основные.

Это приложение после оптического распознавания символов является примером того, как для повышения точности распознавания можно применять некоторую предварительную обработку изображения и последующую обработку результатов OCR.

flamelite
источник
1

Распознавание текста зависит от множества факторов для получения качественного вывода. Вывод оптического сигнала в значительной степени зависит от качества входного изображения. Вот почему каждый механизм OCR предоставляет рекомендации относительно качества входного изображения и его размера. Эти рекомендации помогают движку OCR получать точные результаты.

Я написал подробную статью об обработке изображений в Python. Пожалуйста, перейдите по ссылке ниже для более подробного объяснения. Также добавлен исходный код Python для реализации этого процесса.

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

https://medium.com/cashify-engineering/improve-accuracy-of-ocr-using-image-preprocessing-8df29ec3a033

Бриеш Гупта
источник
2
Пожалуйста, добавьте ответ здесь как краткое изложение вашего блога. Так что даже если ссылка не работает, ответ не будет бесполезным.
18:18
0

вы можете сделать шумоподавление, а затем применить пороговое значение, но вы можете поэкспериментировать с конфигурацией OCR, изменив значения --psm и --oem

попробуй: --psm 5 --oem 2

Вы также можете посмотреть следующую ссылку для получения дополнительной информации здесь

Самер Маурья
источник