PDF的批量OCR程序

时间:2011-05-17 04:36:23

标签: pdf ocr batch-processing

以前曾经问过,但我真的不知道这些答案是否对我有帮助。这是我的问题:我得到了一堆(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(显然它是'$$$,但如果这个东西明显更好,我会花600美元来完成这项工作,即有更准确的ocr)。
  7. 另外,我是编程的n00b,所以如果要花几周时间学习如何做某事,我宁愿支付$$$。感谢输入/体验。

    顺便说一句,我正在运行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

5 个答案:

答案 0 :(得分:6)

只是把你的一些误解直接......

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

你可以在免费(如自由)和免费(如啤酒)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等。

警告:

  1. tiffg4输出设备的默认分辨率为204x196 dpi。你可能想要更好的价值。要获得720 dpi,您应该在命令行中添加-r720x720
  2. 此外,如果您的Ghostscript安装使用 letter 作为其默认媒体大小,您可能需要更改它。您可以使用-gXxY在设备点中设置widthxheight。因此,要在横向中获取 ISO A4 输出页面尺寸,您可以添加-g8420x5950参数。
  3. 因此,控制这两个参数的完整命令,以纵向方式在A4上产生720 dpi输出,将显示为:

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

答案 1 :(得分:5)

想通过回答我自己的问题,我会尝试做出贡献(为自己编写了一些很好的代码,如果没有这个板的帮助就无法完成它)。如果你在unix中使用pdf文件(好吧,对我来说是osx),那么有文本的pdf文件中会包含单词“Font”(作为字符串,但与其他文本混合在一起)b / c这是怎么回事文件告诉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 shell中输入了这个命令:

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

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

答案 2 :(得分:4)

这是一个有趣的问题。如果您愿意在.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页面光栅化为图像,并将其放入一个适合引擎的形式。翻译。这并不一定要以这种方式完成 - 可以通过调用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页面包含一个单独的图像,并在其周围绘制一个框 - 这显然会使图像无法测试,但不会返回任何有用的文本。可能更好的方法是只使用提取的文本,如果没有返回任何内容,那么尝试使用OCR引擎。从一种方法转向另一种方法是写一个不同的谓词。

答案 3 :(得分:3)

最简单的方法是使用单一工具,如ABBYY FineReader,Omnipage等,一批处理图像,而不必将它们分类为扫描图像而非扫描图像。我相信FineReader无论如何都会在执行OCR之前将PDF转换为图像。

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

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

在一天结束时,它将归结为时间和金钱与您所需结果的质量。在一天结束时,商业OCR计划将是最快捷,最简单的解决方案。如果你只有干净的文本文件,那么廉价的OCR程序将起作用,而且价格昂贵。您的文档越复杂,处理它们所需的资金就越多。

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

答案 4 :(得分:0)

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

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

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

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

希望这有助于某人。