Tesseract是一个开源的OCR(光学字符识别)引擎,用于识别并输出图片中的文字。虽然和商业软件比起来识别精度不算很高,但是如果你要寻找免费开源的OCR引擎,可能Tesseract就是唯一的选择了。Tesseract用起来还算是比较方便。它提供了一个简单的命令行工具,没有很多选项,输入图片输出就是文字。因为是开源的,你也可以直接编译使用它基于C++的库。

最近一段时间我对Python产生了很大的兴趣。它是如此的简洁高效,只要可以用Python完成的工作就懒得使用其他编程语言。所以到了应用Tesseract的时候我首先想到了去Google一下有没有Python binding。确实有人使用swig做了个tesseract的封装,不过不幸的是实际应用存在不少问题。首先是安装不便,尤其在mac上的安装令人崩溃。即使完成安装,不知为何又segment fault。其次,很多方法只做了简单的封装,又缺乏文档,想做深入一点的应用例如输出文字在图中的位置,感觉无从着手。不如从Tesseract的源代码入手,自己编写python的扩展,对tesseract的某些感兴趣的方法做个封装,也顺便熟悉下Python和C/C++集成的方法。可以在扩展里为所欲为,真是令人心情愉快。

首先,新建一个cpp源文件,然后为这个新模块想个名字,比如 tessex。然后,需要定义这个新模块,以及模块里需要暴露出来的方法。这样在Python里就可以用import tessex来载入模块。

static PyMethodDef tessexMethods[] = {
{"recognize", (PyCFunction)tessex_recognize,
METH_VARARGS|METH_KEYWORDS,
"recognize text in an image."},
{NULL, NULL, , NULL}
}; PyMODINIT_FUNC inittessex(void) {
(void) Py_InitModule("tessex", tessexMethods);
}

这里,我们暴露一个方法recognize,用来扫描给定图片然后返回识别的文字以及位置。大家知道Python方法可以传两种参数,一种是无名的,一种是有名的,分别对应METH_VARARGS以及METH_KEYWORDS。作为一个有点完美主义倾向的人,我把两个选项都勾上了。然后我们看下recognize方法的定义。正如之前讲的,需要声明参数args以及kw。

