tesseract OCR doğruluğunu artırmak için görüntü işleme


147

Belgeleri metne dönüştürmek için tesseract kullanıyorum. Belgelerin kalitesi çılgınca değişiyor ve ne tür görüntü işlemenin sonuçları iyileştirebileceğine dair ipuçları arıyorum. Yüksek pikselli metnin - örneğin faks makineleri tarafından üretilen - tesseratın işlenmesi için özellikle zor olduğunu fark ettim - muhtemelen karakterlerin tüm bu pürüzlü kenarları şekil tanıma algoritmalarını karıştırıyor.

Ne tür görüntü işleme teknikleri doğruluğu geliştirir? Pikselli görüntüleri yumuşatmak için bir Gauss bulanıklığı kullanıyorum ve bazı küçük iyileştirmeler gördüm, ancak daha iyi sonuçlar verecek daha spesifik bir teknik olduğunu umuyorum. Siyah beyaz görüntülere ayarlanmış, düzensiz kenarları yumuşatan ve karakterleri daha belirgin hale getirmek için kontrastı artıracak bir filtre söyleyin.

Görüntü işlemede acemi olan biri için genel ipuçları var mı?

Yanıtlar:


106
  1. DPI düzelt (gerekirse) 300 DPI minimumdur
  2. metin boyutunu düzeltin (örneğin 12 punto tamam olmalıdır)
  3. metin satırlarını düzeltmeye çalışın (eğrilik düzeltme ve çiğneme metni)
  4. görüntü aydınlatmasını düzeltmeye çalışın (örneğin görüntünün karanlık kısmı yok)
  5. ikilileştir ve parazit giderme görüntüsü

Tüm durumlara uyan evrensel bir komut satırı yoktur (bazen görüntüyü bulanıklaştırmanız ve keskinleştirmeniz gerekir). Ancak Fred'in ImageMagick Script'lerinden TEXTCLEANER'ı deneyebilirsiniz .

Komut satırının hayranı değilseniz, belki açık kaynak scantailor.sourceforge.net veya ticari bookrestorer'ı kullanmayı deneyebilirsiniz .


6
Ve bunun nasıl yapılacağı ile ilgili resimli kılavuz var: code.google.com/p/tesseract-ocr/wiki/ImproveQuality
iljau

2
Bağlantılı komut dosyasının yalnızca linux olarak göründüğünü unutmayın.
Zoran Pavlovic

1
Bu doğru değil - bu bir bash betiğidir. Eğer bash ve ImageMagick yüklediyseniz, pencerelerde de çalışır. Bash diğer yararlı yazılımların bir parçası olarak kurulabilir, örneğin git veya msys2 ...
user898678

6
@iljau Github'a taşındığından beri. wiki sayfası: github.com/tesseract-ocr/tesseract/wiki/ImproveKalite
hometoast


73

Hiçbir şekilde bir OCR uzmanı değilim. Ama bu hafta metni bir jpg'den dönüştürmem gerekiyordu.

Renklendirilmiş RGB 445x747 piksel jpg ile başladım. Hemen bu konuda tesseract denedim ve program neredeyse hiçbir şeyi dönüştürmedi. Sonra GIMP'e girdim ve aşağıdakileri yaptım. image> mode> gri tonlamalı görüntü> ölçekli görüntü> 1191x2000 piksel filtre> Enhanc> yarıçap = 6,8, miktar = 2,69, eşik = 0 değerlerine sahip maskeyi kaldırın ve sonra% 100 kalitede yeni bir jpg olarak kaydettim.

Daha sonra Tesseract tüm metni bir .txt dosyasına çıkarabildi

Gimp senin arkadaşın.


11
+1 Adımlarını takip ettim ve büyük bir gelişme elde ettim. Teşekkürler
onof

