pemrosesan gambar untuk meningkatkan akurasi OCR tesseract

145

Saya telah menggunakan tesseract untuk mengubah dokumen menjadi teks. Kualitas dokumen berkisar liar, dan saya mencari kiat tentang jenis pengolahan gambar apa yang dapat meningkatkan hasil. Saya perhatikan bahwa teks yang sangat berpiksel - misalnya yang dihasilkan oleh mesin faks - sangat sulit untuk diproses oleh tesseract - mungkin semua tepi bergerigi pada karakter mengacaukan algoritma pengenalan bentuk.

Apa jenis teknik pemrosesan gambar yang akan meningkatkan akurasi? Saya telah menggunakan Gaussian blur untuk memuluskan gambar-gambar ter-pixellated dan melihat sedikit peningkatan, tetapi saya berharap ada teknik yang lebih spesifik yang akan menghasilkan hasil yang lebih baik. Ucapkan filter yang disetel ke gambar hitam putih, yang akan menghaluskan tepi yang tidak beraturan, diikuti dengan filter yang akan meningkatkan kontras untuk membuat karakter lebih berbeda.

Adakah tip umum untuk seseorang yang baru memulai pemrosesan gambar?

pengguna364902
sumber

Jawaban:

103
  1. memperbaiki DPI (jika perlu) 300 DPI adalah minimum
  2. memperbaiki ukuran teks (mis. 12 pt harus ok)
  3. mencoba untuk memperbaiki garis teks (teks deskew dan dewarp)
  4. coba perbaiki iluminasi gambar (mis. tidak ada bagian gelap gambar)
  5. binarize dan hapus noise gambar

Tidak ada baris perintah universal yang cocok untuk semua kasus (kadang-kadang Anda perlu mengaburkan dan mempertajam gambar). Tetapi Anda dapat mencoba TEXTCLEANER dari Fred's ImageMagick Scripts .

Jika Anda bukan penggemar command line, mungkin Anda dapat mencoba menggunakan opensource scantailor.sourceforge.net atau bookrestorer komersial .

pengguna898678
sumber
6
Dan ada panduan bergambar tentang bagaimana melakukan ini: code.google.com/p/tesseract-ocr/wiki/ImproveQuality
iljau
2
Catatan, skrip yang ditautkan tampaknya hanya untuk linux.
Zoran Pavlovic
1
Ini tidak benar - ini adalah skrip bash. Jika Anda telah menginstal bash dan ImageMagick itu akan berjalan di windows juga. Bash dapat diinstal sebagai bagian dari perangkat lunak lain yang bermanfaat misalnya git atau msys2 ...
user898678
6
@iljau Sejak pindah ke github. Halaman wiki ada di: github.com/tesseract-ocr/tesseract/wiki/ImproveQuality
hometoast
2
Tesseract docs pindah lagi, ke tesseract-ocr.github.io/tessdoc/ImproveQuality
Tidak ada yang tahu
73

Saya sama sekali bukan ahli OCR. Tapi saya minggu ini harus mengkonversi teks dari jpg.

Saya mulai dengan jpg piksel 445x747 berwarna. Saya segera mencoba tesseract pada ini, dan program hampir tidak mengubah apa pun. Saya kemudian pergi ke GIMP dan melakukan yang berikut. image> mode> grayscale image> scale image> filter 1191x2000 piksel> boost> unsharp mask dengan nilai radius = 6.8, jumlah = 2.69, threshold = 0 Saya kemudian disimpan sebagai jpg baru dengan kualitas 100%.

Tesseract kemudian dapat mengekstraksi semua teks menjadi file .txt

Gimp adalah temanmu.

