如何在小型 C++ 项目中使用 tesseract ocr(或任何其他免费 ocr)?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/5079635/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How can i use tesseract ocr(or any other free ocr) in small c++ project?
提问by Marko29
So what I heard after research is that the only solid free OCR options are either Tesseractor CuneiForm.
所以我在研究后听到的是,唯一可靠的免费 OCR 选项是Tesseract或 CuneiForm。
Now, the Tesseract docs are plain horrible, all they give you is a bunch of Visual Studio code (for me on Windows) and from there you are on your own in an ocean of their API. All you can do is use the exe that compiles then use it on a tiff image.
现在,Tesseract 文档简直太糟糕了,他们给你的只是一堆 Visual Studio 代码(对我来说是 Windows 上的),然后你就可以在他们 API 的海洋中独自一人了。您所能做的就是使用编译的 exe,然后在 tiff 图像上使用它。
I was expecting at least short documentation that tells you how to pull their API call to use OCR at least for a small example but no, there's nothing like that in their docs.
我期待至少有简短的文档告诉您如何至少在一个小示例中提取他们的 API 调用以使用 OCR,但不,他们的文档中没有类似的内容。
CuneiForm: I downloaded it and "great" everything is in Russian. :(
CuneiForm:我下载了它,“很棒”的一切都是俄语。:(
Is it really hard for those guys to pull a small example instead they supply us with bunch of irrelevant info that probably 90% of people won't reach, how can you reach there without starting on small things and they explain none of it!
对于那些人来说,举一个小例子真的很难吗?他们向我们提供了一堆可能 90% 的人无法到达的无关信息,你怎么能在不从小事着手的情况下到达那里,而他们却没有解释!
So I have bunch of API but how the hell am I supposed to use it if it's explained nowhere?... Maybe someone can offer me advice and a solution? I'm not asking for a miracle, just something small to show me how things work.
所以我有一堆 API,但是如果没有任何解释,我该怎么使用它?...也许有人可以为我提供建议和解决方案?我不是在要求奇迹,只是一些小事来向我展示事情是如何运作的。
回答by zkunov
You might have given up, but there may be some other who are still trying. So here is what you need to start with tesseract:
您可能已经放弃了,但可能还有其他人仍在尝试。所以这里是你需要从 tesseract 开始的:
First of all you should read all the documentation about tesseract. You may find something useful is the wiki.
首先,您应该阅读有关 tesseract 的所有文档。您可能会发现wiki有用。
To start using the API(v 3.0.1, currently in trunk, read also the README and ChangeLog from trunk) you should check out the baseapi.h
. The documentation of how to use the api is right there, a comment above each function.
要开始使用API(V 3.0.1,目前在躯干,还宣读了README和更新日志行李箱),你应该看看baseapi.h
。如何使用 api 的文档就在那里,每个函数上方都有注释。
For starters:
对于初学者:
- include
baseapi.h
& constructTessBaseAPI
object - call
Init()
- Some optional like
- change some params with the
SetVariable()
func. You can see all the params and their values if you print them in a file usingPrintVariables()
func. - change the segmentation mode with
SetPageSegMode()
. Tell tesseract what the image you are about to OCR represents - block or line of text, word or character.
- change some params with the
SetImage()
GetUTF8Text()
- 包含
baseapi.h
和构造TessBaseAPI
对象 - 称呼
Init()
- 一些可选的喜欢
- 使用
SetVariable()
func更改一些参数。如果使用PrintVariables()
func 将它们打印在文件中,则可以看到所有参数及其值。 - 使用 更改分段模式
SetPageSegMode()
。告诉 tesseract 您将要进行 OCR 的图像代表什么 - 文本块或一行、单词或字符。
- 使用
SetImage()
GetUTF8Text()
(Again, that is just for starters.)
(同样,这只是初学者。)
You can check the tesseract's community for alredy answerd questions or ask your own here.
回答by matiu
I'm digging into it .. so far I've generated DoxyGen code for it .. that's helping. Still reading all the docs though.
我正在研究它......到目前为止我已经为它生成了 DoxyGen 代码......这很有帮助。尽管如此,仍在阅读所有文档。
Some links that help me:
一些对我有帮助的链接:
- The dev google groupis full of broken examples from desperate devs
- A slightly old (v2.0) hacking tesseract how to
- 谷歌开发组充满了来自绝望开发者的坏例子
- 一个稍微旧的 (v2.0) hacking tesseract 如何
Any I downloaded the svn from google code: http://code.google.com/p/tesseract-ocr/
我从谷歌代码下载了 svn:http: //code.google.com/p/tesseract-ocr/
and made and installed it then used doxygen to generate my own API reference docs. Very useful.
并制作并安装它,然后使用 doxygen 生成我自己的 API 参考文档。很有用。
The way I did it is:
我这样做的方式是:
- I used 'make install' and it put some stuff in /usr/include/tesseract
- I copied that dir to my home dir
- doxygen -g doxygen.conf; # To generate a doxygen file
- Go through the file it generates and set output dir and project name or whatever. I used 'doxy-dox' as my output dir
- doxygen -g doxygen.conf
- chromium-browser chromium-browser doxy-doc/html/index.html
- 我使用了'make install',它把一些东西放在/usr/include/tesseract
- 我将该目录复制到我的家庭目录
- doxygen -g doxygen.conf; # 生成doxygen文件
- 浏览它生成的文件并设置输出目录和项目名称或其他任何内容。我使用“doxy-dox”作为我的输出目录
- doxygen -g doxygen.conf
- 铬浏览器 铬浏览器 doxy-doc/html/index.html
Hope that helps a bit.
希望那些对你有帮助。
回答by Kage_Gaara
I figured it out, if you are using visual studios 2010 and are using windows forms / designer you can add it easily this way with no issues
我想通了,如果您使用的是 Visual Studios 2010 并且正在使用 Windows 窗体/设计器,您可以通过这种方式轻松添加它,没有任何问题
add the following projects to your project ( i am warning you once, do not add the tesseract solution, or change any setting in the projects you add, unless you love to hate yourself )
ccmain ccstruct ccutil classify cube cutil dict image libtesseract nutral_networks textord viewer wordrec
将以下项目添加到您的项目中(我警告您一次,不要添加 tesseract 解决方案,或更改您添加的项目中的任何设置,除非您喜欢讨厌自己)
ccmain ccstruct ccutil 分类立方体 cutil dict 图像 libtesseract nutral_networks textord 查看器 wordrec
you can add the others but you don't really want all that built into your project do you? naaa, build those separately
你可以添加其他的,但你真的不希望所有的东西都内置到你的项目中,对吗?naaa,分别构建它们
go to your project properties and add libtesseract as a reference, you can now that it is visible as a project, this will make it so that your project builds fast without examining the millions of warnings within tesseract. [common properties]->[add reference]
right click your project in the solution explorer and click project dependencies, make sure it is dependant on libtesseract or even all of them, it just means they build before your project.
the tesseract 2010 visual studio projects contain a number of configuration settings aka release, release.dll, debug, debug.dll, it seems that the release.dll settings produce the right files. First, set the solution output to release.dll. Click your project properties. Then click configuration manager. If that is not available, do this, click the SOLUTION's properties in the solution tree and click configuration tab, you will see a list of projects and the associated configuration settings. You will notice your project is not set to release.dll even though the output is. If you took the second route you still need to click configuration manager. Then you can edit the settings, click new on your projects settings and call it release.dll...exactly the same as the rest of them and copy the settings from release. Do the same thing for Debug, so that you have a debug.dll name copied from debug settings. wheew...almost done
Don't try to change tesseracts settings to match yours....that wont work ....and when the new release comes out you wont be able to just "throw it in" and go. Accept the fact that in this state your new modes are Release.dll and Debug.dll. don't stress out...you can go back when its is finished and remove the projects from your solution.
Guess where the libraries and dll's come out? in your project, you may or may not need to add the library directories. Some people say to dump all the headers into a single folder so they only need to add one folder to the includes but not me. I want to be able to delete the tesseract folder and reload it from the zips without extra work....and be fully ready to update in one move or restore it if I made a mess of the code. Its a bit of work and you can to it with code instead of the settings which is the way i do it, but you should include all the folders that contain header files within the 2010 tesseract project folder and leave them alone.
there is no need to add any files to your project. just these lines of code..... I have included some additional code that converts from one foreign data set to the tiff friendly version with no need to save / load file. aren't I nice?
now you can fully debug in debug.dll and release.dll, once you have successfully built it into your project even once you can remove all the added projects and it will be peeerfect. no extra compiling or errors. fully debugable, all natural.
If I remember right, I could not get around the fact I had to copy the files in 2008/lib/ into my projects release folder….darn it.
转到您的项目属性并添加 libtesseract 作为参考,您现在可以将其作为项目可见,这将使您的项目快速构建,而无需检查 tesseract 中的数百万个警告。[常用属性]->[添加参考]
在解决方案资源管理器中右键单击您的项目并单击项目依赖项,确保它依赖于 libtesseract 甚至所有这些,这只是意味着它们在您的项目之前构建。
tesseract 2010 Visual Studio 项目包含许多配置设置,又名 release、release.dll、debug、debug.dll,似乎 release.dll 设置生成了正确的文件。首先,将解决方案输出设置为 release.dll。单击您的项目属性。然后点击配置管理器。如果这不可用,请执行此操作,在解决方案树中单击解决方案的属性,然后单击配置选项卡,您将看到项目列表和相关的配置设置。您会注意到您的项目没有设置为 release.dll,即使输出是。如果您选择了第二条路线,您仍然需要单击配置管理器。然后您可以编辑设置,在您的项目设置上单击新建并将其命名为 release.dll...与其余设置完全相同,然后从 release 复制设置。对 Debug 做同样的事情,这样您就可以从调试设置中复制一个 debug.dll 名称。呼……差不多完成了
不要尝试更改tesseracts设置以匹配您的设置....那行不通....当新版本发布时,您将无法“投入”然后去。接受这样一个事实,即在这种状态下您的新模式是 Release.dll 和 Debug.dll。不要紧张...您可以在完成后返回并从您的解决方案中删除项目。
猜猜库和 dll 是从哪里出来的?在您的项目中,您可能需要也可能不需要添加库目录。有些人说要将所有标题转储到一个文件夹中,这样他们只需将一个文件夹添加到包含中,而不是我。我希望能够删除 tesseract 文件夹并从 zip 重新加载它,而无需额外的工作......并且如果我把代码弄得一团糟,就可以一次更新或恢复它。它有一些工作,您可以使用代码而不是我这样做的方式进行设置,但是您应该在 2010 tesseract 项目文件夹中包含所有包含头文件的文件夹,并且不要管它们。
无需向项目添加任何文件。只是这些代码行..... 我已经包含了一些额外的代码,可以从一个外部数据集转换为 tiff 友好版本,无需保存/加载文件。我不好吗?
现在您可以在 debug.dll 和 release.dll 中进行完全调试,一旦您成功将其构建到您的项目中,即使您可以删除所有添加的项目,它将是完美的。没有额外的编译或错误。完全可调试,一切自然。
如果我没记错的话,我无法回避我必须将 2008/lib/ 中的文件复制到我的项目发布文件夹中的事实……该死的。
In my projects “functions.h” I put
在我的项目“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>
in my main project I put this in a class as a member:
在我的主要项目中,我将它作为成员放在一个类中:
tesseract::TessBaseAPI *readSomeNombers;
and of course I included “functions.h” somewhere
当然我在某处包含了“functions.h”
then I put this in my classes constructor:
然后我把它放在我的类构造函数中:
readSomeNombers = new tesseract::TessBaseAPI();
readSomeNombers ->Init(NULL, "eng" );
readSomeNombers ->SetVariable( "tessedit_char_whitelist", "0123456789,." );
then I created this class member function: and a class member to serve as an output, don't hate, I don't like returning variables. Not my style. The memory for the pix does not need to be destroyed when used inside a member function this way I believe and my test suggest this is a safe way to call these functions. But by all means, you can do whatever.
然后我创建了这个类成员函数:和一个类成员作为输出,不要讨厌,我不喜欢返回变量。不是我的风格。以这种方式在成员函数中使用时,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 );
}
The object that has the information that I want to scan is in memory and is pointed to by &scanImage
. It is from the “EasyBMP” library but that is not important.
具有我要扫描的信息的对象在内存中并由&scanImage
. 它来自“EasyBMP”库,但这并不重要。
Which I deal with in a function in “functions.h”/ “functions.cpp” by the way, i am doing a little extra processing here while i am in the loop, namely thinning the characters and making it black and white and reversing black and white which is unnecessary. At this phase in my development I am still looking for ways to improve the recognition. Though for my proposes this has not yielded bad data yet. My view is to use the default Tess data for simplicity. I am acting heuristically to solve a very complex problem.
顺便说一下,我在“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;
}
}
one thing I don't like is the way I declare the size of the pix outside the function. It seems if I try to do it within the function I have unexpected results....if the memory is allocated while inside it is destroyed when I leave.
我不喜欢的一件事是我在函数外声明像素大小的方式。似乎如果我尝试在函数中执行此操作,我会得到意想不到的结果....如果在我离开时在内部分配内存会被破坏。
g m a i l Certainly not my most elegant work but I also gutted the hell out of it for simplicity. Why I bother to share this I don't know. I should have kept it to myself. What is my name? Kage.Sabaku.No.Gaara
gmail 当然不是我最优雅的工作,但为了简单起见,我也把它弄得一团糟。我不知道为什么我费心分享这个。我应该把它留给自己。我的名字是什么?刀影影之我爱罗
before i let you go i should mention the subtle differences between my windows form app and the default settings. namely i use "multi-byte" character set. project properties...and such..give a dog a bone, maybe a vote?
在我让你走之前,我应该提到我的 Windows 窗体应用程序和默认设置之间的细微差别。即我使用“多字节”字符集。项目属性......等等......给狗一根骨头,也许是投票?
p.p.s. I hate to say it but I made one change to host.c if you use 64 bit you can do the same. Otherwise your on your own.....but my reason was a bit insane you don't have to
pps 我不想这么说,但我对 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;
回答by Mark Kadlec
Marko, I've tried to write a quick C++ app as well using Tesseract and ran into the same problems.
Marko,我尝试使用 Tesseract 编写一个快速的 C++ 应用程序,但遇到了同样的问题。
In a nutshell I found it confusing with little examples/docs, but I don't fault the product, heck, it's open source and the contributers are probably more interested in improving it than marketing.
简而言之,我发现它与一些小示例/文档令人困惑,但我并没有责怪产品,哎呀,它是开源的,贡献者可能对改进它比营销更感兴趣。
You could try poking around at the source code and possibly spending time might get an understanding, but I can totally relate to your frustration.
您可以尝试查看源代码,花时间可能会有所了解,但我完全可以理解您的挫败感。
Good luck!
祝你好运!
回答by gil123
If you using windows 10, there is OCR API. no need to install anything.
如果您使用 Windows 10,则有 OCR API。无需安装任何东西。
The stuff is very hard to get it right. the documentation was very not easy to work with.
这些东西很难做到正确。文档非常不容易使用。
But I got it right.
但我做对了。
Here is a simple function that use Windows 10 OCR engine 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;
}