обробка зображення для поліпшення точності тессеракта OCR


145

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

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

Якісь загальні поради для того, хто є початківцем у обробці зображень?

Відповіді:


103
  1. зафіксуйте DPI (за потреби) 300 DPI - мінімум
  2. виправити розмір тексту (наприклад, 12 пт має бути нормально)
  3. спробуйте виправити текстові рядки (утиснутий і деверфічний текст)
  4. спробуйте виправити підсвічування зображення (наприклад, відсутність темної частини зображення)
  5. зображення бінаризованого та знеструмленого шуму

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

Якщо ви не любитель командного рядка, можливо, ви можете спробувати скористатися opensource scantailor.sourceforge.net або комерційним книгарнею .


6
І ось ілюстрований посібник про те, як це зробити: code.google.com/p/tesseract-ocr/wiki/ImproveQuality
iljau

2
Зауважте, що пов'язаний скрипт видається лише Linux.
Зоран Павлович

1
Це неправда - це баш сценарій. Якщо ви встановили bash та ImageMagick, він також буде працювати на Windows. Bash можна було б встановити як частину іншого корисного програмного забезпечення, наприклад, git або msys2 ...
user898678

6
@iljau З моменту переїзду до github. Сторінка wiki знаходиться за адресою: github.com/tesseract-ocr/tesseract/wiki/ImproveQuality
hometoast

2
Документи Tesseract знову перейшли на tesseract-ocr.github.io/tessdoc/ImproveQuality
Ніхто

73

Я аж ніяк не експерт з ОКР. Але мені цього тижня довелося перетворити текст із jpg.

Я розпочав з кольорового, RGB 445x747 пікселів jpg. Я одразу спробував tesseract на цьому, і програма майже нічого не перетворила. Потім я пішов у GIMP і зробив наступне. зображення> режим> зображення в градаціях сірого> масштабне зображення> фільтри 1191x2000 пікселів> посилення> нерізка маска зі значеннями радіуса = 6,8, сума = 2,69, поріг = 0 Потім я зберегла як новий jpg при 100% якості.

Тоді Tesseract зміг витягти весь текст у файл .txt

Гімп - твій друг.


11
+1 Я стежив за вашими кроками, і я значно покращився. Дякую
onof

1
У мене також складається враження, що Tesseract працює краще, якщо ви перетворите вхід у файл TIFF і надаєте Tesseract TIFF (а не просите Tesseract зробити перетворення для вас). ImageMagick може зробити перетворення за вас. Це моє анекдотичне враження, але я не перевіряв його ретельно, тому це може бути неправильним.
DW

+1 Фільтр "нерізка маска" дійсно зробив мій день. Ще один крок , який допоміг мені: з допомогою «нечіткого вибору» інструмент вибору фону , потім натисніть Del для wightening це
Давіде

Я застряг у цьому питанні обробки зображень перед розпізнаванням 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, він буде попередньо змінювати розмір, 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 та усунути деякі перешкоди, які я зазнав, коли все було менш зрозумілим, ніж мені хотілося б у документації.

Якщо ви хочете перевірити їх, тут я ділюсь посиланнями з вами:


чому ми перетворюємо зображення в сірі кольори? Якщо бути більш конкретним, я бачив, що в процесі виявлення зображень зображення спочатку перетворюється на сіру гаму, потім на Sobel-> MSER -> SWT. Ви можете, будь ласка, розробити це? Я новачок у галузі IP.
OnePunchMan

Наскільки я розумію, це залежить від алгоритму, який може взагалі не потребувати перетворення. Розгляньте пікселі як кілька кольорових значень, збережених у цифровому форматі - у випадку RGB, червоного, зеленого та синього кольорів. Коли піксель перетворюється на шкалу B / W, то ваш алгоритм повинен працювати лише на 2 виміри, а не на 3. Це забезпечує очевидні переваги у швидкості, коли алгоритм працює на пікселях по одному. Крім того, деякі можуть також сказати, що легше видалити шум і виявити краї зображення на малюнку, коли він перетворений у відтінки сірого.
bkaankuguoglu

Дякую за відповідь. А щодо свого блогу, будь ласка, напишіть його про те, ЯК БУДІВИТЬ ОКР З ВІДКРИТТЯ, ВИКОРИСТОВУЮЩЕ ТЕСЕРАКТ для неримського сценарію. Я шукаю всюди, все, що доступно правильно, не зрозуміло.
OnePunchMan