John
sumber
11
+1 Saya mengikuti langkah-langkah Anda dan saya mendapat peningkatan besar. Terima kasih
tanggal
1
Saya juga memiliki kesan bahwa Tesseract berfungsi lebih baik jika Anda mengonversi input ke file TIFF dan memberikan Tesseract TIFF (daripada meminta Tesseract untuk melakukan konversi untuk Anda). ImageMagick dapat melakukan konversi untuk Anda. Ini adalah kesan anekdotal saya, tetapi saya belum mengujinya dengan cermat, jadi itu bisa salah.
DW
+1 Filter "topeng unsharp" benar-benar membuat hari saya menyenangkan. Langkah lain yang membantu saya: menggunakan alat "fuzzy selection" pilih latar belakang lalu tekan Del untuk memperketatnya
Davide
Saya terjebak pada masalah pemrosesan gambar ini sebelum tesseract recognition stackoverflow.com/questions/32473095/… Dapatkah Anda membantu saya di sini?
Hussain
nggak. Saya mencoba untuk membuatnya menjadi ukuran yang lebih besar, dan mengaturnya ke skala abu-abu sepertinya tidak ada yang memberi saya hasil yang positif. Sigh :( Periksa target ini: freesms4us.com/...
gumuruh
30

Tiga poin untuk meningkatkan keterbacaan gambar: 1) Ubah ukuran gambar dengan tinggi dan lebar variabel (kalikan 0,5 dan 1 dan 2 dengan tinggi dan lebar gambar). 2) Konversi gambar ke format Skala abu-abu (Hitam dan putih). 3) Hapus piksel noise dan buat lebih jelas (Saring gambar).

Lihat kode di bawah ini:

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

GAMBAR INPUT
GAMBAR INPUT

GAMBAR OUTPUT GAMBAR OUTPUT

Sathyaraj Palanisamy
sumber
Ya. Kita harus melewati parameter yang diperlukan untuk metode Ubah Ukuran, Ini akan mempreosikan ulang ukuran, operasi SetGrayscale dan RemoveNoise kemudian mengembalikan gambar output dengan keterbacaan yang lebih baik.
Sathyaraj Palanisamy
Mencoba pendekatan ini pada satu set file dan dibandingkan dengan hasil awal. Dalam beberapa kasus terbatas ini memberikan hasil yang lebih baik, sebagian besar ada sedikit penurunan kualitas teks keluaran. Jadi, itu tidak terlihat seperti solusi universal.
Bryn
Ini sebenarnya bekerja cukup baik untuk saya. Tentu saja ini memberikan titik awal untuk pra-pemrosesan gambar yang menghilangkan jumlah omong kosong yang Anda dapatkan dari Tesseract.
ses
22

Sebagai patokan, saya biasanya menerapkan teknik pra-pemrosesan gambar berikut ini menggunakan pustaka OpenCV:

  1. Menyimpan ulang gambar (disarankan jika Anda bekerja dengan gambar yang memiliki DPI kurang dari 300 dpi):

    img = cv2.resize(img, None, fx=1.2, fy=1.2, interpolation=cv2.INTER_CUBIC)
    
  2. Konversi gambar ke skala abu-abu:

    img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    
  3. Menerapkan pelebaran dan erosi untuk menghilangkan kebisingan (Anda dapat bermain dengan ukuran kernel tergantung pada kumpulan data Anda):

    kernel = np.ones((1, 1), np.uint8)
    img = cv2.dilate(img, kernel, iterations=1)
    img = cv2.erode(img, kernel, iterations=1)
    
  4. Menerapkan blur, yang dapat dilakukan dengan menggunakan salah satu dari baris berikut (masing-masing memiliki pro dan kontra, namun, median blur dan filter bilateral biasanya berkinerja lebih baik daripada gaussian blur.):

    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)
    

Saya baru-baru ini menulis panduan yang cukup sederhana untuk Tesseract tetapi seharusnya memungkinkan Anda untuk menulis skrip OCR pertama Anda dan menjernihkan beberapa rintangan yang saya alami ketika semuanya kurang jelas daripada yang saya inginkan dalam dokumentasi.

Jika Anda ingin memeriksanya, di sini saya membagikan tautan dengan Anda:

