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


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

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

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

12 110

12 ответов:

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

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

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

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

Я начала с цветной, РГБ 445x747 пикселей в формате JPG. Я сразу же попробовал tesseract на этом, и программа почти ничего не преобразовала. Затем я вошел в GIMP и сделал следующее. изображение>режим>оттенки серого изображение > масштаб изображения>1191x2000 пикселей фильтры > усиление > нерезкая маска со значениями radius = 6.8, amount = 2.69, threshold = 0 Потом сохранять в JPG на 100% качество.

Тессеракт тогда смог извлечь весь текст в a .текстовый файл

Gimp-твой друг.

три точки для улучшения читаемости изображения: 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;
        }

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

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

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

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

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

Что было чрезвычайно полезно для меня на этом пути являются исходные коды для проекта Capture2Text. http://sourceforge.net/projects/capture2text/files/Capture2Text/.

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

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

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

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

версия 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;
}

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

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

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

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

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

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

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

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

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

(по состоянию на конец 2017 года Tesseract 4 еще не выпущен как стабильный, но версия для разработки используется)

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

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

    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 и прояснить некоторые препятствия, которые я испытал, когда все было менее ясно, чем я бы понравилось в документации.

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

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

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

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

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

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

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

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

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

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

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

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

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