web-dev-qa-db-ja.com

PDF用のバッチOCRプログラム

これは以前に尋ねられたことがありますが、答えが私に役立つかどうかは本当にわかりません。これが私の問題です:私はたくさんの(10,000かそこらの)pdfファイルを手に入れました。いくつかはAdobeの印刷機能を使用して保存されたテキストファイルでした(したがって、それらのテキストは完璧であり、私はそれらを台無しにする危険を冒したくありません)。また、スキャンされた画像もあります(したがって、テキストがなく、OCRを使用する必要があります)。ファイルは同じディレクトリにあり、どれがどれかわかりません。最終的には、それらを.txtファイルに変換してから、文字列処理を実行したいと思います。したがって、可能な限り最も正確なOCRが必要です。

人々が推奨しているようです:

  1. Adobe pdf(私はこれのライセンスされたコピーを持っていないので...さらにABBYYファインリーダーか何かがより良いなら、私がそれを使わないのならなぜそれを支払うのか)
  2. ocropus(これの使い方がわからない)、
  3. Tesseract(1995年は素晴らしかったようですが、もっと正確なものがあるかどうかはわかりませんが、ネイティブでpdfを実行しないため、TIFFに変換する必要があります。これは、私が持っていないため、独自の問題を引き起こします。ライセンスされたacrobatのコピーなので、10,000個のファイルをtiffに変換する方法がわかりません。さらに、10,000個の30ページのドキュメントを30,000個の個別のtiff画像に変換したくありません)。
  4. wowocr
  5. pdftextstream(2009年から)
  6. ABBYY FineReader(どうやらその$$$ですが、これが大幅に優れている場合、つまりより正確なocrがある場合は、これを行うために600ドルを費やします)。

また、私はプログラミングの初心者なので、何かをする方法を学ぶのに数週間かかる場合は、$$$を支払うほうがいいです。入力/経験のためのThx。

ところで、私はLinux Mint 1164ビットおよび/またはWindows764ビットを実行しています。

他のスレッドは次のとおりです。

まだOCRされていないバッチOCRPDF

オープンソースOCR

OCRを使用したPDFテキスト抽出アプローチ

https://superuser.com/questions/107678/batch-ocr-for-many-pdf-files-not-already-ocred

17
Aquat33nfan

あなたの誤解のいくつかをまっすぐにするために...

"私はacrobatのライセンスされたコピーを持っていないので、10,000ファイルをtiffに変換する方法がわかりません。"

無料(自由のように)と無料(ビールのように)Ghostscriptの助けを借りてPDFをTIFFに変換することができます。 LinuxMintまたはWindows7で実行する場合は、次のように選択します。Linuxのコマンドラインは次のとおりです。

gs \
 -o input.tif \
 -sDEVICE=tiffg4 \
  input.pdf

"10,000個の30ページのドキュメントを30,000個の個別のtiff画像に変換したくない"

「マルチページ」TIFFを簡単に作成できます。上記のコマンドは、G4(fax tiff)フレーバーのそのようなTIFFを作成します。代わりに単一ページのTIFFが必要な場合は、次のコマンドを変更できます。

gs \
 -o input_page_%03d.tif \
 -sDEVICE=tiffg4 \
  input.pdf

出力ファイル名の%03d部分は、一連の001002003などに自動的に変換されます。

警告:

  1. tiffg4出力デバイスのデフォルトの解像度は204x196dpiです。あなたはおそらくより良い値が欲しいでしょう。 720 dpiを取得するには、コマンドラインに-r720x720を追加する必要があります。
  2. また、Ghostscriptインストールでデフォルトのメディアサイズとしてletterが使用されている場合は、それを変更することをお勧めします。 -gXxYを使用して、デバイスポイントのwidthxheightを設定できます。したがって、横向きでISO A4出力ページの寸法を取得するには、-g8420x5950パラメーターを追加できます。

したがって、これら2つのパラメーターを制御して、縦向きでA4に720 dpiの出力を生成する完全なコマンドは、次のようになります。

gs \
 -o input.tif \
 -sDEVICE=tiffg4 \
 -r720x720 \
 -g5950x8420 \
  input.pdf
7
Kurt Pfeifle

