如何在小型C++项目中使用Tesseract OCR(或任何其他免费OCR)?

28
我调查后得知,唯一可靠的免费OCR选项是Tesseract或CuneiForm。
然而,Tesseract文档很糟糕,只给你一堆Visual Studio代码(对于我来说是在Windows上),然后你就需要自己在他们的API海洋中摸索。你只能使用编译后的exe文件来处理tiff图像。
我期望至少有一份简短的文档,告诉我如何调用它们的API,即使只是一个小例子,但是没有,文档里面什么都没有。
CuneiForm:我下载了它,但是所有的东西都是俄语,让我很头疼。
这些人难道不会提供一个小例子吗?他们提供的大部分信息都与使用OCR无关,可能90%的人都看不懂,如果没有从小事做起并解释其中的细节,你怎么能到达那个水平呢?
所以我有一堆API,但如果没有解释,我该怎么使用它呢?也许有人可以给我建议和解决方案吗?我不求奇迹,只需要一个小例子来展示如何工作。

5
这是一份投诉,不适合在这里。您可以删除投诉,并尝试使用tesseract或cuinform,然后提供更具体的问题。此外,我对这两个项目都不熟悉,如果您能提供链接会更有帮助。 - David Thornley
2
欢迎来到开源库的世界,这里的API很糟糕,什么都没有文档。 - Cat Plus Plus
1
@Davi Thornley,我希望我能使用它,但是没有起点的文档...我一直在网上搜索示例,但是找不到。我的问题是从哪里开始将他们的API引入我的C项目,只需要一个小例子,指导我深入挖掘,肯定有人在他们的项目中使用过其中之一。 - Marko29
5个回答

28

你可能已经放弃了,但还有其他人在尝试。那么这是你需要开始使用Tesseract的内容:

首先,您应该阅读所有关于Tesseract的文档。您可能会发现一些有用的内容在wiki中。

要开始使用API(v3.0.1,目前在主分支中,请同时阅读trunk中的README和ChangeLog),您应该查看baseapi.h。如何使用该API的文档就在那里,每个函数上面都有注释。

对于初学者:

  • 包括baseapi.h并构造TessBaseAPI对象
  • 调用Init()
  • 一些可选项,例如:
    • 使用SetVariable()函数更改一些参数。如果您使用PrintVariables()函数将它们打印到文件中,您可以查看所有参数及其值。
    • 使用SetPageSegMode()更改分割模式。告诉Tesseract您要OCR的图像表示为文本块或线、单词或字符。
  • SetImage()
  • GetUTF8Text()

(再次强调,这只是刚开始的步骤。)

您可以在Tesseract社区中查找已回答的问题或在此处提出自己的问题。


4

我正在研究它...到目前为止,我已经生成了DoxyGen代码...这很有帮助。不过我仍在阅读所有文档。

以下是一些帮助我的链接:

我下载了来自Google Code的svn:http://code.google.com/p/tesseract-ocr/

然后进行了制作和安装,接着使用doxygen生成了自己的API参考文档。非常有用。

我使用的方法是:

  1. 我使用'make install',它将一些东西放在/usr/include/tesseract中
  2. 我将该目录复制到我的主目录中
  3. doxygen -g doxygen.conf; # 生成一个doxygen文件
  4. 浏览生成的文件并设置输出目录和项目名称或其他内容。我使用'doxy-dox'作为我的输出目录
  5. doxygen -g doxygen.conf
  6. chromium-browser chromium-browser doxy-doc/html/index.html

希望这有点帮助。


3

我已经弄清楚了,如果你正在使用Visual Studios 2010并使用Windows Forms/设计器,你可以轻松添加它,而且没有任何问题。

  1. 将以下项目添加到您的项目中(我警告您一次,不要添加Tesseract解决方案,或更改您添加的项目中的任何设置,除非您喜欢自讨苦吃)

    ccmain ccstruct ccutil classify cube cutil dict image libtesseract nutral_networks textord viewer wordrec