bkaankuguoglu
sumber
mengapa kita mengonversi gambar ke skala abu-abu? Untuk lebih spesifik, saya telah melihat dalam proses deteksi gambar, gambar pertama-tama dikonversi ke skala abu-abu, kemudian sobel-> MSER -> SWT. bisakah Anda menjelaskannya? Saya baru di bidang IP.
OnePunchMan
Mengenai pemahaman saya, itu tergantung pada algoritma, beberapa mungkin tidak perlu mengkonversi sama sekali. Pikirkan piksel sebagai beberapa nilai warna yang disimpan secara digital -dalam kasus RGB, merah, hijau, dan biru-. Ketika sebuah piksel dikonversikan ke skala B / W, maka algoritme Anda hanya perlu bekerja pada 2 dimensi, bukan 3. Ini hadir dengan keuntungan yang jelas dalam kecepatan saat menjalankan algoritme Anda pada piksel satu per satu. Lebih lanjut, beberapa orang mungkin juga mengatakan bahwa lebih mudah untuk menghilangkan noise dan mendeteksi tepi pada gambar ketika dikonversi ke skala abu-abu.
bkaankuguoglu
Terima kasih atas tanggapannya. Dan tentang blog Anda, bisakah Anda menulisnya di BAGAIMANA CARA MEMBANGUN OCR DARI SCRATCH MENGGUNAKAN TESSERACT untuk skrip non-Romawi. Saya telah mencari di mana-mana, semua yang tersedia benar tidak jelas.
OnePunchMan
16

Ini agak lalu tetapi mungkin masih berguna.

Pengalaman saya menunjukkan bahwa mengubah ukuran gambar dalam memori sebelum meneruskannya ke tesseract terkadang membantu.

Coba berbagai mode interpolasi. Posting https://stackoverflow.com/a/4756906/146003 banyak membantu saya.

Atmokasi
sumber
15

Apa yang sangat membantu saya dalam hal ini adalah kode sumber untuk proyek Capture2Text. http://sourceforge.net/projects/capture2text/files/Capture2Text/ .

BTW: Kudos kepada penulisnya karena berbagi algoritma yang begitu melelahkan.

Berikan perhatian khusus pada file Capture2Text \ SourceCode \ leptonica_util \ leptonica_util.c - itulah inti dari preprocession gambar untuk utilitas ini.

Jika Anda akan menjalankan binari, Anda dapat memeriksa transformasi gambar sebelum / setelah proses di folder Capture2Text \ Output \.

Solusi yang disebutkan PS menggunakan Tesseract untuk OCR dan Leptonica untuk preprocessing.

Orang bijak
sumber
1
Terima kasih atas alat Capture2Text. Ini dengan sempurna menyelesaikan semua masalah OCR di proyek saya!
Lê Quang Duy
12

Versi Java untuk kode Sathyaraj di atas:

// 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;
}
Fábio Silva
sumber
Apa kelas Anda untuk Bitmap? Bitmap tidak ditemukan di Java (Ada di Android asli).
Kami adalah Borg
Metode ini melalui pengecualian: Disebabkan oleh: java.lang.IllegalArgumentException: y harus <bitmap.height ()
Nativ
9

Dokumentasi Tesseract berisi beberapa detail bagus tentang cara meningkatkan kualitas OCR melalui langkah-langkah pemrosesan gambar.

Pada tingkat tertentu, Tesseract secara otomatis menerapkannya. Dimungkinkan juga untuk memberi tahu Tesseract untuk menulis gambar perantara untuk diperiksa, yaitu untuk memeriksa seberapa baik pemrosesan gambar internal bekerja (cari tessedit_write_imagesdalam referensi di atas).

Lebih penting lagi, sistem jaringan saraf baru di Tesseract 4 menghasilkan hasil OCR yang jauh lebih baik - secara umum dan terutama untuk gambar dengan noise. Ini diaktifkan dengan --oem 1, misalnya dalam:

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

(contoh ini memilih bahasa jerman)

Jadi, masuk akal untuk menguji terlebih dahulu seberapa jauh Anda mendapatkan dengan mode LSTM Tesseract baru sebelum menerapkan beberapa langkah pemrosesan gambar pra-pemrosesan kustom.