私は自分の質問に答えることによって貢献しようと考えました(自分のためにいくつかの素敵なコードを書いたので、このボードの助けがなければそれを行うことはできませんでした)。 pdfファイルをunix(まあ、私にとってはosx)でキャットすると、テキストを含むpdfファイルには(文字列として、ただし他のテキストと混合された)「フォント」という単語が含まれます。 fileは、表示するフォントをAdobeに指示します。

Bashのcatコマンドは、python( 'w'または 'r'または 'aの代わりにファイルを開くときに' rb 'モードを使用)でバイナリモードでファイルを読み取るのと同じ出力を持っているようです')。したがって、テキストを含むすべてのpdfファイルのバイナリ出力に「Font」という単語が含まれ、画像のみのファイルは含まれないと想定しています。これが常に当てはまる場合、このコードはすべてのリストを作成します。テキストを含む単一のディレクトリ内のpdfファイルと、画像のみを含むファイルの個別のリスト。各リストを個別の.txtファイルに保存し、bashのコマンドを使用してpdfファイルを適切なフォルダーに移動できます。

それらを独自のフォルダーに入れたら、images_onlyフォルダー内のpdfファイルのみでバッチocrソリューションを実行できます。私はまだそこまで到達していません(明らかに)。

    import os, re

    #path is the directory with the files, other 2 are the names of the files you will store your lists in

    path = 'C:/folder_with_pdfs'
    files_with_text = open('files_with_text.txt', 'a')
    image_only_files = open('image_only_files.txt', 'a')


    #have os make a list of all files in that dir for a loop
    filelist = os.listdir(path)

    #compile regular expression that matches "Font"
    mysearch = re.compile(r'.*Font.*', re.DOTALL)

    #loop over all files in the directory, open them in binary ('rb'), search that binary for "Font"
    #if they have "Font" they have text, if not they don't
    #(pdf does something to understand the Font type and uses this Word every time the pdf contains text)
    for pdf in filelist:
        openable_file = os.path.join(path, pdf)
        cat_file = open(openable_file, 'rb')
        usable_cat_file = cat_file.read()
        #print usable_cat_file
        if mysearch.match(usable_cat_file):
            files_with_text.write(pdf + '\n')
        else:
            image_only_files.write(pdf + '\n')

ファイルを移動するために、bashシェルで次のコマンドを入力しました。

cat files_with_text.txt | while read i; do mv $i Volumes/hard_drive_name/new_destination_directory_name; done 

また、上記のpythonコードを再実行しませんでした。手動で編集しただけなので、バグがある可能性があります、Idk。

5

これは興味深い問題です。 .NETのWindowsで作業する場合は、 dotImage でこれを行うことができます(免責事項、私はAtalasoftで働いており、ほとんどのOCRエンジンコードを記述しています)。問題を細かく分割してみましょう。最初は、すべてのPDFを反復処理することです。

string[] candidatePDFs = Directory.GetFiles(sourceDirectory, "*.pdf");
PdfDecoder decoder = new PdfDecoder();

foreach (string path in candidatePDFs) {
    using (FileStream stm = new FileStream(path, FileMode.Open)) {
        if (decoder.IsValidFormat(stm)) {
            ProcessPdf(path, stm);
        }
    }
}

これにより、.pdfで終わるすべてのファイルのリストが取得され、ファイルが有効なpdfの場合は、ルーチンを呼び出して処理します。

public void ProcessPdf(string path, Stream stm)
{
    using (Document doc = new Document(stm)) {
        int i=0;
        foreach (Page p in doc.Pages) {
            if (p.SingleImageOnly) {
                ProcessWithOcr(path, stm, i);
            }
            else {
                ProcessWithTextExtract(path, stm, i);
            }
            i++;
        }
    }
}

これにより、ファイルがDocumentオブジェクトとして開かれ、各ページが画像のみであるかどうかが尋ねられます。その場合はページをOCRし、そうでない場合はテキストを抽出します。

public void ProcessWithOcr(string path, Stream pdfStm, int page)
{
    using (Stream textStream = GetTextStream(path, page)) {
        PdfDecoder decoder = new PdfDecoder();
        using (AtalaImage image = decoder.Read(pdfStm, page)) {
            ImageCollection coll = new ImageCollection();
            coll.Add(image);
            ImageCollectionImageSource source = new ImageCollectionImageSource(coll);
            OcrEngine engine = GetOcrEngine();
            engine.Initialize();
            engine.Translate(source, "text/plain", textStream);
            engine.Shutdown();
        }
    }
}

