多くのPDFをバッチOCR


20

これは1年前にここで議論されています:

多くのPDFファイルのバッチOCR(まだOCRedではありません)?

まだOCRedになっていないOCR PDFをバッチ処理する方法はありますか?これは、次の2つの問題に対処する現状です。

バッチOCR PDF

  • Acrobat –これは、OCRをバッチ処理する最も簡単なocrエンジンです。唯一の問題は1)すでにOCRedであるファイルをスキップしないこと2)それにPDFの束を投げてみて(古い)クラッシュを監視することです。それは少しバグです。エラーが発生するたびに警告を表示します(ただし、ソフトウェアに通知しないように指示することはできます。ただし、特定の種類のPDFではひどく死に至るため、走行距離が異なる場合があります。

  • ABBYY FineReader(バッチ/スキャンスナップ)、Omnipage –これらは、人間に知られている最悪のプログラムされたソフトウェアの一部でなければなりません。同じ名前で保存するPDFのバッチOCR を完全に自動化する(プロンプトを表示しない)方法を見つけることができる場合は、ここに投稿してください。私が見つけることができる唯一の解決策はどこかで失敗したようです-完全に自動化されていないなど、名前を変更するなどです。

  • ABBYY FineReader EngineABBYY認識サーバー -これらは実際にはエンタープライズソリューションです。おそらく、acrobatをフォルダー上で実行し、試行錯誤するよりもエラー/プログラムをクラッシュさせるPDFを試してみることをお勧めします。評価ソフトウェアをインストールします(あなたが単純なエンドユーザーであると仮定します)。小規模ユーザーにとってはコスト競争力がないようです。

  • ** Autobahn DXワークステーション**この製品のコストは非常に高いため、おそらく6コピーのacrobatを購入できます。実際にはエンドユーザーソリューションではありません。エンタープライズ設定の場合、これはあなたにとって価値があるかもしれません。

Linux

  • WatchOCR –開発されておらず、基本的に現代のUbuntuディストリビューションでは実行できません
  • pdfsandwich –開発されていないため、基本的に現代のUbuntuディストリビューションでは実行できません
  • ** ABBY LINUX OCR **-これはスクリプト化可能でなければならず、いくつかの良い結果があるようです:

http://www.splitbrain.org/blog/2010-06/15-linux_ocr_software_comparison

ただし、これらの他の多くのABBYY製品と同様に、ページごとに課金されるので、Acrobat Batch OCRを機能させることをお勧めします。

  • ** Ocrad、GOCR、OCRopus、tesseract、** –これらは機能する可能性がありますが、いくつかの問題があります。

    1. OCRの結果は、たとえば、これらの一部のアクロバットほど優れていません(上記のリンクを参照)。
    2. どのプログラムもPDFファイルを取り込んでPDFファイルを出力しません。スクリプトを作成し、最初にPDFを分解し、それぞれに対してプログラムを実行してから、ファイルをPDFとして再構成する必要があります
    3. 実行すると、私がしたように、(tesseract)がOCRレイヤーを作成し、それが上にシフトすることがわかります。そのため、「the」という単語を検索すると、その隣の単語の一部がハイライトされます。
  • バッチDjVu →PDFに変換–まだ検討していませんが、恐ろしいラウンドアラウンドソリューションのようです。

オンライン

  • PDFcubed.com –バッチソリューションではありません。
  • ABBYY Cloud OCR-これが本当にバッチソリューションであるかどうかはわかりませんが、いずれにしてもページごとに支払う必要があり、これはかなり高価になる可能性があります。

非OCRed PDFの識別

これはやや簡単な問題で、Linuxでは簡単に解決できますが、Windowsではそれほど解決できません。pdffontどのファイルがOCRedではないかを判断するためにフォントが埋め込まれているかどうかを識別するために使用するperlスクリプトをコーディングできました。


現在の「解決策」

  1. スクリプトを使用して非OCRed pdfを識別し(数千のOCRed PDFを再実行しないようにします)、これらを一時ディレクトリにコピーし(正しいディレクトリツリーを保持)、Windows上のAcrobatを使用してこれらを実行しますバッチはクラッシュしません。

  2. 同じスクリプトを使用しますが、Linux ocrツールの1つを適切に機能させると、ocr品質が低下します。

私は#1を試すつもりだと思う、私はLinux OCRツールの結果についてあまりにも心配しているだけだ(誰かが比較をしたとは思わない)、ファイルをバラバラにして再びつなぎ合わせるようだAdobeがディレクトリをチョークせずにOCRを実際にバッチ処理できる場合、コーディングは不要です。

完全に無料のソリューションが必要な場合は、スクリプトを使用して非OCRed pdfを識別する(またはOCRedで再実行する)必要があります。次に、Linuxツールの1つを使用してOCRを試行します。Teseractが最良の結果を持っているように見えますが、これらのツールのいくつかはUbuntuの最新バージョンでは十分にサポートされていませんが、セットアップしてテキストマッチングレイヤーと一致しないイメージレイヤーの問題を解決できる場合は( tesseractを使用すると)かなり実用的なソリューションが得られ、もう一度Linux> Windowsができます。


OCR PDF完全に自動化し、同じ名前を保持しているOCRedファイルをスキップして高品質で完全に自動化する実用的なソリューションはありますか?もしそうなら、私は入力を本当に感謝します。


非OCRedファイルを一時ディレクトリに移動するPerlスクリプト。これが動作することを保証することはできず、おそらく書き直す必要がありますが、誰かがそれを動作させる(動作しないと仮定して)または動作を改善する場合は、お知らせください。


#!/usr/bin/perl

# move non-ocred files to a directory
# change variables below, you need a base dir (like /home/joe/), and a sourcedirectory and output
# direcotry (e.g books and tempdir)
# move all your pdfs to the sourcedirectory

use warnings;
use strict;

# need to install these modules with CPAN or your distros installer (e.g. apt-get)
use CAM::PDF;
use File::Find;
use File::Basename;
use File::Copy;

#use PDF::OCR2;
#$PDF::OCR2::CHECK_PDF   = 1;
#$PDF::OCR2::REPAIR_XREF = 1;

my $basedir = '/your/base/directory';
my $sourcedirectory  = $basedir.'/books/';
my @exts       = qw(.pdf);
my $count      = 0;
my $outputroot = $basedir.'/tempdir/';
open( WRITE, >>$basedir.'/errors.txt' );

#check file
#my $pdf = PDF::OCR2->new($basedir.'/tempfile.pdf');
#print $pdf->page(10)->text;



find(
    {
        wanted => \&process_file,

        #       no_chdir => 1
    },
    $sourcedirectory
);
close(WRITE);

sub process_file {
    #must be a file
    if ( -f $_ ) {
        my $file = $_;
        #must be a pdf
        my ( $dir, $name, $ext ) = fileparse( $_, @exts );
        if ( $ext eq '.pdf' ) {
            #check if pdf is ocred
            my $command = "pdffonts \'$file\'";
            my $output  = `$command`;
            if ( !( $output =~ /yes/ || $output =~ /no/ ) ) {
                #print "$file - Not OCRed\n";
                my $currentdir = $File::Find::dir;
                if ( $currentdir =~ /$sourcedirectory(.+)/ ) {
                    #if directory doesn't exist, create
                    unless(-d $outputroot.$1){
                    system("mkdir -p $outputroot$1");
                    }
                    #copy over file
                    my $fromfile = "$currentdir/$file";
                    my $tofile = "$outputroot$1/$file";
                    print "copy from: $fromfile\n";
                    print "copy to: $tofile\n";
                    copy($fromfile, $tofile) or die "Copy failed: $!";
#                       `touch $outputroot$1/\'$file\'`;
                }
            }

        }

    }
}

?こんにちは、あなたは事前に感謝し、あなたのWindowsの「スクリプト非OCRed PDFを(...)を識別し、一時ディレクトリにこれらをコピーする(正しいディレクトリツリーを保持)を共有してもらえ;)
エルブ