你可以添加其他项目,但你真的不想把所有这些都集成在你的项目中,对吧?不需要,分别构建它们即可。

  1. 打开项目属性并添加libtesseract作为参考,现在你可以看到它作为一个项目可见,这将使您的项目快速构建而不必检查tesseract中的数百万个警告。[常规属性]->[添加引用]

  2. 在解决方案资源管理器中右键单击您的项目,然后单击项目依赖项,确保它依赖于libtesseract甚至所有这些项目,这意味着它们会在您的项目之前构建。

  3. tesseract 2010 Visual Studio项目包含许多配置设置,例如release、release.dll、debug、debug.dll,似乎release.dll设置会生成正确的文件。首先,将解决方案输出设置为release.dll。单击您的项目属性。然后单击配置管理器。如果不可用,请单击解决方案树中的SOLUTION属性,然后单击配置选项卡,您将看到一系列项目和相关的配置设置。您会注意到您的项目未设置为release.dll,即使输出是如此。如果您采取了第二种方法,则仍需单击配置管理器。然后您可以编辑设置,在您的项目设置上单击新建并将其命名为release.dll……与其他设置完全相同,并从release中复制设置。对于Debug也要做同样的事情,这样您就有了从debug设置中复制的debug.dll名称。快完成了

  4. 不要尝试更改tesseract的设置以匹配您的设置……那行不通……当新版本发布时,您将无法“扔进去”并继续使用。接受这个事实,在此状态下,您的新模式是Release.dll和Debug.dll。不要紧张……完成后可以返回并从解决方案中删除这些项目。

  5. 猜猜库和dll在哪里?在您的项目中,您可能需要添加库目录。有人说要将所有头文件倒入一个单独的文件夹中,以便他们只需要添加一个文件夹到包含文件夹中,但我不这么做。我希望能够删除tesseract文件夹并从zip文件重新加载它而无需额外工作……并且可以完全准备好一次更新或恢复代码。这需要一些工作,您可以通过代码而不是设置来完成,但应该包括包含在2010 tesseract项目文件夹中的所有包含头文件的文件夹,并让它们保持原样。

  6. 没有必要向您的项目添加任何文件。只需这些代码行……我还包括了一些额外的代码,用于将一组外国数据转换为不需要保存/加载文件的tiff友好版本。我真好心吧?

  7. 现在您可以完全在debug.dll和release.dll中进行调试,一旦您成功将其构建到您的项目中,甚至可以删除所有添加的项目,它将是完美的。没有额外的编译或错误。完全可调试,完全自然。

  8. 如果我没记错的话,我无法避免必须将2008/lib/中的文件复制到我的项目发布文件夹中……该死。

在我的项目中的“functions.h”文件里,我放置了以下内容:
#pragma comment (lib, "liblept.lib" )
#define _USE_TESSERACT_
#ifdef _USE_TESSERACT_
#pragma comment (lib, "libtesseract.lib" )
#include <baseapi.h>
#endif
#include <allheaders.h>

在我的主项目中,我将以下内容作为成员放入了一个类中:

tesseract::TessBaseAPI *readSomeNombers;

当然,我在某个地方包含了“functions.h”。
然后我将此放入我的类构造函数中:
readSomeNombers = new tesseract::TessBaseAPI();
readSomeNombers ->Init(NULL, "eng" );
readSomeNombers ->SetVariable( "tessedit_char_whitelist", "0123456789,." );

然后我创建了这个类成员函数:以及一个类成员来作为输出,不要反感,我不喜欢返回变量。不是我的风格。在成员函数内部使用图像的内存不需要被销毁,我相信这是一种安全的调用方式,我的测试也证明了这一点。但是,无论如何,你可以做任何事情。
void Gaara::scanTheSpot()
{
    Pix *someNewPix;
    char* outText;
    ostringstream tempStream;
    RECT tempRect;
    someNewPix = pixCreate( 200 , 40 , 32 );
    convertEasyBmpToPix( &scanImage, someNewPix, 87, 42 );

    readSomeNombers ->SetImage(someNewPix);
    outText = readSomeNombers ->GetUTF8Text();
    tempStream.str("");
    tempStream << outText;
    classMemeberVariable = tempStream.str();
//pixWrite( "test.bmp", someNewPix, IFF_BMP );
}

我想扫描的信息所在的对象在内存中,并且由&scanImage指向。这是来自“EasyBMP”库的,但这并不重要。

我在“functions.h”/“functions.cpp”中编写了一个处理它的函数,顺便说一下,我正在循环中进行一些额外的处理,即细化字符、将其变成黑白颜色并反转黑白颜色,这是不必要的。在开发的这个阶段,我仍在寻找改进识别的方法。尽管对于我的目的,这还没有产生过坏数据。我的看法是为了简单起见使用默认的Tess数据。我正在试图以启发式的方式解决一个非常复杂的问题。