1
Ayrıca, girişi bir TIFF dosyasına dönüştürürseniz ve Tesseract'a TIFF'yi verirseniz (Tesseract'tan sizin için dönüşüm yapmasını istemekten ziyade) Tesseract'ın daha iyi çalıştığı izlenimine sahibim. ImageMagick sizin için dönüştürme yapabilir. Bu benim anekdot izlenimim, ama dikkatlice test etmedim, bu yüzden yanlış olabilir.
DW

+1 "Keskinliği Azaltma Maskesi" filtresi gerçekten günümü yaptı. Bana yardımcı olan başka bir adım: "bulanık seçim" aracını kullanarak arka planı seçin ve hafifletmek için Del'e basın
Davide

Tesseract tanıma önce bu görüntü işleme sorunu sıkışmış stackoverflow.com/questions/32473095/… Bana burada yardımcı olabilir misiniz?
Hussain

Hayır. daha büyük boyutta yapmaya çalıştım ve gri tonlamaya ayarladım, hiçbir şey bana olumlu sonuç vermiyor. İç geçirme
gumuruh

30

Görüntünün okunabilirliğini artırmak için üç nokta: 1) Görüntüyü değişken yükseklik ve genişlikle yeniden boyutlandırın (görüntü yüksekliği ve genişliği ile 0,5 ve 1 ve 2'yi çarpın). 2) Görüntüyü Gri tonlama formatına dönüştürün (Siyah beyaz). 3) Gürültü piksellerini kaldırın ve daha net hale getirin (Görüntüyü filtreleyin).

Aşağıdaki koda bakın:

//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;
        }

GİRİŞ GÖRÜNTÜ
GİRİŞ GÖRÜNTÜ

ÇIKTI GÖRÜNTÜ ÇIKTI GÖRÜNTÜ


Evet. Yeniden boyutlandırma yöntemi için gerekli parametreyi geçmeliyiz, yeniden boyutlandırma, SetGrayscale ve RemoveNoise işlemini önceden işler ve daha iyi okunabilirlik ile çıktı görüntüsünü döndürür.
Sathyaraj Palanisamy

Bu yaklaşımı bir dizi dosyada denedi ve ilk sonuçla karşılaştırıldı. Bazı sınırlı durumlarda daha iyi sonuç verir, çoğunlukla çıktı metni kalitesinde hafif bir düşüş oldu. Yani, evrensel bir çözüm gibi görünmüyor.
Bryn

Bu aslında benim için oldukça iyi sonuç verdi. Elbette, Tesseract'tan geri aldığınız anlamsızlık miktarını kaldıran görüntü ön işleme için bir başlangıç ​​noktası verir.
ses

22

Genel bir kural olarak, genellikle OpenCV kütüphanesini kullanarak aşağıdaki görüntü ön işleme tekniklerini uygularım:

  1. Görüntüyü yeniden ölçeklendirme (DPI'si 300 dpi'den düşük görüntülerle çalışıyorsanız önerilir):

    img = cv2.resize(img, None, fx=1.2, fy=1.2, interpolation=cv2.INTER_CUBIC)
    
  2. Görüntüyü gri tonlamaya dönüştürme:

    img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    
  3. Gürültüyü gidermek için dilatasyon ve erozyon uygulama (veri setinize bağlı olarak çekirdek boyutuyla oynayabilirsiniz):

    kernel = np.ones((1, 1), np.uint8)
    img = cv2.dilate(img, kernel, iterations=1)
    img = cv2.erode(img, kernel, iterations=1)
    
  4. Aşağıdaki satırlardan birini kullanarak yapılabilen bulanıklık uygulamak (her birinin artıları ve eksileri vardır, ancak medyan bulanıklık ve çift filtre genellikle gauss bulanıklığından daha iyi performans gösterir):

    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)
    

Kısa bir süre önce Tesseract için oldukça basit bir rehber yazdım, ancak ilk OCR betiğinizi yazmanıza ve belgelerde sevdiğimden daha az net olduğunda yaşadığım bazı engelleri temizlemenize izin vermelidir.

Onları kontrol etmek isterseniz, burada bağlantıları sizinle paylaşıyorum:


