Tesseract OCRは下付き文字と上付き文字を認識できますか?

Aug 24 2020

テキストフラグメントの添え字と上付き文字の一般的な認識に問題があります。

例-画像:

Tesseract 4.1.1を使用し、トレーニングデータは https://github.com/tesseract-ocr/tessdata_best。以下を除いて、多数のオプションにはデフォルト値がありました。

  • tessedit_create_hocr = 1(HOCRとして結果を取得するため)
  • hocr_font_info = 1(フォントサイズなどの追加のフォント情報を取得するため)
  • hocr_char_boxes = 1(文字ベースの結果を取得するため)

言語はengに設定されました。ページセグメンテーションモード3(PSM_AUTO_OSD)でも11(PSM_SPARSE_TEXT)でも12(PSM_SPARSE_TEXT_OSD)でも、添え字/上付き文字は正しく認識されませんでした。

出力では、サブ/サップフラグメントはすべて多かれ少なかれ間違っていました:

  • 「サブテキストサブは」「Subtextsu」として認識されています
  • 「Suptextサブは」として認識されている「Suptexts?」
  • 「P 0」「ポー」として認識されています
  • 「P 100」「P1go」として認識されています
  • " 2 + B 2 "として認識されている"+ bの?"

OCRにTesseractを使用する方法はありますか...?

  1. 下付き文字/上付き文字の処理を最適化する
  2. 認識された下付き文字/上付き文字に関する情報を取得します(hocr-output内-理想的には各文字に対して)

回答

1 MaS Sep 22 2020 at 06:52

このトピックに対する他の質問/回答で提案されているように画像の品質に取り組んでも、実際には何も変わりませんでした。

:最初はたTesseract-グーグル・ニュースグループからのこれら2つのリンクに続き、本当に訓練の問題と思われたリンク1とリンク2。

しかし、いくつかの実験を行った後、使用されたOEM_DEFAULT-OCRエンジンモードでは必要な情報が表示されないことがわかりました。私は問題の部分的な解決策を見つけました。sub / supに関するほとんどの情報を取得し、認識された文字はほとんどの場合正しいが、すべての文字についてではないため、部分的です。

OEM_TESSERACT_ONLY-OCRエンジンモード(=レガシーモード)とTess4Jによって提供されるいくつかのAPIメソッドを使用して、次のJavaテストクラスを思いつきました。

public class SubSupEvaluator {
    public void determineSubSupCharacters(BufferedImage image) {
        //1. initialize Tesseract and set image infos
        TessBaseAPI handle = TessAPI1.TessBaseAPICreate();
        try {
            int bpp = image.getColorModel().getPixelSize();
            int bytespp = bpp / 8;
            int bytespl = (int) Math.ceil(image.getWidth() * bpp / 8.0);
            TessBaseAPIInit2(handle, new File("./tessdata/").getAbsolutePath(), "eng", TessOcrEngineMode.OEM_TESSERACT_ONLY);
            TessBaseAPISetPageSegMode(handle, TessPageSegMode.PSM_AUTO_OSD);
            TessBaseAPISetImage(handle, ImageIOHelper.convertImageData(image), image.getWidth(), image.getHeight(), bytespp, bytespl);

            //2. start actual OCR run
            TessBaseAPIRecognize(handle, null);

            //3. iterate over the result character-wise
            TessResultIterator ri = TessBaseAPIGetIterator(handle);
            TessPageIterator pi = TessResultIteratorGetPageIterator(ri);
            TessPageIteratorBegin(pi);
            do {
                //determine character
                Pointer ptr = TessResultIteratorGetUTF8Text(ri, TessPageIteratorLevel.RIL_SYMBOL);
                String character = ptr.getString(0);
                TessDeleteText(ptr); //release memory

                //determine position information
                IntBuffer leftB = IntBuffer.allocate(1);
                IntBuffer topB = IntBuffer.allocate(1);
                IntBuffer rightB = IntBuffer.allocate(1);
                IntBuffer bottomB = IntBuffer.allocate(1);
                TessPageIteratorBoundingBox(pi, TessPageIteratorLevel.RIL_SYMBOL, leftB, topB, rightB, bottomB);

                //write info to console
                System.out.println(String.format("%s - position [%d %d %d %d], subscript: %b, superscript: %b", character, leftB.get(), topB.get(),
                    rightB.get(), bottomB.get(), TessAPI1.TessResultIteratorSymbolIsSubscript(ri) == TessAPI1.TRUE,
                    TessAPI1.TessResultIteratorSymbolIsSuperscript(ri) == TessAPI1.TRUE));
            } while (TessPageIteratorNext(pi, TessPageIteratorLevel.RIL_SYMBOL) == TessAPI1.TRUE);
        } finally {
            TessBaseAPIDelete(handle); //release memory
        }
    }
}

レガシーモードは、「通常の」トレーニングデータでのみ機能します。「-best」トレーニングデータを使用すると、エラーが発生します。

sancho.sReinstateMonicaCellio Sep 10 2020 at 07:50

このトピックに関する情報はほとんどありません。下付き/上付き文字認識を強化する1つのオプションは、(位置自体でなくても)画像をcv2/ pil(枕も)で前処理してから、それをテッセラクトすることです。

OCRを使用して画像内の添え字番号を検出する方法を参照してください。

関連(ただし、それ以外の場合は質問に答えない):

https://www.mail-archive.com/[email protected]/msg19434.html

https://github.com/tesseract-ocr/tesseract/blob/master/src/ccmain/superscript.cpp

mjpablo23 Nov 07 2020 at 02:43

tesseractに一文字を認識させることについてどう思いますか?

Tesseractは単一の文字を認識しません

オプション--psm10で試してみました

tesseract imTstg.png out5 --psm 10

しかし、それはうまくいかなかったようです。単一の文字を検出するためにyoloを実行することを考えています。