PDF 的批量 OCR 程序 [关闭]

Posted

技术标签:

【中文标题】PDF 的批量 OCR 程序 [关闭]【英文标题】:Batch OCR Program for PDFs [closed] 【发布时间】:2011-08-26 22:41:12 【问题描述】:

以前有人问过这个问题,但我真的不知道答案是否对我有帮助。这是我的问题:我有一堆(10,000 左右)pdf 文件。有些是使用 adobe 的打印功能保存的文本文件(因此它们的文本是完美的,我不想冒险搞砸它们)。有些是扫描的图像(所以它们没有任何文字,我将不得不接受 OCR)。这些文件在同一个目录中,我不知道哪个是哪个。最终我想把它们变成 .txt 文件,然后对它们进行字符串处理。所以我想要尽可能准确的 OCR。

好像有人推荐过:

    adobe pdf(我没有这个的许可副本,所以......加上如果 ABBYY Finereader 或其他更好的东西,如果我不使用它,为什么还要付费) ocropus(我不知道怎么用这个东西), Tesseract(在 1995 年看起来很棒,但我不确定是否有更准确的东西,而且它本身不支持 pdf,我必须转换为 TIFF。这会引发它自己的问题,因为我不这样做'没有 acrobat 的许可副本,所以我不知道如何将 10,000 个文件转换为 tiff。另外,我不希望将 10,000 个 30 页文档转换为 30,000 个单独的 tiff 图像)。 wowocr pdftextstream(从 2009 年开始) ABBYY FineReader(显然是它的 $$$$,但如果这件事明显更好,即具有更准确的 ocr,我将花费 600 美元来完成这项工作)。

我也是编程爱好者,所以如果要花几周的时间来学习如何做某事,我宁愿支付 $$$。感谢输入/经验。

顺便说一句,我正在运行 Linux Mint 11 64 位和/或 Windows 7 64 位。

这里是其他线程:

Batch OCRing PDFs that haven't already been OCR'd

Open source OCR

PDF Text Extraction Approach Using OCR

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

【问题讨论】:

【参考方案1】:

只是为了纠正你的一些误解......

“我没有 acrobat 的许可副本,所以我不知道如何将 10,000 个文件转换为 tiff。”

您可以借助 Free(如 liberty)和免费(如啤酒)Ghostscript 将 PDF 转换为 TIFF。如果您想在 Linux Mint 或 Windows 7 上执行此操作,您可以选择。Linux 的命令行是:

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

“我不希望将 10,000 个 30 页的文档变成 30,000 个单独的 tiff 图像”

您可以轻松创建“多页”TIFF。上面的命令确实创建了 G4(传真 tiff)风格的 TIFF。如果您甚至想要单页 TIFF,您可以修改命令:

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

输出文件名的%03d部分会自动翻译成一系列001002003

注意事项:

    tiffg4 输出设备的默认分辨率为 204x196 dpi。您可能想要更好的价值。要获得 720 dpi,您应该在命令行中添加 -r720x720。 另外,如果您的 Ghostscript 安装使用 letter 作为其默认媒体大小,您可能需要更改它。您可以使用-gXxY 设置设备点的宽度x高度。因此,要获得 ISO A4 横向输出页面尺寸,您可以添加 -g8420x5950 参数。

因此,控制这两个参数的完整命令将在 A4 纵向上产生 720 dpi 输出,如下所示:

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

【讨论】:

【参考方案2】:

我想我会尝试通过回答我自己的问题来做出贡献(我已经为自己编写了一些不错的代码,如果没有这个委员会的帮助,我是做不到的)。如果您在 unix 中搜索 pdf 文件(好吧,对我来说是 osx),那么包含文本的 pdf 文件中将包含“Font”一词(作为字符串,但与其他文本混合)b/c 这就是文件告诉 Adob​​e 要显示的字体。

bash 中的 cat 命令似乎与在 python 中以二进制模式读取文件具有相同的输出(打开文件时使用 'rb' 模式而不是 'w' 或 'r' 或 'a')。所以我假设所有包含文本的 pdf 文件在二进制输出中都有“字体”这个词,并且没有图像文件永远不会。如果始终如此,那么此代码将列出单个目录中包含文本的所有 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 shell 中输入了这个命令:

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

另外,我没有重新运行上面的 python 代码,我只是手动编辑了东西,所以它可能是错误的,Idk。

【讨论】:

【参考方案3】:

这是一个有趣的问题。如果您愿意在 .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 的形式。这并不一定需要以这种方式完成 - 可以通过调用识别从 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("0p1.txt", fname, pageNo));
    return new FileStream(finalPath, FileMode.Create);

这会是 100% 的解决方案吗?不,当然不是。您可以想象 PDF 页面包含单个图像并在其周围绘制一个框 - 这显然会使仅图像测试失败,但不会返回任何有用的文本。可能更好的方法是仅使用提取的文本,如果没有返回任何内容,请尝试使用 OCR 引擎。从一种方法更改为另一种方法是编写不同的谓词。

【讨论】:

【参考方案4】:

最简单的方法是使用单一工具(例如 ABBYY FineReader、Omnipage 等)批量处理图像,而无需将它们分类为扫描图像和未扫描图像。我相信 FineReader 在执行 OCR 之前会将 PDF 转换为图像。

使用 OCR 引擎将为您提供自动纠偏、页面方向检测、图像阈值处理、去斑点等功能。这些功能您必须购买图像处理库并自行编程,但可能很难找到10,000 个 PDF 的最佳参数集。

使用自动 OCR 方法会产生其他副作用,具体取决于输入图像,如果您对图像进行排序并为每种类型的图像设置最佳参数,您会发现您会获得更好的结果。为了准确起见,最好使用适当的 PDF 文本提取例程来提取具有完美文本的 PDF。

归根结底,这将归结为时间和金钱与您需要的结果的质量。归根结底,商业 OCR 程序将是最快、最简单的解决方案。如果您只有纯文本文档,那么便宜的 OCR 程序将与昂贵的解决方案一样有效。您的文件越复杂,处理它们所需的资金就越多。

我会尝试寻找一些商业 OCR 引擎的演示/试用版,并在花费太多时间和金钱之前看看它们在不同文档类型上的表现。

【讨论】:

【参考方案5】:

我为 Abbyy OCR4LINUX CLI 引擎(恕我直言,成本不高)和 Tesseract 3 编写了一个小包装器。

包装器可以批量转换文件,如:$ pmocr.sh --batch --target=pdf --skip-txt-pdf /some/directory

脚本使用pdffonts 来确定PDF 文件是否已经被OCRed 跳过它们。此外,该脚本还可以作为系统服务来监控目录并在文件进入目录后立即启动 OCR 操作。

脚本可以在这里找到:https://github.com/deajan/pmOCR

希望这对某人有所帮助。

【讨论】:

以上是关于PDF 的批量 OCR 程序 [关闭]的主要内容,如果未能解决你的问题,请参考以下文章

发票自动数据提取 OCR 或 PDF [关闭]

开源 OCR [关闭]

基于百度OCR提取图像中的文本

进行OCR识别文本的时候提示PDF文档无法识别

如何将外部 OCR 嵌入现有 PDF?

如何制作 OCR 程序? [关闭]