@David OK 最初に正しく動作しない可能性があることを警告します。これはあなたのpdfファイルをまったく傷つけません(ただコピーするだけで、元のファイルには触れません)が、私が意味するのはスクリプトを修正する必要があるかもしれないということです。perlを知っているなら、私に知らせていないなら、それは簡単だろう。あるいは、あなた自身でそれをデバッグして、必要な小さな編集をすることができるかもしれない。
ジョー

どうもありがとう。(perlが初めての場合でも)動作させようとします。ありがとう。
Erb

Windowsでのもう1つのアイデア(XPで動作)過去に「パスワードのないすべてのpdfファイルをフォルダー(サブフォルダーを含む)から削除する」ためにこれを使用しました。アイデアは、パスワードで保護されたすべてのpdfファイルを保持することでした。Syncbackフリーウェアですべてのpdf(関連するサブフォルダーを含む)を新しいフォルダー(C:\ 5 \ ")にコピーします。pdftotext.exeとdel_pdf_no_password.batで名前を変更したこのテキストファイルを追加します。その内容:" FOR / RC:\ 5 \% %X IN(* .PDF)DO(pdftotext %% X NUL && DEL %% x)は」どこで"C:。。\ 5 \"変化にフォルダがあるその後pdftotext.exeだけにして.BATファイルを開始
Erb

詳細:フリーウェアの名前変更機能(例:alternativeto.net/software/renamerなど)を使用して、フォルダー名内の空のスペース(+などの特別な文字)を削除する必要があります。そうしないと、すべてのサブフォルダーで機能しません!追伸:このスクリプトは書いていません(... 2004年に誰かに助けられました!)
Erb

回答:


3

私も多くのPDFを自動化された方法でバッチOCRする方法を探しました。最終的に、Acrobatと次のようなスクリプトを使用して、あなたと同様の実行可能なソリューションを思い付きました。

  1. 関連するすべてのPDFを特定のディレクトリにコピーします。

  2. すでにテキストを含んでいるPDFを削除します(既にOCRdまたは既にテキストであると想定しています-理想的ではありませんが、今のところは十分です)。

  3. AutoHotKeyを使用して、Acrobatを自動的に実行し、特定のディレクトリを選択し、ファイル名に「-ocr」を追加してすべてのドキュメントをOCRします。

  4. 「-ocr.pdf」ファイルの存在を使用して、OCRd PDFを元の場所に戻し、成功したかどうかを判断します。

少しヒース・ロビンソンですが、実際にはかなりうまくいきます。


Acrobatがディレクトリをバッチ処理する場合、AutoHotKeyを使用する必要があるのはなぜですか?acrobatがクラッシュした場合にプロセスを繰り返すことを心配している場合は、変更されたファイルのタイムスタンプにより、中断した場所がわかります。オリジナルを保持したい場合は、ディレクトリをコピーするだけです。最後に-ocrが必要な場合は、完了後にバッチ名を変更するだけです。
ジョー

1
こんにちは、運が良ければ、Windowsでポイント2と3をどうやって行うのか教えてください。事前に感謝;)
Erb