görüntüyü neden gri skalaya dönüştürüyoruz? Daha spesifik olmak gerekirse, görüntü algılama sürecinde gördüm, görüntü önce gri skalaya, sonra sobel-> MSER -> SWT'ye dönüştürülür. lütfen biraz açar mısın? IP alanında yeniyim.
OnePunchMan

Anladığım kadarıyla, algoritmaya bağlı, bazılarının dönüştürülmesi gerekmeyebilir. Pikselleri, RGB, kırmızı, yeşil ve mavi durumunda dijital olarak saklanan birkaç renk değeri olarak düşünün. Bir piksel S / B ölçeğine dönüştürüldüğünde, algoritmanızın 3 yerine yalnızca 2 boyutta çalışması gerekir. Bu, algoritmanızı pikseller üzerinde tek tek çalıştırırken belirgin bir hız avantajı ile birlikte gelir. Ayrıca, bazıları ayrıca gri tonlamaya dönüştürüldüğünde resimdeki parazitleri gidermenin ve kenarları algılamanın daha kolay olduğunu söyleyebilir.
bkaankuguoglu

Cevap için teşekkürler. Ve blogunuz hakkında, lütfen Roman olmayan komut dosyası için TESSERACT KULLANAN SCRATCH'DAN OCR NASIL YAPILIR yazabilirsiniz? Her yerde arama yapıyorum, mevcut olan her şey net değil.
OnePunchMan

16

Bu biraz önce ama yine de faydalı olabilir.

Deneyimlerim, görüntüyü tesserat'a geçmeden önce bellekte yeniden boyutlandırmanın bazen yardımcı olduğunu gösteriyor.

Farklı enterpolasyon modlarını deneyin. Https://stackoverflow.com/a/4756906/146003 gönderi bana çok yardımcı oldu.


15

Bu şekilde bana son derece YARDIMCI olan şey, Capture2Text projesinin kaynak kodlarıdır. http://sourceforge.net/projects/capture2text/files/Capture2Text/ .

BTW: Böyle bir özenli algoritmayı paylaştığı için yazar Kudüs.

Capture2Text \ SourceCode \ leptonica_util \ leptonica_util.c dosyasına özellikle dikkat edin - bu yardımcı program için görüntü önişleminin özü budur.

İkili dosyaları çalıştıracaksanız, Capture2Text \ Output \ klasöründeki işlemden önce / sonra görüntü dönüşümünü kontrol edebilirsiniz.

PS bahsedilen çözüm OCR için Tesseract ve ön işleme için Leptonica kullanır.


1
Capture2Text aracı için teşekkür ederiz. Projemdeki tüm OCR sorunlarını mükemmel bir şekilde çözüyor!
Lê Quang Duy

12

Yukarıdaki Sathyaraj kodu için Java sürümü:

// 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 için sınıfınız nedir? Bitmap Java'da bulunamadı (Android'de yerel olarak).
Borg

Bu yöntem bir istisna oluşturur: Neden: java.lang.IllegalArgumentException: y, <bitmap.height ()
Nativ

9

Tesseract belgeleri OCR kalitesinin nasıl artırılacağı hakkında bazı iyi detaylar içerir görüntü işleme adımları yoluyla .

Bir dereceye kadar, Tesseract bunları otomatik olarak uygular. Tesseract'a inceleme için bir ara görüntü yazmasını, yani dahili görüntü işlemenin ne kadar iyi çalıştığını kontrol etmesini söylemek mümkündür ( tessedit_write_imagesyukarıdaki referansta arayın ).

Daha da önemlisi, Tesseract 4'teki yeni sinir ağı sistemi , genel olarak ve özellikle biraz gürültülü görüntüler için çok daha iyi OCR sonuçları verir. Şununla etkinleştirilir --oem 1, örneğin:

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

(bu örnek Almanca dilini seçer)

Bu nedenle, bazı özel ön işleme görüntü işleme adımlarını uygulamadan önce yeni Tesseract LSTM moduyla ne kadar ilerlediğinizi test etmek mantıklıdır.