static PyObject* tessex_recognize(PyObject* self, PyObject* args, PyObject* kw){

接下来是展开从Python调用传进来的参数。要使用有名参数,需要把所有参数名都先列出来。

  static const char* kwlist[]={"data", "w", "h", "channels", "step", NULL};

然后调用PyArg_ParseTupleAndKeywords展开有名参数。一个格式字符串用于声明参数的类型。data是图像的像素buffer,适用S类型。w、h、channels、step分别是图像的宽度、高度、信道数、步长,都是整型变量,适用i类型。

    PyStringObject *data;
int w=;
int h=;
int channels=;
int step=; if (!PyArg_ParseTupleAndKeywords(args, kw, "Siiii", (char**)(kwlist),
&data, &w, &h, &channels, &step)) {
PyErr_SetString(PyExc_Exception, "Tessex: Failed to parse arguments.");
return NULL;
}

我们要开始使用Tesseract的API了。Tesseract支持多种语言,不过语言包要分别下载安装。这里我们使用英语。

    tesseract::TessBaseAPI *api = new tesseract::TessBaseAPI();
if (api->Init(NULL, "eng")) {
PyErr_SetString(PyExc_Exception, "Tessex: Failed to initialize tesseract API.");
return NULL;
}

把传入的图像数据传递给Tesseract,然后进行识别。

    api->SetImage((const unsigned char*)PyString_AS_STRING(data),
w, h, channels, step); api->Recognize();

识别结果的处理稍微复杂点。一般的应用如果只想得到所有文字,只要调用GetUTF8Text()就完了。但是我想知道每一行的文字,它们的具体位置以及可信度,就需要对识别结果进行详细的分析。幸运的是Tesseract提供了iterator接口,可以返回不同粒度的数据。这里我选择了按行输出,即RIL_TEXTLINE。

    PyObject* l = PyList_New();
tesseract::ResultIterator* it = api->GetIterator();
it->Begin();
while() {
char* utf8_text;
int left, top, right, bottom;
int confidence = ; utf8_text = it->GetUTF8Text(tesseract::RIL_TEXTLINE);
if (utf8_text == NULL)
break; confidence = it->Confidence(tesseract::RIL_TEXTLINE);
it->BoundingBox(tesseract::RIL_TEXTLINE, &left, &top, &right, &bottom); PyObject* t = Py_BuildValue("(siiiii)", utf8_text,
left, top, right, bottom, confidence);
PyList_Append(l, t); delete []utf8_text; it->Next(tesseract::RIL_TEXTLINE);
}
api->End(); PyObject* o = Py_BuildValue("O", l); return o;

返回的是一个list,其每个元素都是一个tuple,代表识别出来的文字行,包括文字、位置和可信度。

最后不要忘了include需要的头文件,并在链接选项里加入需要的库。

#include "Python.h"
#include <tesseract/baseapi.h>
#include <tesseract/resultiterator.h>

具体如何编译tesseract可以参考https://code.google.com/p/tesseract-ocr/wiki/Compiling/

在示例代码里我们并没有用到任何图形库。但是因为要使用Tesseract就必须链接leptonica库,所以需要加入链接选项-llept。

如果你想在扩展里使用leptonica的功能可以include <leptonica/allheaders.h>。或者你想使用openCV,可以include <opencv2/opencv.hpp>并链接-lopencv_XXXXX。

这样代码部分算是完成了。不过接下来还有一步,我们需要打包完成一个Python扩展使之容易编译和安装。可以使用distutils模块。

from distutils.core import setup, Extension

tessenigma = Extension (
'tessex',
sources=['tessex.cpp'],
include_dirs = ['/usr/local/include'],
libraries=[ 'tesseract'],
library_dirs=['/usr/local/lib']
) setup (name='tessex',
version='1.0',
description='This is a tesseract extensiion.',
ext_modules = [tessex])

把这些定义写入一个setup.py文件里。这样我们就可以用通常的方式编译和安装模块了。编译用setup.py build。一个动态链接库会生成。例如在Linux下面就是tessex.so。安装模块使用setup.py install。前面生成的库文件会被复制到Python的site-packages下面。当然你也可以手动复制到$PYTHONPATH路径下面,一样能被Python找到。

安装好扩展后,在Python里是这样调用的,假定我们使用一个openCV图像:

import tessex
import cv cv_img = cv.LoadImage(path, cv.CV_LOAD_IMAGE_COLOR) lines = tessex.recognize(
data=cv_img.tostring(),
w=cv_img.width,
h=cv_img.height,
channels=cv_img.nChannels,
step=cv_img.width * cv_img.nChannels * cv_img.depth / 8) for line in lines:
  line_text, left, top, right, bottom, confidence = line

通过Tesseract扩展,可以在Python中比较方便地识别图像中的文字以及位置,对基于图像识别的自动化测试是很有帮助的。

编写Tesseract的Python扩展的更多相关文章

  1. VSCode的Python扩展下程序运行的几种方式与环境变量管理

    在VSCode中编写Python程序时,由于有些地方要使用环境变量,但是发现设置的环境变量有时不起作用,花了点时间研究了一下,过程不表,直接说结论. 首先,环境变量的设置,Python扩展中有三种方式 ...

  2. Python 扩展技术总结(转)

    一般来说,所有能被整合或导入到其他Python脚本中的代码,都可以称为扩展.你可以用纯Python来写扩展,也可以用C/C++之类的编译型语言来写扩展,甚至可以用java,C都可以来写 python扩 ...

  3. metasploit framework(五):meterpreter基本命令和python扩展

    基于内存的DLL注入式payload 注入合法的系统进程并建立stager 基于stager上传和预加载DLL进行扩展模块的注入(客户端API) 基于stager建立的socket连接建立加密的TLS ...

  4. LFD,非官方的Windows二进制文件的Python扩展包

    LFD,非官方的Windows二进制文件的Python扩展包 LFD,非官方版本.32和64位.Windows.二进制文件.科学开源.Python扩展包 克里斯托夫·戈尔克(by Christoph ...

  5. 自己来编写一份 Python 脚本 第一版

    解决问题 我们已经探索了 Python 语言中的许多部分,现在我们将通过设计并编写一款程序来了解如何把这些部分组合到一起.这些程序一定是能做到一些有用的事情.这节的Python教程就是教大家方法去学习 ...

  6. Effective Python之编写高质量Python代码的59个有效方法

                                                         这个周末断断续续的阅读完了<Effective Python之编写高质量Python代码 ...

  7. Python 扩展 Op

    Python 扩展 Op 注意 :本文涉及的 Python Kernel 仅在 gcc 4.8.5 编译环境下充分测试,进一步的完善计划见 Issue 3951. 背景介绍 OneFlow 将各种对于 ...

  8. vs写python扩展资料收集

    总结: 1.创建dll工程: 2.增加包含头文件路径 :将python路径下的include加入到包含头文件路径:在工程属性页 C/C++/附加包含目新增<Python>\include目 ...

  9. Python基础+Pythonweb+Python扩展+Python选修四大专题 超强麦子学院Python35G视频教程

    [保持在百度网盘中的, 可以在观看,嘿嘿 内容有点多,要想下载, 回复后就可以查看下载地址,资源收集不易,请好好珍惜] 下载地址:http://www.fu83.cc/ 感觉文章好,可以小手一抖 -- ...

随机推荐

  1. 【BZOJ】3397: [Usaco2009 Feb]Surround the Islands 环岛篱笆(tarjan)

    http://www.lydsy.com/JudgeOnline/problem.php?id=3397 显然先tarjan缩点,然后从枚举每一个scc,然后向其它岛屿连费用最小的边,然后算最小的即可 ...

  2. Hive数据类型与文件存储格式

    Hive数据类型 基础数据类型: TINYINT,SMALLINT,INT,BIGINT,BOOLEAN,FLOAT,DOUBLE,STRING,BINARY,TIMESTAMP,DECIMAL,CH ...

  3. web.xml配置文件详解

    笔者从大学毕业一直从事网上银行的开发,都是一些web开发项目.接下来会写一些关于web开发相关的东西,也是自己工作以来经常用到的内容.本篇先从web.xml文件开始介绍,笔者接触到的项目中都有这个文件 ...

  4. OpenvSwitch2.4.0源码解读

    原文发表在我的博客主页,转载请注明出处! 一.前言 OpenvSwitch,虚拟交换机,以下简称OVS,是云计算和SDN领域非常重要的一个开源交换机,如果需要深入研究云计算和SDN的数据平面,读懂OV ...

  5. Java实现 Hessian接口测试

    Hessian接口测试简单单例 Hessian是基于Binary –RPC(二进制远程过程调用协议)进行通讯. Hessian就是把Java对象转变成字节序列,然后通过Http传输到目标服务器上(主机 ...

  6. mysql 中用户默认密码加密问题

    问题描述: 在mysql中 user表中新增用户默认密码为123456,但是在数据库中显示不能为明文,而mysql的默认字段不能用函数 解决方法: 用触发器 delimiter | drop trig ...

  7. 微信支付 超时 mysql.event

    $wtime 使用具体timestamp //rand 防推测 $wev = 'ev_gbuy_create_' . trim($winsert_id) . rand(100, 999); $sql ...

  8. selenium3.x的使用例子

    1.需要下载selenium的相关包以备工程调用. 2.工程中配置引用selenium的lib. selenium3.x中主要是根据webdriver进行浏览器的各种操作,可以完全模仿人工操作浏览器, ...

  9. numpy.random.random & numpy.ndarray.astype & numpy.arange

    今天看到这样一句代码: xb = np.random.random((nb, d)).astype('float32') #创建一个二维随机数矩阵(nb行d列) xb[:, 0] += np.aran ...

  10. PHP的几种排序方法

    <?php /** * PHP最常用的四个排序方法及二种查找方法 * 下面的排序方法全部都通过测试 * auther : soulence * date : 2015/06/20 */ //PH ...