2

ABBYY FineReaderは、高速で正確なすぐに使用できるOCRを提供するように設計されたエンドユーザーソリューションであることを理解する必要があると思います。

私の経験に基づいて、OCRプロジェクトは毎回大幅に異なる詳細を持っているため、それぞれのユニークなケースに対してすぐに使える魂を作成する方法はありませんが、私はあなたのために仕事をすることができるより専門的なツールを提案できます:

私は上記のクラウドサービスのフロントエンド開発チームの一員であり、必要に応じて詳細情報を提供できます。

PDFでのテキストレイヤーのルックアップを考慮すると、このタスクは私の専門であるOCRから少し離れているため、アドバイスはできません。したがって、外部スクリプトを使用するアプローチは非常に合理的です。たぶん、あなたはこの議論が役立つと思うでしょう:http : //forum.ocrsdk.com/questions/108/check-if-pdf-is-scanned-image-or-contains-text


1
少なくとも、ABBYYにはPDFのフォルダーを簡単にバッチ処理するためのドキュメントまたは機能(Acrobatにあります)がないことがわかっています。非OCRedドキュメントのフォルダーの単純なバッチOCRは、非常に望ましい機能です(ABBYYの他の機能の一部よりもはるかに優れています)。この欲求がどれほど圧倒的に一般的であるかをグーグルで検索してください。他のオプションに感謝しますが、私はそれらを調べますが、今のところ、この非常に一般的なタスクを完了する方法を探してここに来る人に(引用可能)、ABBYYがこれを行うことができないことを馬の口から聞いたことを知らせてください。
ジョー

