【问题标题】:How can i use tesseract ocr(or any other free ocr) in small c++ project?我如何在小型 c++ 项目中使用 tesseract ocr(或任何其他免费的 ocr)?
【发布时间】:2011-07-02 01:35:46
【问题描述】:

所以我在研究后听到的是,唯一可靠的免费 OCR 选项是 Tesseract 或 CuneiForm。

现在,Tesseract 文档简直太可怕了,他们给你的只是一堆 Visual Studio 代码(对我来说是在 Windows 上),然后你就可以自己在他们的 API 的海洋中了。您所能做的就是使用编译的 exe,然后在 tiff 图像上使用它。

我期待至少有简短的文档告诉你如何拉他们的 API 调用以使用 OCR 至少作为一个小例子,但不,他们的文档中没有类似的东西。

CuneiForm:我下载了它,“很棒”的一切都是俄语的。 :(

这些家伙真的很难举一个小例子,而是他们向我们提供了一堆可能 90% 的人不会接触到的不相关信息,如果不从小事做起,你怎么能到达那里,他们什么也没解释它!

所以我有一堆 API,但如果没有任何解释,我到底应该如何使用它?...也许有人可以给我建议和解决方案?我不是在要求奇迹,只是为了让我知道事情是如何运作的。

【问题讨论】:

  • 这是投诉,这里不适合。您可以删除投诉,尝试使用 tesseract 或 cuinform,然后返回更具体的问题。另外,我对这两个项目都不熟悉,如果您至少提供链接会有所帮助。
  • 欢迎来到开源库的世界,这里的 API 很糟糕,没有任何文档记录。
  • @Davi Thornley 我希望我可以使用它,但没有记录起点。我一直在网上搜索示例,但找不到任何东西。我的问题是从哪里开始将他们的 api 拉入我的 c 项目中,只是一个应该指导我进一步挖掘的小例子,一定有人在他们的项目中使用过其中任何一个

标签: c++ c windows image-processing ocr


【解决方案1】:

您可能已经放弃了,但可能还有其他人仍在尝试。所以这里是你需要从 tesseract 开始:

首先你应该阅读所有关于 tesseract 的文档。您可能会发现一些有用的东西是wiki

要开始使用 API(v 3.0.1,当前在主干中,还请阅读 trunk 中的 README 和 ChangeLog),您应该查看 baseapi.h。如何使用 api 的文档就在那里,每个函数上方都有注释。

对于初学者:

  • 包含baseapi.h & 构造TessBaseAPI 对象
  • 致电Init()
  • 一些可选的,例如
    • 使用SetVariable() 函数更改一些参数。如果您使用PrintVariables() func 将它们打印到文件中,则可以查看所有参数及其值。
    • SetPageSegMode()更改分段模式。告诉 tesseract 你将要进行 OCR 的图像代表什么 - 文本块或行、单词或字符。
  • SetImage()
  • GetUTF8Text()

(同样,这只是为了初学者。)

您可以查看 tesseract 的社区以获取已回答的问题或询问您自己的here

【讨论】:

    【解决方案2】:

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

    一些对我有帮助的链接:

    任何我从谷歌代码下载的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】:

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

      简而言之,我发现它与小示例/文档令人困惑,但我不会责怪产品,见鬼,它是开源的,贡献者可能对改进它比营销更感兴趣。

      您可以尝试浏览源代码,可能花时间可能会有所了解,但我完全可以理解您的沮丧。

      祝你好运!

      【讨论】:

      • 最后我设法通过 shell 执行来使用它,但它太不准确了,我放弃了它,至少在我感兴趣的字体上,我只能想象训练是多么“有趣”就这样..
      • 我不想抨击它背后的人,只是说它对我来说是如何结束的,我相信它以自己的方式是好的库
      【解决方案4】:

      我想通了,如果您使用的是 Visual Studios 2010 并且正在使用 Windows 窗体/设计器,您可以通过这种方式轻松添加它,没有任何问题

      1. 将以下项目添加到您的项目中(我警告您一次,不要添加 tesseract 解决方案,或更改您添加的项目中的任何设置,除非您爱恨自己)

        ccmain 结构体 ccutil 分类 立方体 角质 听写 图片 libtesseract nutral_networks 文本 观众 文字记录

      您可以添加其他的,但您并不真的希望所有这些都内置到您的项目中,对吗? naaa,分别构建这些

      1. 转到您的项目属性并添加 libtesseract 作为参考,您现在可以看到它作为一个项目可见,这将使您的项目快速构建而无需检查 tesseract 中的数百万警告。 【常用属性】->【添加引用】

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

      3. tesseract 2010 Visual Studio 项目包含许多配置设置,即 release、release.dll、debug、debug.dll,看来 release.dll 设置会生成正确的文件。首先,将解决方案输出设置为 release.dll。单击您的项目属性。然后单击配置管理器。如果不可用,请执行此操作,单击解决方案树中的解决方案属性,然后单击配置选项卡,您将看到项目列表和相关的配置设置。您会注意到您的项目未设置为 release.dll,即使输出是。如果您采用第二条路线,您仍然需要单击配置管理器。然后您可以编辑设置,在您的项目设置上单击新建并将其命名为 release.dll ...与其余设置完全相同,然后从发布中复制设置。对 Debug 执行相同的操作,以便您从调试设置中复制一个 debug.dll 名称。呼……快完成了

      4. 不要尝试更改 tesseracts 设置以匹配您的设置....这不会起作用....当新版本发布时,您将无法“扔进去”然后走。接受在这种状态下您的新模式是 Release.dll 和 Debug.dll 的事实。不要紧张...您可以在完成后返回并从您的解决方案中删除项目。

      5. 猜猜这些库和 dll 是从哪里出来的?在您的项目中,您可能需要也可能不需要添加库目录。有人说要将所有标题转储到一个文件夹中,因此他们只需将一个文件夹添加到包含而不是我。我希望能够删除 tesseract 文件夹并从 zip 中重新加载它而无需额外的工作......并且如果我把代码弄得一团糟,就可以完全准备好一次更新或恢复它。它有点工作,您可以使用代码而不是我的方式进行设置,但是您应该在 2010 tesseract 项目文件夹中包含所有包含头文件的文件夹,不要管它们。

      6. 无需向您的项目添加任何文件。只是这些代码行.....我已经包含了一些额外的代码,这些代码可以从一个外部数据集转换为 tiff 友好版本,而无需保存/加载文件。我不是很好吗?

      7. 1234563没有额外的编译或错误。完全可调试,一切自然。
      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,." );
      

      然后我创建了这个类成员函数:和一个类成员作为输出,不要讨厌,我不喜欢返回变量。不是我的风格。我相信以这种方式在成员函数内部使用时,不需要破坏 pix 的内存,并且我的测试表明这是调用这些函数的安全方法。但无论如何,你可以做任何事情。

      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 );
      }
      

      具有我要扫描的信息的对象在内存中,并由&amp;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.我不想这么说,但是如果您使用 64 位,我对 host.c 进行了更改,您也可以这样做。否则你自己……但我的理由有点疯狂,你不必这样做

      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 的支持,使用说明很简单。
      【解决方案5】:

      如果您使用的是 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;
      }
      
      
      

      【讨论】:

        猜你喜欢
        • 2011-05-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-08-09
        • 1970-01-01
        • 2017-11-03
        相关资源
        最近更新 更多