2020年10月26日
pytesseract 中image_to_data的C++实现
GetTSVText是Tesseract提供的在C++中可以获取TSV格式输出的函数,但其返回结果是字符串。那么在C++中是否能实现类似pytesseract中image_to_data DICT输出的函数,可以便捷获取识别结果的各项信息呢?本文将分享如何用GetTSVText实现该功能。
环境
VS2019
Tesseract5.0
opencv4.3
image_to_data在C++中的实现思路
以下代码是image_to_data在pytesseract中的实现。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
def image_to_data( image, lang=None, config='', nice=0, output_type=Output.STRING, timeout=0, pandas_config=None, ): """ Returns string containing box boundaries, confidences, and other information. Requires Tesseract 3.05+ """ if get_tesseract_version() < '3.05': raise TSVNotSupported() config = '{} {}'.format('-c tessedit_create_tsv=1', config.strip()).strip() args = [image, 'tsv', lang, config, nice, timeout] return { Output.BYTES: lambda: run_and_get_output(*(args + [True])), Output.DATAFRAME: lambda: get_pandas_output( args + [True], pandas_config, ), Output.DICT: lambda: file_to_dict(run_and_get_output(*args), '\t', -1), Output.STRING: lambda: run_and_get_output(*args), }[output_type]() |
根据代码可知,在pytesseract中,先调用tesseract.exe获取待识别图片的tsv格式的输出,然后根据设定将输出转换为BYTES,DATAFRAM,DICT,或者STRING的形式。在pytesseract image_to_data检测并定位图片中的文字中介绍的是DICT的输出,这也是比较常用的输出格式。同时我们也要注意:Tesseract3.05以下的版本不支持TSV格式。
明确了image_to_data在pytesseract中的实现步骤后,我们也基本确定其功能在C++中的实现思路:
2. 将TSV格式的输出转换为类似Output.DICT的格式输出。C++中,与Python中DICT形式与存取方法较为接近的变量是std::map,因此在C++中最终的输出将是std::map的形式。
image_to_data在C++中的实现代码详解
image_to_data在C++中的实现的完整代码已上传至Github,欢迎测评。这里我们主要讲解实现函数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 |
#include "tesstsv2map.h" #include "tesseract\baseapi.h" #include "leptonica\allheaders.h" using namespace std; using namespace cv; std::map<std::string, std::vector<std::string>> tsv2map(cv::Mat tessImage, int magnifiRatio,const char* lang, const char* langPath) { tesseract::TessBaseAPI *ocrObj; map<string, vector<string>> result; ocrObj = new tesseract::TessBaseAPI(); if (ocrObj->Init(langPath, lang) == -1) { return result; } if (tessImage.data != NULL) { if (magnifiRatio > 1) { resize(tessImage, tessImage, Size(tessImage.cols * magnifiRatio, tessImage.rows * magnifiRatio), 0, 0, INTER_CUBIC); } ocrObj->SetImage(tessImage.data, tessImage.cols, tessImage.rows, tessImage.elemSize(), tessImage.step1()); // Get the OCR output as tsv with coordinates of each word char* charTsvResult = ocrObj->GetTSVText(0); //split the content by the "\n" vector<string> tsvVec = splitString(charTsvResult, "\n"); int Len = tsvVec.size(); //the tsv file from GetTSVText() don't contains the tsv header, so initial the head here vector<string> headVec = { "level","page_num","block_num","par_num","line_num","word_num","left","top","width","height","conf","text" }; //result size. int hLen = headVec.size(); if (Len > 1) { //the last line in tsv file is null, so ignore it Len = Len - 1; for (int i = 0; i < Len; i++) { string lineStr = tsvVec[i]; vector<string> lineVec = splitString(lineStr, "\t"); int tmpLen = lineVec.size(); for (int j = 0; j < tmpLen; j++) { result[headVec[j]].push_back(lineVec[j]); } if (tmpLen < hLen) { result[headVec[hLen - 1]].push_back(""); } } } } return result; } |
第1~3行包含必要的头文件。
第7行定义将tesseract的tsv格式输出转换为C++ map输出的函数。
该函数的输出格式为std::map,它有四个输入参数,意义分别如下:
1 2 3 4 5 6 7 8 9 |
std::map<std::string, std::vector<std::string>> tsv2map(cv::Mat tessImage, int magnifiRatio,const char* lang, const char* langPath) cv::Mat tessImage:测试图像,请确保该输入图像为RGB彩色,或者灰度图,或者是二值化图像。 int magnifiRatio: 测试图像放大倍数。有的图像放大后可能获得更好的识别效果。 const char* lang: Tesseract的识别用语言。 const char* langPath: Tesseract识别语言所在路径。 |
第10行定义tesseract变量。
第11行定义存储转换结果的变量。
第13~17行,tesseract变量实例化,并根据设定加载语言文件,若加载失败将直接返回空的结果。
第22~25行,根据设定结果将输入图像进行放大。在Tesseract中,有时将识别图像放大会得到更好的识别效果,目前该参数仅支持放大。
第26行,为tesseract实例化变量设定待识别图像的参数。
第29行,调用GetTSVText(0)函数获取Tesseract根据内部数据结构制作TSV格式的字符串.函数GetTSVText()有一个参数,其名称为”page_number”。我将该参数的意义理解为Tesseract对图片识别过程中进行页面分割的序号,一般情况下,该参数值为0。
第32行,用函数splitString将Tesseract的识别结果进行分割,分割符为”/n”。
splitString可以根据设定分割字符对输入的字符串进行分割,返回变量形式为vector<string>,在Github上可以获取本文完整的代码。
第34行,获取识别结果按”/n”分割后的vector中元素数量。
第37行,为返回结果初始化tsv文件的单项名称。若使用Tesseract输出tsv格式的文件,该文件中会有tsv结果各类别的名称;但GetTSVText()函数的返回结果中仅有各类别的结果,因此这里我们根据.tsv格式中各类别的名称为C++的map输出初始化单项名称。
第46~61行,遍历第32行代码分割后的vector<string>结果,根据37行初始化的单项类别,分别取出相应的结果,存储在相应类别中。
测试图像以及变量内容大致如下图:
在确认当前工程可以正常调用Tesseract后,我们可以用以下代码在C++工程中获取并使用类似pytesseract中image_to_data DICT的输出结果。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
std::map<std::string, std::vector<std::string>> results = tsv2map(testImg,1,"eng","tesseract-5.0\\tessdata\\eng/"); string level = results["level"][i];//get level of index i string block_num = results["block_num"][i];//get block_num of index i string page_num = results["page_num"][i];//get page_num of index i string par_num = results["par_num"][i];//get par_num of index i string line_num = results["line_num"][i];//get line_num of index i string word_num = results["word_num"][i];//get word_num of index i string left = results["left"][i]; string top = results["top"][i];//the left-top corner of the OCR word coordinates string width = results["width"][i]; string height = results["height"][i];//the width and height of the OCR word coordinates string conf = results["conf"][i];//get the confidence of the OCR word. string text = results["text"][i];//get the OCR word. |
本文到此结束,感谢阅读,欢迎关注。