バッチOCRはABBYY FineReader Professionalで利用できます。あなたの質問では、OCRを完全に自動化する必要があると述べています。これで、バッチ処理が必要になります。正確に何が必要かを明確にしてください。
ニコライ

上記参照。「簡単なバッチOCR」、「フォルダの単純なバッチOCR」と言いました。さらに上:「バッチOCRを完全に自動化する(プロンプトを表示しない)方法を見つけることができる場合..」私が欲しいものはかなり明白です。このページにアクセスした人には明確にしましょう:* 大量のユーザー集約型プロセスで恐ろしい保存オプションを備えた恐ろしく複雑なインターフェイスを使用してPDFのフォルダーを「バッチ処理」したい場合は、ABBYYが有効です* Acrobatがすでに行っているように、ABBYY Finereaderは、「簡単なバッチOCR」、「簡単なバッチOCR」、他の何千もの他のユーザーのように少ないユーザー操作を備えています。
ジョー

2

Linuxで

pypdfocrそれを使用するのが最善で最も簡単な方法は、pdfを変更しません

pypdfocr your_document.pdf

最後your_document_ocr.pdfに、検索可能なテキストを使用した別の方法があります。アプリは画像の品質を変更しません。オーバーレイテキストを追加して、ファイルのサイズを少し大きくします。

PDFをバッチ処理するには

ls ./p*.pdf | xargs -L1 -I {}  pypdfocr {}

PDFがサブフォルダーにある場合:

tree -fai . | grep -P ".pdf$" | xargs -L1 -I {}  pypdfocr {}

2018年11月3日更新:

pypdfocr2016年以降サポートされなくなり、メンテナンスされていないために問題が発生しました。ocrmypdfモジュール)は、類似のジョブを実行し、次のように使用できます。

ocrmypdf in.pdf out.pdf

インストールする:

pip install ocrmypdf

または

apt install ocrmypdf

コマンドは次のようになります

tree -fai . | grep -P ".pdf$" | xargs -L1 -I {}  ocrmypdf {} {}_ocr.pdf 

1

2015年の初めに、WindowsでNuance OmniPage Ultimateを使用してバッチOCRを完全にハンドオフすることに成功しました。無料ではない、定価500ドル。含まれているバッチプログラム「DocuDirect」を使用します。「プロンプトなしでジョブを実行する」オプションがあり、これは元の質問に対する直接的な回答のようです。

DocuDirectを使用して、入力画像(つまり、検索不可)PDFファイルごとに1つの検索可能PDFファイルを出力しました。入力フォルダーツリーを元の入力ファイル名と同様に出力フォルダーに複製するように指示できます(ほぼ-以下を参照)。複数のコアも使用します。精度は、私が評価したパッケージの中で最高でした。パスワードで保護されたドキュメントはスキップされます(ジョブを停止せず、ダイアログを表示しません)。

注意1:ほとんど元のファイル名-サフィックス ".PDF"は ".pdf"(つまり、大文字から小文字)になります。これは、Windowsでも同じだからです。(うーん)

警告2:ログファイルがないので、認識中にどのファイルが失敗するかを診断します。DocuDirectは、ページ全体が単に欠落しているような文字化けした出力を喜んで生成します。PyPDF2モジュールを使用して大まかな検証を実装するpythonスクリプトを作成しました。出力ページ数が入力ページ数と一致することをテストします。下記参照。

警告3:曖昧で不明瞭な入力画像ファイルは、CPUを使用せずにOmniPageを永久にハングアップさせます。回復することはありません。これは本当にバッチ処理の妨げとなり、回避策は見つかりませんでした。私もこれをNuanceに報告しましたが、どこにも行きませんでした。