これは、PDFページを画像にラスタライズし、engine.Translateに適した形式に変換します。これは、厳密にはこの方法で行う必要はありません。 Recognizeを呼び出してAtalaImageからエンジンからOcrPageオブジェクトを取得しますが、構造をループしてテキストを書き出すのはクライアントコード次第です。

GetOcrEngine()を省略していることに注意してください。クライアントで使用できる4つのOCRエンジン(Tesseract、GlyphReader、RecoStar、Iris)を利用できるようにしています。ニーズに最適なものを選択します。

最後に、すでに完全に適切なテキストが含まれているページからテキストを抽出するためのコードが必要になります。

public void ProcessWithTextExtract(string path, Stream pdfStream, int page)
{
    using (Stream textStream = GetTextStream(path, page)) {
        StreamWriter writer = new StreamWriter(textStream);
        using (PdfTextDocument doc = new PdfTextDocument(pdfStream)) {
            PdfTextPage page = doc.GetPage(i);
            writer.Write(page.GetText(0, page.CharCount));
        }
    }
}

これにより、指定されたページからテキストが抽出され、出力ストリームに書き込まれます。

最後に、GetTextStream()が必要です。

public Stream GetTextStream(string sourcePath, int pageNo)
{
    string dir = Path.GetDirectoryName(sourcePath);
    string fname = Path.GetFileNameWithoutExtension(sourcePath);
    string finalPath = Path.Combine(dir, String.Format("{0}p{1}.txt", fname, pageNo));
    return new FileStream(finalPath, FileMode.Create);
}

これは100%のソリューションになりますか?いいえ、違います。 PDF 1つの画像を含み、その周りにボックスが描画されているページを想像できます。これは明らかに画像のみのテストに失敗しますが、有用なテキストは返されません。おそらく、より良いアプローチは、抽出されたテキストで何も返されない場合は、OCRエンジンを試してください。あるアプローチから別のアプローチに変更するには、別の述語を作成する必要があります。

4
plinth

最も簡単なアプローチは、ABBYY FineReader、Omnipageなどの単一のツールを使用して、スキャンされた画像とスキャンされていない画像に分類することなく、画像を1つのバッチで処理することです。FineReaderは変換すると思いますとにかくOCRを実行する前にPDFを画像に変換します。

OCRエンジンを使用すると、自動デスキュー、ページ方向検出、画像のしきい値処理、スペックル除去などの機能が提供されます。これらは、画像処理ライブラリを購入して自分でプログラムする必要がある機能であり、最適なセットを見つけるのが難しい場合があります。 10,000個のPDFのパラメータ。

自動OCRアプローチを使用すると、入力画像に応じて他の副作用が発生します。画像を並べ替えて、画像の種類ごとに最適なパラメータを設定すると、より良い結果が得られることがわかります。正確さを期すために、適切なPDFテキスト抽出ルーチンを使用して、完全なテキストを持つPDFを抽出することをお勧めします。

結局のところ、それはあなたが必要とする結果の質に対して時間とお金に帰着し​​ます。結局のところ、商用OCRプログラムが最も迅速で簡単なソリューションになります。クリーンなテキストのみのドキュメントがある場合は、安価なOCRプログラムと高価なソリューションが機能します。ドキュメントが複雑になるほど、ドキュメントの処理に必要な費用が増えます。

商用OCRエンジンのデモ/試用版をいくつか見つけて、時間とお金をかけすぎる前に、さまざまな種類のドキュメントでどのように機能するかを確認します。

3
Andrew Cash

Abbyy OCR4LINUX CLIエンジン(IMHO、それほどコストはかかりません)とTesseract3の小さなラッパーを作成しました。

ラッパーは、次のようにファイルをバッチ変換できます。
$ pmocr.sh --batch --target=pdf --skip-txt-pdf /some/directory

スクリプトはpdffontsを使用して、PDFファイルがすでにOCRedになっているかどうかを判断し、それらをスキップします。また、スクリプトはシステムサービスとして機能し、ディレクトリを監視してOCRアクションを起動できます。ファイルがディレクトリに入るとすぐに。

スクリプトはここにあります:
https://github.com/deajan/pmOCR

うまくいけば、これは誰かを助けます。

0
Orsiris de Jong