maxschlepzig
sumber
6

Ambang batas adaptif penting jika pencahayaan tidak merata di seluruh gambar. Preprocessing saya menggunakan GraphicsMagic disebutkan dalam posting ini: https://groups.google.com/forum/#!topic/tesseract-ocr/jONGSChLRv4

GraphicsMagic juga memiliki fitur -lat untuk Linear time Adaptive Threshold yang akan saya coba segera.

Metode thresholding lain menggunakan OpenCV dijelaskan di sini: http://docs.opencv.org/trunk/doc/py_tutorials/py_imgproc/py_thresholding/py_thresholding.pyml

tebing
sumber
2
Tautan OpenCV berubah. Dalam dokumentasi OpenCV itu adalah OpenCV-Python Tutorials> Pemrosesan Gambar di OpenCV> Image Thresholding
richk
2

Saya melakukan ini untuk mendapatkan hasil yang baik dari gambar yang memiliki teks yang tidak terlalu kecil.

  1. Oleskan blur ke gambar asli.
  2. Terapkan Ambang Adaptif.
  3. Terapkan efek Penajaman.

Dan jika masih belum mendapatkan hasil yang baik, skala gambar menjadi 150% atau 200%.

Hamza Iqbal
sumber
2

Membaca teks dari dokumen gambar menggunakan mesin OCR memiliki banyak masalah untuk mendapatkan akurasi yang baik. Tidak ada solusi pasti untuk semua kasus tetapi di sini ada beberapa hal yang harus dipertimbangkan untuk meningkatkan hasil OCR.

1) Adanya noise karena kualitas gambar yang buruk / elemen / gumpalan yang tidak diinginkan di wilayah latar belakang. Ini membutuhkan beberapa operasi pra-pemrosesan seperti penghilangan derau yang dapat dengan mudah dilakukan dengan menggunakan filter gaussian atau metode filter median normal. Ini juga tersedia di OpenCV.

2) Orientasi gambar yang salah: Karena orientasi yang salah, mesin OCR gagal untuk membagi garis dan kata-kata dalam gambar dengan benar yang memberikan akurasi terburuk.

3) Kehadiran garis: Sambil melakukan segmentasi kata atau garis, mesin OCR kadang-kadang juga mencoba menggabungkan kata-kata dan garis secara bersamaan dan dengan demikian memproses konten yang salah dan karenanya memberikan hasil yang salah. Ada masalah lain juga tetapi ini adalah masalah mendasar.

Aplikasi post OCR ini adalah contoh kasus di mana beberapa pre-preocessing dan pemrosesan post pada hasil OCR dapat diterapkan untuk mendapatkan akurasi OCR yang lebih baik.

flamelite
sumber
1

Pengenalan Teks tergantung pada berbagai faktor untuk menghasilkan output kualitas yang baik. Output OCR sangat tergantung pada kualitas gambar input. Inilah sebabnya mengapa setiap mesin OCR memberikan panduan mengenai kualitas gambar input dan ukurannya. Pedoman ini membantu mesin OCR untuk menghasilkan hasil yang akurat.

Saya telah menulis artikel terperinci tentang pemrosesan gambar dengan python. Silakan ikuti tautan di bawah ini untuk penjelasan lebih lanjut. Juga menambahkan kode sumber python untuk mengimplementasikan proses tersebut.

Silakan tulis komentar jika Anda memiliki saran atau ide yang lebih baik tentang topik ini untuk memperbaikinya.

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

Brijesh Gupta
sumber
2
Silakan tambahkan jawaban di sini sebagai ringkasan blog Anda. Sehingga bahkan jika tautannya mati, jawabannya tidak akan dianggap tidak berguna.
Nithin
0

Anda dapat melakukan pengurangan noise dan kemudian menerapkan ambang, tetapi Anda dapat bermain-main dengan konfigurasi OCR dengan mengubah nilai --psm dan --oem

coba: --psm 5 --oem 2

Anda juga dapat melihat tautan berikut untuk detail lebih lanjut di sini

maurya yang sama
sumber