@Joeは、ソフトウェアのプログラミングと文書化が不十分であることについて正しいです。OmniPage のコアには驚くべき文字認識マジックテクノロジーがありますが、外側のシェル(GUIとバッチ処理)で髪を引き抜くことができます。

OCRパッケージを保護されていない画像ドキュメントでのみ表示するために、スクリプトを使用してファイルを除外する@Joeと@Kiwiの提案を推奨します。

私がNuanceに所属しているのは、完全に満足していない顧客としてです。それを証明するために、未解決のサポートチケットがたくさんあります。

@ジョー:遅い答えですが、おそらく関連性があります。@SuperUserコミュニティ:これが話題になっていると感じていただければ幸いです。

**更新**後継パッケージはNuance PowerPDF Advancedで、定価はわずか150ドルです。私はこれでさらに良い成功を収めました。それは同じくらい正確ですが、はるかに安定しています。

事前/事後OCRツリー検証pythonスクリプトが続きます。

'''
Script to validate OCR outputs against inputs.
Both input and output are PDF documents in a directory tree.
For each input document, checks for the corresponding output
document and its page count.

Requires PyPDF2 from https://pypi.python.org/pypi/PyPDF2
'''

from __future__ import print_function
from PyPDF2 import PdfFileReader
import getopt
import os
import stat
import sys

def get_pdf_page_count(filename):
    '''
    Gets number of pages in the named PDF file.
    Fails on an encrypted or invalid file, returns None.
    '''
    with open(filename, "rb") as pdf_file:
        page_count = None
        err = None
        try:
            # slurp the file
            pdf_obj = PdfFileReader(pdf_file)
            # extract properties
            page_count = pdf_obj.getNumPages()
            err = ""
        except Exception:
            # Invalid PDF.
            # Limit exception so we don't catch KeyboardInterrupt etc.
            err = str(sys.exc_info())
            # This should be rare
            print("Warning: failed on file %s: %s" % (filename, err), file=sys.stderr)
            return None

    return page_count

def validate_pdf_pair(verbose, img_file, txt_file):
    '''
    Checks for existence and size of target PDF file;
    number of pages should match source PDF file.
    Returns True on match, else False.
    '''
    #if verbose: 
    #    print("Image PDF is %s" % img_file)
    #    print("Text PDF is %s" % txt_file)

    # Get source and target page counts
    img_pages = get_pdf_page_count(img_file)
    txt_pages = get_pdf_page_count(txt_file)
    if img_pages is None:
        # Bogus PDF, skip.
        print("Warning: failed to get page count for %s" % img_file, file=sys.stderr)
        return None
    if txt_pages is None:
        # Bogus PDF, skip.
        print("Warning: failed to get page count for %s" % txt_file, file=sys.stderr)
        return None

    retval = True
    if img_pages != txt_pages:
        retval = False
        print("Mismatch page count: %d in source %s, %d in target %s" % (img_pages, img_file, txt_pages, txt_file), file=sys.stderr)

    return retval


def validate_ocr_output(verbose, process_count, total_count, img_dir, txt_dir):
    '''
    Walks a tree of files to compare against output tree, calling self recursively.
    Returns a tuple with PDF file counts (matched, non-matched).
    '''
    # Iterate over the this directory
    match = 0
    nonmatch = 0
    for dirent in os.listdir(img_dir):
        src_path = os.path.join(img_dir, dirent)
        tgt_path = os.path.join(txt_dir, dirent)
        if os.path.isdir(src_path):
            if verbose: print("Found source dir %s" % src_path)
            # check target
            if os.path.isdir(tgt_path):
                # Ok to process
                (sub_match, sub_nonmatch) = validate_ocr_output(verbose, process_count + match + nonmatch, total_count, 
                                         src_path, tgt_path)
                match += sub_match
                nonmatch += sub_nonmatch
            else:
                # Target is missing!?
                print("Fatal: target dir not found: %s" % tgt_path, file=sys.stderr)

        elif os.path.isfile(src_path):
            # it's a plain file
            if src_path.lower().endswith(".pdf"):
                # check target
                # HACK: OmniPage changes upper-case PDF suffix to pdf;
                # of course not visible in Windohs with the case-insensitive 
                # file system, but it's a problem on linux.
                if not os.path.isfile(tgt_path):
                    # Flip lower to upper and VV
                    if tgt_path.endswith(".PDF"):
                        # use a slice
                        tgt_path = tgt_path[:-4] + ".pdf"
                    elif tgt_path.endswith(".pdf"):
                        tgt_path = tgt_path[:-4] + ".PDF"
                # hopefully it will be found now!
                if os.path.isfile(tgt_path):
                    # Ok to process
                    sub_match = validate_pdf_pair(verbose, src_path, tgt_path)
                    if sub_match:
                        match += 1
                    else:
                        nonmatch += 1
                    if verbose: print("File %d vs %d matches: %s" % (process_count + match + nonmatch, total_count, sub_match))

                else:
                    # Target is missing!?
                    print("Fatal: target file not found: %s" % tgt_path, file=sys.stderr)
                    nonmatch += 1

        else:
            # This should never happen
            print("Warning: not a directory nor file: %s" % src_path, file=sys.stderr)
    return (match, nonmatch)