void convertEasyBmpToPix( BMP *sourceImage, PIX *outputImage, unsigned startX, unsigned startY )
{
    int endX = startX + ( pixGetWidth( outputImage ) );
    int endY = startY + ( pixGetHeight( outputImage ) );
    unsigned destinationX;
    unsigned destinationY = 0;
    for( int yLoop = startY; yLoop < endY; yLoop++ )
    {
        destinationX = 0;
        for( int xLoop = startX; xLoop < endX; xLoop++ )
        {
            if( isWhite( &( sourceImage->GetPixel( xLoop, yLoop ) ) ) )
            {
                pixSetRGBPixel( outputImage, destinationX, destinationY, 0,0,0 );
            }
            else
            {
                pixSetRGBPixel( outputImage, destinationX, destinationY, 255,255,255 );
            }
            destinationX++;
        }
        destinationY++;
    }
}
bool isWhite( RGBApixel *image )
{
    if(
        //destination->SetPixel( x, y, source->GetPixel( xLoop, yLoop ) );
        ( image->Red   < 50 ) ||
        ( image->Blue  < 50 ) ||
        ( image->Green < 50 )
        )
    {
        return false;
    }
    else
    {
        return true;
    }
}

我不喜欢的一件事是在函数外部声明像素大小的方式。如果我试图在函数内部这样做,我会得到意想不到的结果……如果在内部分配内存,则在离开时会被销毁。

g m a i l 这绝不是我最优美的作品,但也为了简单而大刀阔斧地摆脱了它。我为什么要分享这个,我不知道。我应该把它留给自己。 我的名字是什么?Kage.Sabaku.No.Gaara

在让你走之前,我应该提到我的Windows表单应用程序和默认设置之间的细微差别。即我使用“多字节”字符集。项目属性……等等……给狗一根骨头,也许能投一票?

p.p.s. 我不想说,但我对host.c做了一个改变,如果你使用64位,你也可以这样做。否则你就自己想办法吧……但我的原因有点疯狂,不需要效仿。

typedef unsigned int uinT32;
#if (_MSC_VER >= 1200)            //%%% vkr for VC 6.0
typedef _int64 inT64;
typedef unsigned _int64 uinT64;
#else
typedef long long int inT64;
typedef unsigned long long int uinT64;
#endif                           //%%% vkr for VC 6.0
typedef float FLOAT32;
typedef double FLOAT64;
typedef unsigned char BOOL8;

这已经过时了。现在所需的只是libtesseract。标准代码包括对VS2008的支持,而根据说明进行2010年的支持也很简单。 - sventechie

3

Marko,我也尝试使用Tesseract编写快速的C++应用程序,并遇到了同样的问题。

简而言之,我发现很难理解,缺少示例和文档,但是我不会责怪这个产品,它是开源的,贡献者可能更有兴趣改进它而不是营销它。

您可以尝试查看源代码并可能花费时间来理解,但我完全理解您的沮丧感。

祝你好运!


我设法通过shell执行最终使用它,但它非常不准确,我放弃了它,至少对我感兴趣的字体而言是这样,我只能想象训练它有多么“有趣”.. - Marko29
我不想抨击背后的人,只是说一下对我来说它的结局如何,我相信它在自己的方式上是一个好库。 - Marko29

1
如果您使用的是Windows 10操作系统,则有OCR API可用,无需安装任何软件。
这项技术非常难以掌握,文档也不太容易理解。但我最终成功了。
以下是一个使用Windows 10 OCR引擎API的简单函数:

// For the Windows 10 OCR API
#include "winrt/Windows.Storage.Streams.h"
#include "winrt/Windows.Graphics.Imaging.h"
#include "winrt/Windows.Media.Ocr.h"
#include "winrt/Windows.Networking.Sockets.h"
#include "winrt/Windows.Globalization.h"
#pragma comment(lib, "pathcch")
#pragma comment(lib,"windowsapp.lib")

std::string ExtractTextFromImage(byte* pixels, int xSize, int ySize)
{
    using namespace winrt;

    Windows::Globalization::Language lang = Windows::Globalization::Language(L"en");
    Windows::Media::Ocr::OcrEngine engine = Windows::Media::Ocr::OcrEngine::TryCreateFromLanguage(lang);
    //OcrEngine engine = OcrEngine::TryCreateFromUserProfileLanguages();


    int pixels_size = xSize * ySize * 4;

    Windows::Storage::Streams::InMemoryRandomAccessStream stream = { 0 };
    Windows::Storage::Streams::DataWriter writer(stream);


    array_view<const byte> bytes(pixels, pixels + pixels_size);

    writer.WriteBytes(winrt::array_view<const byte>(bytes));

    Windows::Storage::Streams::IBuffer buffer = writer.DetachBuffer();



    Windows::Graphics::Imaging::SoftwareBitmap bitmap = Windows::Graphics::Imaging::SoftwareBitmap::CreateCopyFromBuffer
    (
        buffer,
        Windows::Graphics::Imaging::BitmapPixelFormat::Bgra8,
        xSize,
        ySize
    );

    Windows::Media::Ocr::OcrResult result = engine.RecognizeAsync(bitmap).get();
    std::string output = winrt::to_string(result.Text());

    bitmap.Close();
    writer.Close();



    return output;
}



网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接