16

Це дещо тому, але все ще може бути корисним.

Мій досвід показує, що іноді допомагає зміна розміру зображення в пам'яті перед передачею його тессеракту.

Спробуйте різні режими інтерполяції. Допис https://stackoverflow.com/a/4756906/146003 мені дуже допоміг.


15

Що було НАЙКРИЧНО ДОПОМОГО на цьому шляху - це вихідні коди проекту Capture2Text. http://sourceforge.net/projects/capture2text/files/Capture2Text/ .

BTW: Кудос - його автор для спільного використання такого кропіткого алгоритму.

Зверніть особливу увагу на файл Capture2Text \ SourceCode \ leptonica_util \ leptonica_util.c - ось суть попередньої обробки зображень для цієї утиліти.

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

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


1
Дякуємо за інструмент Capture2Text. Це прекрасно вирішує всі питання OCR в моєму проекті!
Lê Quang Duy

12

Версія Java для коду Sathyaraj вище:

// 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 ()
Nativ

9

Документація Tesseract містить хороші подробиці про те, як покращити якість OCR за допомогою кроків обробки зображень.

Певною мірою Tesseract автоматично застосовує їх. Можна також сказати Tesseract написати проміжне зображення для огляду, тобто перевірити, наскільки добре працює внутрішня обробка зображень (пошук tessedit_write_imagesу наведеній вище посилання).

Що ще важливіше, нова система нейронної мережі в Tesseract 4 дає набагато кращі результати OCR - в цілому і особливо для зображень з деяким шумом. Він увімкнено за допомогою --oem 1, наприклад, як у:

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

(цей приклад вибирає німецьку мову)

Таким чином, є сенс спершу перевірити, наскільки далеко ви дістанетесь за допомогою нового режиму LSTM Tesseract, перш ніж застосовувати деякі спеціальні етапи обробки зображень.


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


2
Посилання OpenCV змінено. У документації на OpenCV це підручники OpenCV-Python> Обробка зображень у OpenCV> Поріг зображення
Richk

2

Я зробив це, щоб отримати хороші результати із зображення, яке має не дуже маленький текст.

  1. Нанесіть розмиття на оригінальне зображення.
  2. Застосувати адаптивний поріг.
  3. Застосовуйте ефект різкості.

І якщо все-таки не отримують хороших результатів, масштабуйте зображення до 150% або 200%.


2

Читання тексту із графічних документів за допомогою будь-якого двигуна OCR має багато питань, щоб отримати хорошу точність. Немає фіксованого рішення для всіх випадків, але ось кілька речей, які слід враховувати для покращення результатів ОКР.

1) Наявність шуму через низьку якість зображення / небажані елементи / краплі у фоновому регіоні. Для цього потрібні такі операції попередньої обробки, як видалення шуму, які можна легко виконати за допомогою гауссового фільтра або звичайних методів медіанного фільтра. Вони також доступні у OpenCV.

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

3) Наявність рядків: виконуючи сегментацію слів або рядків, система OCR іноді також намагається об'єднати слова та рядки разом, обробляючи таким чином неправильний вміст і, таким чином, даючи неправильні результати. Є й інші питання, але це основні.

Ця програма OCR після публікації є прикладом, коли для покращення точності OCR можна застосувати деяку попередню обробку зображення та обробку після результатів OCR.


1

Розпізнавання тексту залежить від різноманітних факторів, які дозволяють отримати якісний вихід. Вихід OCR сильно залежить від якості вхідного зображення. Ось чому кожен двигун OCR надає рекомендації щодо якості вхідного зображення та його розміру. Ці вказівки допомагають двигуну OCR отримати точні результати.

Я написав докладну статтю з обробки зображень в python. Будь ласка, перейдіть за посиланням нижче для отримання додаткових пояснень. Також додано вихідний код python для реалізації цього процесу.

Будь ласка, напишіть коментар, якщо у вас є пропозиція чи краща ідея на цю тему, щоб покращити її.

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


2
Будь ласка, додайте тут відповідь як резюме свого блогу. Так що навіть якщо посилання мертве, відповідь не буде видаватися марною.
Нітін

0

Ви можете зробити зниження шуму, а потім застосувати порогове значення, але ви можете пограти з конфігурацією OCR, змінивши значення --psm і --oem

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

ви також можете переглянути наступне посилання для отримання детальної інформації тут

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.