def count_pdfs_listdir(verbose, src_dir):
    '''
    Counts PDF files in a tree using os.listdir, os.stat and recursion.
    Not nearly as elegant as os.walk, but hopefully very fast on
    large trees; I don't need the whole list in memory.
    '''
    count = 0
    for dirent in os.listdir(src_dir):
        src_path = os.path.join(src_dir, dirent)
        # stat the entry just once
        mode = os.stat(src_path)[stat.ST_MODE]
        if stat.S_ISDIR(mode):
            # It's a directory, recurse into it
            count += count_pdfs_listdir(verbose, src_path)
        elif stat.S_ISREG(mode):
            # It's a file, count it
            if src_path.lower().endswith('.pdf'):
                count += 1
        else:
            # Unknown entry, print an error
            print("Warning: not a directory nor file: %s" % src_path, file=sys.stderr)
    return count

def main(args):
    '''
    Parses command-line arguments and processes the named dirs.
    '''
    try:
        opts, args = getopt.getopt(args, "vi:o:")
    except getopt.GetoptError:
        usage()
    # default values
    verbose = False
    in_dir = None
    out_dir = None
    for opt, optarg in opts:
        if opt in ("-i"):
            in_dir = optarg
        elif opt in ("-o"):
            out_dir = optarg
        elif opt in ("-v"):
            verbose = True
        else:
            usage()
    # validate args
    if in_dir is None or out_dir is None: usage()
    if not os.path.isdir(in_dir):
        print("Not found or not a directory: %s" % input, file=sys.stderr)
        usage()
    if not os.path.isdir(out_dir):
        print("Not found or not a directory: %s" % out_dir, file=sys.stderr)
        usage()
    if verbose: 
        print("Validating input %s -> output %s" % (in_dir, out_dir))
    # get to work
    print("Counting files in %s" % in_dir)
    count = count_pdfs_listdir(verbose, in_dir)
    print("PDF input file count is %d" % count)
    (match,nomatch) = validate_ocr_output(verbose=verbose, process_count=0, total_count=count, img_dir=in_dir, txt_dir=out_dir) 
    print("Results are: %d matches, %d mismatches" % (match, nomatch))

def usage():
    print('Usage: validate_ocr_output.py [options] -i input-dir -o output-dir')
    print('    Compares pre-OCR and post-OCR directory trees')
    print('    Options: -v = be verbose')
    sys.exit()

# Pass all params after program name to our main
if __name__ == "__main__":
    main(sys.argv[1:])

あなたの更新を見ました。やってみます。OCRが静かにクラッシュすることなく行われることを願っています!(すごい!1GBのダウンロードファイル!)
Erb

0

AquaforestのAutobahn DXを検討できますhttp ://www.aquaforest.com/en/autobahn.asp

PDFのバッチを処理するように設計されており、さまざまなオプション(たとえば、OCRedファイルをスキップまたはパススルーする)と、より良い結果をもたらす可能性のあるPDFのスマートな処理のオプション(PDFに画像ページとテキストページ、画像ページのみをOCRできます)


その製品と提携している場合は、質問を編集して明示的にそうしてください。
-slhck

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.