6

Aydınlatma görüntü boyunca eşit değilse, uyarlamalı eşikleme önemlidir. GraphicsMagic kullanarak önişlemim şu yayında belirtilmiştir: https://groups.google.com/forum/#!topic/tesseract-ocr/jONGSChLRv4

GraphicsMagic ayrıca, yakında deneyeceğim Doğrusal zaman Adaptive Eşiği için -lat özelliğine sahiptir.

OpenCV kullanarak başka bir eşikleme yöntemi burada açıklanmıştır: http://docs.opencv.org/trunk/doc/py_tutorials/py_imgproc/py_thresholding/py_thresholding.html


2
OpenCV bağlantısı değiştirildi. OpenCV belgelerinde OpenCV-Python Öğreticileri>
OpenCV'de

2

Bunları çok küçük olmayan bir görüntüden iyi sonuçlar almak için yaptım.

  1. Orijinal görüntüye bulanıklık uygulayın.
  2. Uyarlamalı Eşiği uygulayın.
  3. Bileme efekti uygulayın.

Yine de iyi sonuçlar alamıyorsanız, resmi% 150 veya% 200 olarak ölçeklendirin.


2

Herhangi bir OCR motoru kullanarak görüntü belgelerinden metin okumak, iyi bir doğruluk elde etmek için birçok soruna sahiptir. Tüm vakalar için sabit bir çözüm yoktur, ancak burada OCR sonuçlarını iyileştirmek için düşünülmesi gereken birkaç şey vardır.

1) Arka plan bölgesinde görüntü kalitesi / istenmeyen elemanlar / lekeler nedeniyle parazit var. Bu, gauss filtresi veya normal medyan filtre yöntemleri kullanılarak kolayca yapılabilen gürültü giderme gibi bazı ön işleme işlemlerini gerektirir. Bunlar OpenCV'de de mevcuttur.

2) Görüntünün yanlış yönü: Yanlış yönlendirme nedeniyle OCR motoru görüntüdeki satırları ve kelimeleri doğru şekilde bölümlere ayıramaz ve bu da en kötü doğruluğu verir.

3) Satırların varlığı: Kelime veya satır segmentasyonu yaparken bazen OCR motoru da kelimeleri ve satırları birleştirmeye ve böylece yanlış içeriği işlemeye ve dolayısıyla yanlış sonuçlar vermeye çalışır. Başka konular da var ama bunlar temel konular.

Bu OCR sonrası uygulama , daha iyi OCR doğruluğu elde etmek için OCR sonucu üzerinde bazı görüntü önişlemi ve son işlemenin uygulanabileceği örnek bir durumdur.


1

Metin Tanıma, iyi kalitede çıktı üretmek için çeşitli faktörlere bağlıdır. OCR çıkışı büyük ölçüde giriş görüntüsünün kalitesine bağlıdır. Bu nedenle her OCR motoru, giriş görüntüsünün kalitesi ve boyutu ile ilgili yönergeler sağlar. Bu yönergeler OCR motorunun doğru sonuçlar üretmesine yardımcı olur.

Python'da görüntü işleme hakkında ayrıntılı bir makale yazdım. Daha fazla açıklama için lütfen aşağıdaki bağlantıyı takip edin. Ayrıca bu işlemi uygulamak için python kaynak kodunu ekledi.

Geliştirmek için bu konuda bir öneriniz veya daha iyi bir fikriniz varsa lütfen bir yorum yazın.

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


2
Lütfen blogunuza özet olarak bir cevap ekleyin. Böylece bağlantı ölü olsa bile cevap işe yaramaz hale gelmez.
Nithin

0

parazit azaltma yapabilir ve ardından eşikleme uygulayabilirsiniz, ancak --psm ve --oem değerlerini değiştirerek OCR yapılandırmasıyla oynayabilirsiniz

deneyin: --psm 5 --oem 2

Ayrıca daha detaylı bilgi için aşağıdaki bağlantıya bakabilir burada

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.